diff --git a/src/moar.h b/src/moar.h index 0eaa581294..684527a712 100644 --- a/src/moar.h +++ b/src/moar.h @@ -143,13 +143,13 @@ MVM_PUBLIC const MVMint32 MVM_jit_support(void); #include "core/regionalloc.h" #include "spesh/dump.h" #include "spesh/debug.h" +#include "spesh/pea.h" #include "spesh/graph.h" #include "spesh/codegen.h" #include "spesh/candidate.h" #include "spesh/manipulate.h" #include "spesh/args.h" #include "spesh/usages.h" -#include "spesh/pea.h" #include "spesh/facts.h" #include "spesh/optimize.h" #include "spesh/dead_bb_elimination.h" diff --git a/src/spesh/candidate.c b/src/spesh/candidate.c index 66e55bc947..8f44175568 100644 --- a/src/spesh/candidate.c +++ b/src/spesh/candidate.c @@ -97,6 +97,7 @@ void MVM_spesh_candidate_add(MVMThreadContext *tc, MVMSpeshPlanned *p) { candidate->num_deopts = sg->num_deopt_addrs; candidate->deopts = sg->deopt_addrs; candidate->deopt_named_used_bit_field = sg->deopt_named_used_bit_field; + candidate->deopt_pea = sg->deopt_pea; candidate->num_locals = sg->num_locals; candidate->num_lexicals = sg->num_lexicals; candidate->num_inlines = sg->num_inlines; @@ -204,6 +205,7 @@ void MVM_spesh_candidate_destroy(MVMThreadContext *tc, MVMSpeshCandidate *candid MVM_free(candidate->handlers); MVM_free(candidate->spesh_slots); MVM_free(candidate->deopts); + MVM_spesh_pea_destroy_deopt_info(tc, &(candidate->deopt_pea)); MVM_free(candidate->inlines); MVM_free(candidate->local_types); MVM_free(candidate->lexical_types); diff --git a/src/spesh/candidate.h b/src/spesh/candidate.h index 4714b31d8d..c7f7073274 100644 --- a/src/spesh/candidate.h +++ b/src/spesh/candidate.h @@ -28,6 +28,9 @@ struct MVMSpeshCandidate { * typically don't update the array in specialized code. */ MVMuint64 deopt_named_used_bit_field; + /* Deopt information produced by escape analysis and scalar replacement. */ + MVMSpeshPEADeopt deopt_pea; + /* Number of inlines and inlines table; see graph.h for description of * the table format. */ MVMint32 num_inlines; diff --git a/src/spesh/deopt.c b/src/spesh/deopt.c index 1bd79553ad..0c12b82c90 100644 --- a/src/spesh/deopt.c +++ b/src/spesh/deopt.c @@ -157,11 +157,30 @@ static void deopt_named_args_used(MVMThreadContext *tc, MVMFrame *f) { f->params.named_used.bit_field = f->spesh_cand->deopt_named_used_bit_field; } +/* Materialize an individual replaced object. */ +static void materialize_object(MVMThreadContext *tc, MVMFrame *f, MVMuint32 info_idx) { + MVM_panic(1, "Deopt: materialize_object NYI"); +} + +/* Materialize all replaced objects that need to be at this deopt point. */ +static void materialize_replaced_objects(MVMThreadContext *tc, MVMFrame *f, MVMint32 deopt_offset) { + MVMint32 i; + MVMSpeshCandidate *cand = f->spesh_cand; + for (i = 0; i < MVM_VECTOR_ELEMS(cand->deopt_pea.deopt_point); i++) { + if (cand->deopt_pea.deopt_point[i].deopt_point_idx == deopt_offset) + materialize_object(tc, f, cand->deopt_pea.deopt_point[i].materialize_info_idx); + } +} + static void deopt_frame(MVMThreadContext *tc, MVMFrame *f, MVMint32 deopt_offset, MVMint32 deopt_target) { - /* Found it; are we in an inline? */ - MVMSpeshInline *inlines = f->spesh_cand->inlines; + /* Found it. We materialize any replaced objects first, then if + * we have stuff replaced in inlines then uninlining will take + * care of moving it out into the frames where it belongs. */ deopt_named_args_used(tc, f); - if (inlines) { + materialize_replaced_objects(tc, f, deopt_offset); + + /* Check if we have inlines. */ + if (f->spesh_cand->inlines) { /* Yes, going to have to re-create the frames; uninline * moves the interpreter, so we can just tweak the last * frame. For the moment, uninlining creates its frames @@ -192,7 +211,6 @@ static void deopt_frame(MVMThreadContext *tc, MVMFrame *f, MVMint32 deopt_offset MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.cuuid)); #endif } - } /* De-optimizes the currently executing frame, provided it is specialized and diff --git a/src/spesh/graph.h b/src/spesh/graph.h index 70d1f70e13..930163c11d 100644 --- a/src/spesh/graph.h +++ b/src/spesh/graph.h @@ -69,6 +69,9 @@ struct MVMSpeshGraph { MVMuint32 *always_retained_deopt_idxs; MVMuint32 num_always_retained_deopt_idxs; + /* Deopt information produced by escape analysis and scalar replacement. */ + MVMSpeshPEADeopt deopt_pea; + /* Table of information about inlines, laid out in order of nesting * depth. Thus, going through the table in order and finding when we * are within the bounds will show up each call frame that needs to diff --git a/src/spesh/pea.c b/src/spesh/pea.c index a685b9a7d9..9cc05ab2c8 100644 --- a/src/spesh/pea.c +++ b/src/spesh/pea.c @@ -545,3 +545,9 @@ void MVM_spesh_pea(MVMThreadContext *tc, MVMSpeshGraph *g) { MVM_VECTOR_DESTROY(gs.bb_states[i].transformations); MVM_VECTOR_DESTROY(gs.shadow_facts); } + +/* Clean up any deopt info. */ +void MVM_spesh_pea_destroy_deopt_info(MVMThreadContext *tc, MVMSpeshPEADeopt *deopt_pea) { + MVM_VECTOR_DESTROY(deopt_pea->materialize_info); + MVM_VECTOR_DESTROY(deopt_pea->deopt_point); +} diff --git a/src/spesh/pea.h b/src/spesh/pea.h index 2b5a2efb9b..edf2bd3b4c 100644 --- a/src/spesh/pea.h +++ b/src/spesh/pea.h @@ -30,4 +30,42 @@ struct MVMSpeshPEAInfo { MVMSpeshPEAAllocation *depend_allocation; }; +/* Information that we retain about a replaced allocations in order that we + * can materialize them upon deoptimization. */ +struct MVMSpeshPEADeopt { + /* Array of materialization info, specifying how to materialize a given + * replaced object. */ + MVM_VECTOR_DECL(MVMSpeshPEAMaterializeInfo, materialize_info); + + /* Pairings of deoptimization points and objects to materialize at those + * point. */ + MVM_VECTOR_DECL(MVMSpeshPEADeoptPoint, deopt_point); +}; + +/* The information needed to materialize a particular replaced allocation + * (that is, to recreate it on the heap). */ +struct MVMSpeshPEAMaterializeInfo { + /* The spesh slot containing the STable of the object to materialize. */ + MVMuint16 stable_sslot; + + /* The register to materialize into. */ + MVMuint16 target_reg; + + /* A list of the registers holding the attributes to put into the + * materialized object. */ + MVMuint16 *attr_regs; +}; + +/* Information about that needs to be materialized at a particular deopt + * point. */ +struct MVMSpeshPEADeoptPoint { + /* The index of the deopt point. */ + MVMint32 deopt_point_idx; + + /* The index into the materialize_info specifying how to materialize + * this object. */ + MVMuint32 materialize_info_idx; +}; + void MVM_spesh_pea(MVMThreadContext *tc, MVMSpeshGraph *g); +void MVM_spesh_pea_destroy_deopt_info(MVMThreadContext *tc, MVMSpeshPEADeopt *deopt_pea); diff --git a/src/types.h b/src/types.h index fcf66c2aa6..556611a773 100644 --- a/src/types.h +++ b/src/types.h @@ -203,6 +203,9 @@ typedef struct MVMSpeshDeoptUseEntry MVMSpeshDeoptUseEntry; typedef struct MVMSpeshFrameWalker MVMSpeshFrameWalker; typedef struct MVMSpeshPEAInfo MVMSpeshPEAInfo; typedef struct MVMSpeshPEAAllocation MVMSpeshPEAAllocation; +typedef struct MVMSpeshPEADeopt MVMSpeshPEADeopt; +typedef struct MVMSpeshPEAMaterializeInfo MVMSpeshPEAMaterializeInfo; +typedef struct MVMSpeshPEADeoptPoint MVMSpeshPEADeoptPoint; typedef struct MVMSTable MVMSTable; typedef struct MVMStaticFrame MVMStaticFrame; typedef struct MVMStaticFrameBody MVMStaticFrameBody;