-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[clr-interp] Implement CEE_LOCALLOC
and frame data allocator for dynamic stack allocations
#114860
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
1fb49a3
e5fb653
6b81d9b
43f4481
f660365
e59cace
7c649a8
1d1e226
cb0b212
581e856
e72e0e3
50e94f6
dfb170b
c3bc007
c91b99d
2bfe64f
c08ab74
7f42176
df20036
8dc3223
cd3d5b7
bbb4345
4b8c03c
db6355f
0e97a9c
980eb78
d203e02
902e4d0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -11,6 +11,110 @@ typedef void* (*HELPER_FTN_PP)(void*); | |||||||||||
|
||||||||||||
thread_local InterpThreadContext *t_pThreadContext = NULL; | ||||||||||||
|
||||||||||||
FrameDataFragment *frame_data_new_fragment(size_t size) | ||||||||||||
kotlarmilos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||
{ | ||||||||||||
if (size < INTERP_STACK_FRAGMENT_SIZE) | ||||||||||||
size = INTERP_STACK_FRAGMENT_SIZE; | ||||||||||||
|
||||||||||||
FrameDataFragment *frag = (FrameDataFragment*)malloc(sizeof(FrameDataFragment) + size); | ||||||||||||
if (!frag) return NULL; | ||||||||||||
|
||||||||||||
frag->start = (uint8_t*)(frag + 1); | ||||||||||||
frag->end = frag->start + size; | ||||||||||||
frag->pos = frag->start; | ||||||||||||
frag->next = NULL; | ||||||||||||
return frag; | ||||||||||||
} | ||||||||||||
|
||||||||||||
void frame_data_allocator_init(FrameDataAllocator *allocator, size_t size) | ||||||||||||
{ | ||||||||||||
allocator->first = frame_data_new_fragment(size); | ||||||||||||
assert(allocator->first && "Failed to allocate initial fragment"); | ||||||||||||
allocator->current = allocator->first; | ||||||||||||
allocator->infos = NULL; | ||||||||||||
allocator->infos_len = 0; | ||||||||||||
allocator->infos_capacity = 0; | ||||||||||||
} | ||||||||||||
|
||||||||||||
void frame_data_fragment_free(FrameDataFragment *frag) | ||||||||||||
{ | ||||||||||||
while (frag) { | ||||||||||||
FrameDataFragment *next = frag->next; | ||||||||||||
free(frag); | ||||||||||||
frag = next; | ||||||||||||
} | ||||||||||||
} | ||||||||||||
|
||||||||||||
void frame_data_allocator_destroy(FrameDataAllocator *allocator) | ||||||||||||
{ | ||||||||||||
assert (allocator->current == allocator->first && allocator->current->pos == allocator->current->start); | ||||||||||||
frame_data_fragment_free(allocator->first); | ||||||||||||
|
||||||||||||
free(allocator->infos); | ||||||||||||
allocator->first = allocator->current = NULL; | ||||||||||||
allocator->infos = NULL; | ||||||||||||
allocator->infos_len = allocator->infos_capacity = 0; | ||||||||||||
} | ||||||||||||
|
||||||||||||
void frame_data_push_info(FrameDataAllocator *allocator, InterpreterFrame *frame) | ||||||||||||
{ | ||||||||||||
if (allocator->infos_len == allocator->infos_capacity) { | ||||||||||||
int new_capacity = allocator->infos_capacity == 0 ? 8 : allocator->infos_capacity * 2; | ||||||||||||
allocator->infos = (FrameDataInfo*)realloc(allocator->infos, new_capacity * sizeof(FrameDataInfo)); | ||||||||||||
assert(allocator->infos && "Failed to reallocate frame info"); | ||||||||||||
allocator->infos_capacity = new_capacity; | ||||||||||||
} | ||||||||||||
|
||||||||||||
FrameDataInfo *info = &allocator->infos[allocator->infos_len++]; | ||||||||||||
info->frame = frame; | ||||||||||||
info->frag = allocator->current; | ||||||||||||
info->pos = allocator->current->pos; | ||||||||||||
} | ||||||||||||
|
||||||||||||
void *frame_data_alloc(FrameDataAllocator *allocator, InterpreterFrame *frame, size_t size) | ||||||||||||
{ | ||||||||||||
|
||||||||||||
if (!allocator->infos_len || (allocator->infos_len > 0 && allocator->infos[allocator->infos_len - 1].frame != frame)) | ||||||||||||
{ | ||||||||||||
frame_data_push_info(allocator, frame); | ||||||||||||
} | ||||||||||||
|
||||||||||||
uint8_t *pos = allocator->current->pos; | ||||||||||||
|
||||||||||||
if (pos + size > allocator->current->end) { | ||||||||||||
if (allocator->current->next && ((allocator->current->next->start + size) <= allocator->current->next->end)) | ||||||||||||
{ | ||||||||||||
allocator->current = allocator->current->next; | ||||||||||||
pos = allocator->current->pos = allocator->current->start; | ||||||||||||
} | ||||||||||||
else | ||||||||||||
{ | ||||||||||||
frame_data_fragment_free(allocator->current->next); | ||||||||||||
FrameDataFragment *new_frag = frame_data_new_fragment(size); | ||||||||||||
assert(new_frag && "Failed to allocate new fragment"); | ||||||||||||
allocator->current->next = new_frag; | ||||||||||||
allocator->current = new_frag; | ||||||||||||
|
||||||||||||
pos = new_frag->pos; | ||||||||||||
} | ||||||||||||
} | ||||||||||||
|
||||||||||||
void *result = (void*)pos; | ||||||||||||
allocator->current->pos = (uint8_t *)(pos + size); | ||||||||||||
return result; | ||||||||||||
} | ||||||||||||
|
||||||||||||
void frame_data_pop_info(FrameDataAllocator *allocator, InterpreterFrame *pFrame) | ||||||||||||
{ | ||||||||||||
int top = allocator->infos_len - 1; | ||||||||||||
if (top >= 0 && allocator->infos[top].frame == pFrame) | ||||||||||||
{ | ||||||||||||
FrameDataInfo *info = &allocator->infos[--allocator->infos_len]; | ||||||||||||
allocator->current = info->frag; | ||||||||||||
allocator->current->pos = info->pos; | ||||||||||||
} | ||||||||||||
} | ||||||||||||
|
||||||||||||
InterpThreadContext* InterpGetThreadContext() | ||||||||||||
{ | ||||||||||||
InterpThreadContext *threadContext = t_pThreadContext; | ||||||||||||
|
@@ -21,6 +125,7 @@ InterpThreadContext* InterpGetThreadContext() | |||||||||||
// FIXME VirtualAlloc/mmap with INTERP_STACK_ALIGNMENT alignment | ||||||||||||
threadContext->pStackStart = threadContext->pStackPointer = (int8_t*)malloc(INTERP_STACK_SIZE); | ||||||||||||
threadContext->pStackEnd = threadContext->pStackStart + INTERP_STACK_SIZE; | ||||||||||||
frame_data_allocator_init(&threadContext->frameDataAllocator, INTERP_STACK_FRAGMENT_SIZE); | ||||||||||||
|
||||||||||||
t_pThreadContext = threadContext; | ||||||||||||
return threadContext; | ||||||||||||
|
@@ -584,7 +689,53 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr | |||||||||||
LOCAL_VAR(ip[1], double) = LOCAL_VAR(ip[2], double) * LOCAL_VAR(ip[3], double); | ||||||||||||
ip += 4; | ||||||||||||
break; | ||||||||||||
case INTOP_MUL_OVF_I4: | ||||||||||||
{ | ||||||||||||
int32_t i1 = LOCAL_VAR(ip[2], int32_t); | ||||||||||||
int32_t i2 = LOCAL_VAR(ip[3], int32_t); | ||||||||||||
int32_t i3; | ||||||||||||
if (__builtin_mul_overflow(i1, i2, &i3)) | ||||||||||||
kotlarmilos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
kotlarmilos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||
assert(0); // Interpreter-TODO: OverflowException | ||||||||||||
LOCAL_VAR(ip[1], int32_t) = i3; | ||||||||||||
ip += 4; | ||||||||||||
break; | ||||||||||||
} | ||||||||||||
|
||||||||||||
case INTOP_MUL_OVF_I8: | ||||||||||||
{ | ||||||||||||
int64_t i1 = LOCAL_VAR(ip[2], int64_t); | ||||||||||||
int64_t i2 = LOCAL_VAR(ip[3], int64_t); | ||||||||||||
int64_t i3; | ||||||||||||
if (__builtin_mul_overflow(i1, i2, &i3)) | ||||||||||||
kotlarmilos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||
assert(0); // Interpreter-TODO: OverflowException | ||||||||||||
LOCAL_VAR(ip[1], int64_t) = i3; | ||||||||||||
ip += 4; | ||||||||||||
break; | ||||||||||||
} | ||||||||||||
|
||||||||||||
case INTOP_MUL_OVF_UN_I4: | ||||||||||||
{ | ||||||||||||
uint32_t i1 = LOCAL_VAR(ip[2], uint32_t); | ||||||||||||
uint32_t i2 = LOCAL_VAR(ip[3], uint32_t); | ||||||||||||
uint32_t i3; | ||||||||||||
if (__builtin_mul_overflow(i1, i2, &i3)) | ||||||||||||
kotlarmilos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||
assert(0); // Interpreter-TODO: OverflowException | ||||||||||||
LOCAL_VAR(ip[1], uint32_t) = i3; | ||||||||||||
ip += 4; | ||||||||||||
break; | ||||||||||||
} | ||||||||||||
|
||||||||||||
case INTOP_MUL_OVF_UN_I8: | ||||||||||||
{ | ||||||||||||
uint64_t i1 = LOCAL_VAR(ip[2], uint64_t); | ||||||||||||
uint64_t i2 = LOCAL_VAR(ip[3], uint64_t); | ||||||||||||
uint64_t i3; | ||||||||||||
if (__builtin_mul_overflow(i1, i2, &i3)) | ||||||||||||
kotlarmilos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||
assert(0); // Interpreter-TODO: OverflowException | ||||||||||||
LOCAL_VAR(ip[1], uint64_t) = i3; | ||||||||||||
ip += 4; | ||||||||||||
break; | ||||||||||||
} | ||||||||||||
case INTOP_DIV_I4: | ||||||||||||
{ | ||||||||||||
int32_t i1 = LOCAL_VAR(ip[2], int32_t); | ||||||||||||
|
@@ -1105,6 +1256,22 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr | |||||||||||
memset(LOCAL_VAR(ip[1], void*), 0, ip[2]); | ||||||||||||
ip += 3; | ||||||||||||
break; | ||||||||||||
case INTOP_LOCALLOC: | ||||||||||||
{ | ||||||||||||
int32_t len = LOCAL_VAR(ip[2], int32_t); | ||||||||||||
void* mem; | ||||||||||||
|
||||||||||||
if (len > 0) | ||||||||||||
{ | ||||||||||||
mem = frame_data_alloc(&pThreadContext->frameDataAllocator, (InterpreterFrame*)pFrame, ALIGN_UP(len, INTERP_STACK_ALIGNMENT)); | ||||||||||||
} else | ||||||||||||
{ | ||||||||||||
mem = NULL; | ||||||||||||
|
// Put the size value in targetReg. If it is zero, bail out by returning null in targetReg. | |
genConsumeRegAndCopy(size, targetReg); | |
endLabel = genCreateTempLabel(); | |
GetEmitter()->emitIns_R_R(INS_test, easz, targetReg, targetReg); | |
inst_JMP(EJ_je, endLabel); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for pointing it out. Looks like there is a mismatch between alloca in C++ and the IL instruction.
I think it would be best to match what RyuJIT does and return zero as well like you have done originally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, reverted.
Uh oh!
There was an error while loading. Please reload this page.