Skip to content

Commit

Permalink
Track stack depths precisely in interpreter
Browse files Browse the repository at this point in the history
And pass those along to spesh. This means that it always has accurate
stack depths to use when making decisions about ordering of the
specializations.
  • Loading branch information
jnthn committed Oct 8, 2021
1 parent a3b6e7b commit 824fb58
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 19 deletions.
4 changes: 4 additions & 0 deletions src/6model/reprs/MVMContinuation.h
Expand Up @@ -28,6 +28,10 @@ struct MVMContinuationBody {
/* If we're profiling, then data needed to cope with the continuation
* being invoked again. */
MVMProfileContinuationData *prof_cont;

/* The call depth of the region prior to the one we sliced off, so we can
* fix up call depths when invokving the continuation. */
MVMuint32 prior_call_depth;
};
struct MVMContinuation {
MVMObject common;
Expand Down
6 changes: 5 additions & 1 deletion src/6model/reprs/MVMSpeshLog.h
Expand Up @@ -32,7 +32,11 @@ typedef enum {
/* An entry in the spesh log. */
struct MVMSpeshLogEntry {
/* The kind of log entry it is; discriminator for the union. */
MVMint32 kind;
MVMuint8 kind;

/* The call depth, if it is an ENTRY. Junk otherwise. Sneaked in
* here to avoid making the entry record any bigger. */
MVMuint16 call_depth;

/* Call frame correlation ID. */
MVMint32 id;
Expand Down
31 changes: 24 additions & 7 deletions src/core/callstack.c
Expand Up @@ -31,6 +31,7 @@ static void next_region(MVMThreadContext *tc) {
region->next = next;
next->prev = region;
}
region->next->call_depth = region->call_depth;
tc->stack_current_region = region->next;
}

Expand All @@ -49,6 +50,7 @@ static void next_oversize_region(MVMThreadContext *tc, size_t size) {
region->next = next;
next->prev = region;
}
region->next->call_depth = region->call_depth;
tc->stack_current_region = region->next;
}

Expand Down Expand Up @@ -140,13 +142,15 @@ void MVM_callstack_init(MVMThreadContext *tc) {
MVMCallStackFrame * MVM_callstack_allocate_frame(MVMThreadContext *tc) {
tc->stack_top = allocate_record(tc, MVM_CALLSTACK_RECORD_FRAME,
sizeof(MVMCallStackFrame));
tc->stack_current_region->call_depth++;
return (MVMCallStackFrame *)tc->stack_top;
}

/* Allocates a bytecode frame record on the callstack. */
MVMCallStackHeapFrame * MVM_callstack_allocate_heap_frame(MVMThreadContext *tc) {
tc->stack_top = allocate_record(tc, MVM_CALLSTACK_RECORD_HEAP_FRAME,
sizeof(MVMCallStackHeapFrame));
tc->stack_current_region->call_depth++;
return (MVMCallStackHeapFrame *)tc->stack_top;
}

Expand Down Expand Up @@ -295,7 +299,7 @@ void MVM_callstack_new_continuation_region(MVMThreadContext *tc, MVMObject *tag)
* the previous region. The first region in the slice is retunred. The prev
* pointer of both the region and of the region start record are NULL'd out. */
MVMCallStackRegion * MVM_callstack_continuation_slice(MVMThreadContext *tc, MVMObject *tag,
MVMActiveHandler **active_handlers) {
MVMActiveHandler **active_handlers, MVMuint32 *prior_call_depth) {
MVMCallStackRegion *cur_region = tc->stack_current_region;
while (cur_region != NULL) {
MVMCallStackRecord *record = (MVMCallStackRecord *)cur_region->start;
Expand All @@ -312,9 +316,11 @@ MVMCallStackRegion * MVM_callstack_continuation_slice(MVMThreadContext *tc, MVMO
tc->stack_top = tag_record->common.prev;
tag_record->common.prev = NULL;

/* Hand back the active handlers at the reset point through the
* out argument, and the region pointer as the return value. */
/* Hand back the active handlers at the reset point and prior
* call depth through the out arguments, and the region pointer
* as the return value. */
*active_handlers = tag_record->active_handlers;
*prior_call_depth = tc->stack_current_region->call_depth;
return cur_region;
}
}
Expand All @@ -333,7 +339,7 @@ static void free_regions_from(MVMCallStackRegion *cur) {
}
}
void MVM_callstack_continuation_append(MVMThreadContext *tc, MVMCallStackRegion *first_region,
MVMCallStackRecord *stack_top, MVMObject *update_tag) {
MVMCallStackRecord *stack_top, MVMObject *update_tag, MVMuint32 prior_call_depth) {
/* Ensure the first record in the region to append is a continuation tag. */
MVMCallStackRecord *record = (MVMCallStackRecord *)first_region->start;
if (record->kind != MVM_CALLSTACK_RECORD_CONTINUATION_TAG)
Expand All @@ -345,18 +351,28 @@ void MVM_callstack_continuation_append(MVMThreadContext *tc, MVMCallStackRegion
tag_record->active_handlers = tc->active_handlers;

/* If we have next regions, free them (this prevents us ending up with
* runaway memory use then continuations move between threads in producer
* runaway memory use when continuations move between threads in producer
* consumer style patterns). */
free_regions_from(tc->stack_current_region->next);

/* Work out the difference to apply to the stack depths in the regions.
* If we were NB frames deep before the continuation tag when we did the
* continuation control, and we're NA frames deep now, then we need to
* adjust the frame depth by adding NA - NB. This will come out negative
* if we are shallower now, and positive if deeper. */
MVMint32 depth_diff = tc->stack_current_region->call_depth - prior_call_depth;

/* Insert continuation regions into the region list. */
tc->stack_current_region->next = first_region;
first_region->prev = tc->stack_current_region;

/* Make sure the current stack region is the one containing the stack top. */
/* Make sure the current stack region is the one containing the stack top,
* tweaking their call depths as we go. */
while ((char *)stack_top < tc->stack_current_region->start ||
(char *)stack_top > tc->stack_current_region->alloc)
(char *)stack_top > tc->stack_current_region->alloc) {
tc->stack_current_region = tc->stack_current_region->next;
tc->stack_current_region->call_depth += depth_diff;
}

/* Make the first record we splice in point back to the current stack top. */
record->prev = tc->stack_top;
Expand Down Expand Up @@ -430,6 +446,7 @@ static void handle_end_of_dispatch_record(MVMThreadContext *tc, MVMuint32 *thunk
}
}
static void exit_frame(MVMThreadContext *tc, MVMFrame *returner) {
tc->stack_current_region->call_depth--;
MVMFrame *caller = returner->caller;
if (caller && (returner != tc->thread_entry_frame || tc->nested_interpreter)) {
if (tc->jit_return_address != NULL) {
Expand Down
10 changes: 5 additions & 5 deletions src/core/callstack.h
Expand Up @@ -23,9 +23,9 @@ struct MVMCallStackRegion {
/* The end of the allocatable region. */
char *alloc_limit;

#if MVM_PTR_SIZE == 4
MVMuint32 thingy_to_ensure_8_byte_alignment;
#endif
/* The current call depth of the deepest frame on this stack
* segment. */
MVMuint32 call_depth;
};

/* The default size of a call stack region. */
Expand Down Expand Up @@ -341,9 +341,9 @@ MVMCallStackDeoptedResumeInit * MVM_callstack_allocate_deopted_resume_init(
MVMThreadContext *tc, MVMSpeshResumeInit *ri);
void MVM_callstack_new_continuation_region(MVMThreadContext *tc, MVMObject *tag);
MVMCallStackRegion * MVM_callstack_continuation_slice(MVMThreadContext *tc, MVMObject *tag,
MVMActiveHandler **active_handlers);
MVMActiveHandler **active_handlers, MVMuint32 *prior_call_depth);
void MVM_callstack_continuation_append(MVMThreadContext *tc, MVMCallStackRegion *first_region,
MVMCallStackRecord *stack_top, MVMObject *update_tag);
MVMCallStackRecord *stack_top, MVMObject *update_tag, MVMuint32 prior_call_depth);
MVMFrame * MVM_callstack_first_frame_in_region(MVMThreadContext *tc, MVMCallStackRegion *region);
MVMCallStackDispatchRecord * MVM_callstack_find_topmost_dispatch_recording(MVMThreadContext *tc);
MVMFrame * MVM_callstack_unwind_frame(MVMThreadContext *tc, MVMuint8 exceptional, MVMuint32 *thunked);
Expand Down
7 changes: 5 additions & 2 deletions src/core/continuation.c
Expand Up @@ -56,9 +56,10 @@ void MVM_continuation_control(MVMThreadContext *tc, MVMint64 protect,

/* Find the tag and slice the required regions off the callstack. */
MVMActiveHandler *active_handler_at_reset;
MVMuint32 prior_call_depth;
MVMCallStackRecord *orig_top = tc->stack_top;
MVMCallStackRegion *taken_region = MVM_callstack_continuation_slice(tc, tag,
&active_handler_at_reset);
&active_handler_at_reset, &prior_call_depth);
if (!taken_region)
MVM_exception_throw_adhoc(tc, "No matching continuation reset found");

Expand All @@ -71,6 +72,7 @@ void MVM_continuation_control(MVMThreadContext *tc, MVMint64 protect,
((MVMContinuation *)cont)->body.first_region = taken_region;
((MVMContinuation *)cont)->body.addr = *tc->interp_cur_op;
((MVMContinuation *)cont)->body.res_reg = res_reg;
((MVMContinuation *)cont)->body.prior_call_depth = prior_call_depth;
if (tc->instance->profiling)
((MVMContinuation *)cont)->body.prof_cont =
MVM_profile_log_continuation_control(tc, first_frame);
Expand Down Expand Up @@ -169,7 +171,8 @@ void MVM_continuation_invoke(MVMThreadContext *tc, MVMContinuation *cont,
* Then detach it from the wrapper object. */
MVM_callstack_continuation_append(tc, cont->body.first_region,
cont->body.stack_top,
cont->body.protected_tag ? cont->body.protected_tag : insert_tag);
cont->body.protected_tag ? cont->body.protected_tag : insert_tag,
cont->body.prior_call_depth);
cont->body.first_region = NULL;
cont->body.stack_top = NULL;

Expand Down
1 change: 1 addition & 0 deletions src/spesh/log.c
Expand Up @@ -114,6 +114,7 @@ void MVM_spesh_log_entry(MVMThreadContext *tc, MVMint32 cid, MVMStaticFrame *sf,
/* Log the entry itself. */
MVMSpeshLogEntry *entry = &(sl->body.entries[sl->body.used]);
entry->kind = MVM_SPESH_LOG_ENTRY;
entry->call_depth = (MVMuint16)tc->stack_current_region->call_depth;
entry->id = cid;
MVM_ASSIGN_REF(tc, &(sl->common.header), entry->entry.sf, sf);
MVMCallsite *cs = args.callsite;
Expand Down
8 changes: 4 additions & 4 deletions src/spesh/stats.c
Expand Up @@ -250,10 +250,10 @@ void sim_stack_init(MVMThreadContext *tc, MVMSpeshSimStack *sims) {

/* Pushes an entry onto the stack frame model. */
void sim_stack_push(MVMThreadContext *tc, MVMSpeshSimStack *sims, MVMStaticFrame *sf,
MVMSpeshStats *ss, MVMuint32 cid, MVMuint32 callsite_idx) {
MVMSpeshStats *ss, MVMuint32 cid, MVMuint32 callsite_idx,
MVMuint32 call_depth) {
MVMSpeshSimStackFrame *frame;
MVMCallsite *cs;
MVMint32 depth = sims->used ? sims->frames[sims->used - 1].depth + 1 : 1;
if (sims->used == sims->limit) {
sims->limit *= 2;
sims->frames = MVM_realloc(sims->frames, sims->limit * sizeof(MVMSpeshSimStackFrame));
Expand All @@ -274,7 +274,7 @@ void sim_stack_push(MVMThreadContext *tc, MVMSpeshSimStack *sims, MVMStaticFrame
frame->call_type_info_used = frame->call_type_info_limit = 0;
frame->last_invoke_offset = 0;
frame->last_invoke_sf = NULL;
frame->depth = depth;
frame->depth = call_depth;
}

/* Adds an entry to a sim frame's callsite type info list, for later
Expand Down Expand Up @@ -550,7 +550,7 @@ void MVM_spesh_stats_update(MVMThreadContext *tc, MVMSpeshLog *sl, MVMObject *s
ss->hits++;
callsite_idx = by_callsite_idx(tc, ss, e->entry.cs);
ss->by_callsite[callsite_idx].hits++;
sim_stack_push(tc, sims, e->entry.sf, ss, e->id, callsite_idx);
sim_stack_push(tc, sims, e->entry.sf, ss, e->id, callsite_idx, e->call_depth);
break;
}
case MVM_SPESH_LOG_PARAMETER: {
Expand Down

0 comments on commit 824fb58

Please sign in to comment.