+/* replace_patch_method_pointer ************************************************
+
+ Patch a method pointer (may be in code, data segment, vftbl, or interface
+ table).
+
+ IN:
+ mpp..............address of the method pointer to patch
+ entrypoint.......the new entrypoint of the method
+ kind.............kind of call to patch, used only for debugging
+
+*******************************************************************************/
+
+static void replace_patch_method_pointer(methodptr *mpp,
+ methodptr entrypoint,
+ const char *kind)
+{
+#if !defined(NDEBUG)
+ codeinfo *oldcode;
+ codeinfo *newcode;
+#endif
+
+ DOLOG( printf("patch method pointer from: %p to %p\n",
+ (void*) *mpp, (void*)entrypoint); );
+
+#if !defined(NDEBUG)
+ oldcode = code_get_codeinfo_for_pv(*mpp);
+ newcode = code_get_codeinfo_for_pv(entrypoint);
+
+ DOLOG_SHORT( printf("\tpatch %s %p ", kind, (void*) oldcode);
+ method_println(oldcode->m);
+ printf("\t with %p ", (void*) newcode);
+ method_println(newcode->m); );
+
+ assert(oldcode->m == newcode->m);
+#endif
+
+ /* write the new entrypoint */
+
+ *mpp = (methodptr) entrypoint;
+}
+
+
+/* replace_patch_class *********************************************************
+
+ Patch a method in the given class.
+
+ IN:
+ vftbl............vftbl of the class
+ m................the method to patch
+ oldentrypoint....the old entrypoint to replace
+ entrypoint.......the new entrypoint
+
+*******************************************************************************/
+
+void replace_patch_class(vftbl_t *vftbl,
+ methodinfo *m,
+ u1 *oldentrypoint,
+ u1 *entrypoint)
+{
+ s4 i;
+ methodptr *mpp;
+ methodptr *mppend;
+
+ /* patch the vftbl of the class */
+
+ replace_patch_method_pointer(vftbl->table + m->vftblindex,
+ entrypoint,
+ "virtual ");
+
+ /* patch the interface tables */
+
+ assert(oldentrypoint);
+
+ for (i=0; i < vftbl->interfacetablelength; ++i) {
+ mpp = vftbl->interfacetable[-i];
+ mppend = mpp + vftbl->interfacevftbllength[i];
+ for (; mpp != mppend; ++mpp)
+ if (*mpp == oldentrypoint) {
+ replace_patch_method_pointer(mpp, entrypoint, "interface");
+ }
+ }
+}
+
+
+/* replace_patch_class_hierarchy ***********************************************
+
+ Patch a method in all loaded classes.
+
+ IN:
+ m................the method to patch
+ oldentrypoint....the old entrypoint to replace
+ entrypoint.......the new entrypoint
+
+*******************************************************************************/
+
+struct replace_patch_data_t {
+ methodinfo *m;
+ u1 *oldentrypoint;
+ u1 *entrypoint;
+};
+
+void replace_patch_callback(classinfo *c, struct replace_patch_data_t *pd)
+{
+ vftbl_t *vftbl = c->vftbl;
+
+ if (vftbl != NULL
+ && vftbl->vftbllength > pd->m->vftblindex
+ && vftbl->table[pd->m->vftblindex] != &asm_abstractmethoderror
+ && code_get_methodinfo_for_pv(vftbl->table[pd->m->vftblindex]) == pd->m)
+ {
+ replace_patch_class(c->vftbl, pd->m, pd->oldentrypoint, pd->entrypoint);
+ }
+}
+
+void replace_patch_class_hierarchy(methodinfo *m,
+ u1 *oldentrypoint,
+ u1 *entrypoint)
+{
+ struct replace_patch_data_t pd;
+
+ pd.m = m;
+ pd.oldentrypoint = oldentrypoint;
+ pd.entrypoint = entrypoint;
+
+ DOLOG_SHORT( printf("patching class hierarchy: ");
+ method_println(m); );
+
+ classcache_foreach_loaded_class(
+ (classcache_foreach_functionptr_t) &replace_patch_callback,
+ (void*) &pd);
+}
+
+
+/* replace_patch_future_calls **************************************************
+
+ Analyse a call site and depending on the kind of call patch the call, the
+ virtual function table, or the interface table.
+
+ IN:
+ ra...............return address pointing after the call site
+ callerframe......source frame of the caller
+ calleeframe......source frame of the callee, must have been mapped
+
+*******************************************************************************/
+
+void replace_patch_future_calls(u1 *ra,
+ sourceframe_t *callerframe,
+ sourceframe_t *calleeframe)
+{
+ u1 *patchpos;
+ methodptr entrypoint;
+ methodptr oldentrypoint;
+ bool atentry;
+ void *pv;
+ codeinfo *calleecode;
+ methodinfo *calleem;
+ java_object_t *obj;
+ vftbl_t *vftbl;
+
+ assert(ra);
+ assert(callerframe->down == calleeframe);
+
+ /* get the new codeinfo and the method that shall be entered */
+
+ calleecode = calleeframe->tocode;
+ assert(calleecode);
+
+ calleem = calleeframe->method;
+ assert(calleem == calleecode->m);
+
+ entrypoint = (methodptr) calleecode->entrypoint;
+
+ /* check if we are at an method entry rplpoint at the innermost frame */
+
+ atentry = (calleeframe->down == NULL)
+ && !(calleem->flags & ACC_STATIC)
+ && (calleeframe->fromrp->id == 0); /* XXX */
+
+ /* get the position to patch, in case it was a statically bound call */
+
+ pv = callerframe->fromcode->entrypoint;
+ patchpos = md_jit_method_patch_address(pv, ra, NULL);
+
+ if (patchpos == NULL) {
+ /* the call was dispatched dynamically */
+
+ /* we can only patch such calls if we are at the entry point */
+
+ if (!atentry)
+ return;
+
+ assert((calleem->flags & ACC_STATIC) == 0);
+
+ oldentrypoint = calleeframe->fromcode->entrypoint;
+
+ /* we need to know the instance */
+
+ if (!calleeframe->instance.a) {
+ DOLOG_SHORT( printf("WARNING: object instance unknown!\n"); );
+ replace_patch_class_hierarchy(calleem, oldentrypoint, entrypoint);
+ return;
+ }
+
+ /* get the vftbl */
+
+ obj = calleeframe->instance.a;
+ vftbl = obj->vftbl;
+
+ assert(vftbl->class->vftbl == vftbl);
+
+ DOLOG_SHORT( printf("\tclass: "); class_println(vftbl->class); );
+
+ replace_patch_class(vftbl, calleem, oldentrypoint, entrypoint);
+ }
+ else {
+ /* the call was statically bound */
+
+ replace_patch_method_pointer((methodptr *) patchpos, entrypoint, "static ");
+ }
+}
+
+
+/* replace_push_activation_record **********************************************
+
+ Push a stack frame onto the execution state.
+
+ *** This function imitates the effects of a call and the ***
+ *** method prolog of the callee. ***
+
+ IN:
+ es...............execution state
+ rpcall...........the replacement point at the call site
+ callerframe......source frame of the caller, or NULL for creating the
+ first frame
+ calleeframe......source frame of the callee, must have been mapped
+
+ OUT:
+ *es..............the execution state after pushing the stack frame
+
+*******************************************************************************/
+
+void replace_push_activation_record(executionstate_t *es,
+ rplpoint *rpcall,
+ sourceframe_t *callerframe,
+ sourceframe_t *calleeframe)
+{
+ s4 reg;
+ s4 i;
+ s4 count;
+ stackslot_t *basesp;
+ stackslot_t *sp;
+ u1 *ra;
+ codeinfo *calleecode;
+
+ assert(es);
+ assert(!rpcall || callerframe);
+ assert(!rpcall || rpcall->type == RPLPOINT_TYPE_CALL);
+ assert(!rpcall || rpcall == callerframe->torp);
+ assert(calleeframe);
+ assert(!callerframe || calleeframe == callerframe->down);
+
+ /* the compilation unit we are entering */
+
+ calleecode = calleeframe->tocode;
+ assert(calleecode);
+
+ /* calculate the return address */
+
+ if (rpcall)
+ ra = rpcall->pc + rpcall->callsize;
+ else
+ ra = es->pc + 1 /* XXX this is ugly */;
+
+ /* write the return address */
+
+#if defined(REPLACE_RA_BETWEEN_FRAMES)
+ es->sp -= SIZE_OF_STACKSLOT;
+
+ *((stackslot_t *)es->sp) = (stackslot_t) ra;
+#endif /* REPLACE_RA_BETWEEN_FRAMES */
+
+#if defined(REPLACE_REG_RA)
+ es->intregs[REPLACE_REG_RA] = (ptrint) ra;
+#endif
+
+ /* we move into a new code unit */
+
+ es->code = calleecode;
+
+ /* set the new pc XXX not needed? */
+
+ es->pc = calleecode->entrypoint;
+
+ /* build the stackframe */
+
+ DOLOG( printf("building stackframe of %d words at %p\n",
+ calleecode->stackframesize, (void*)es->sp); );
+
+ sp = (stackslot_t *) es->sp;
+ basesp = sp;
+
+ sp -= calleecode->stackframesize;
+ es->sp = (u1*) sp;
+
+ /* in debug mode, invalidate stack frame first */
+
+ /* XXX may not invalidate linkage area used by native code! */
+#if !defined(NDEBUG) && 0
+ for (i=0; i<(basesp - sp); ++i) {
+ sp[i] = 0xdeaddeadU;
+ }
+#endif
+
+ /* save the return address register */
+
+#if defined(REPLACE_RA_TOP_OF_FRAME)
+#if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
+ if (!code_is_leafmethod(calleecode))
+#endif
+ *--basesp = (ptrint) ra;
+#endif /* REPLACE_RA_TOP_OF_FRAME */
+
+#if defined(REPLACE_RA_LINKAGE_AREA)
+#if defined(REPLACE_LEAFMETHODS_RA_REGISTER)
+ if (!code_is_leafmethod(calleecode))
+#endif
+ basesp[LA_LR_OFFSET / sizeof(stackslot_t)] = (ptrint) ra;
+#endif /* REPLACE_RA_LINKAGE_AREA */
+
+ /* save int registers */
+
+ reg = INT_REG_CNT;
+ for (i=0; i<calleecode->savedintcount; ++i) {
+ while (nregdescint[--reg] != REG_SAV)
+ ;
+ *--basesp = es->intregs[reg];
+
+ /* XXX may not clobber saved regs used by native code! */
+#if !defined(NDEBUG) && 0
+ es->intregs[reg] = (ptrint) 0x44dead4444dead44ULL;
+#endif
+ }
+
+ /* save flt registers */
+
+ /* XXX align? */
+ reg = FLT_REG_CNT;
+ for (i=0; i<calleecode->savedfltcount; ++i) {
+ while (nregdescfloat[--reg] != REG_SAV)
+ ;
+ basesp -= STACK_SLOTS_PER_FLOAT;
+ *(double*)basesp = es->fltregs[reg];
+
+ /* XXX may not clobber saved regs used by native code! */
+#if !defined(NDEBUG) && 0
+ *(u8*)&(es->fltregs[reg]) = 0x44dead4444dead44ULL;
+#endif
+ }
+
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+ /* save adr registers */
+
+ reg = ADR_REG_CNT;
+ for (i=0; i<calleecode->savedadrcount; ++i) {
+ while (nregdescadr[--reg] != REG_SAV)
+ ;
+ *--basesp = es->adrregs[reg];
+
+ /* XXX may not clobber saved regs used by native code! */
+#if !defined(NDEBUG) && 0
+ es->adrregs[reg] = (ptrint) 0x44dead4444dead44ULL;
+#endif
+ }
+#endif
+
+ /* write slots used for synchronization */
+
+ count = code_get_sync_slot_count(calleecode);
+ assert(count == calleeframe->syncslotcount);
+ for (i=0; i<count; ++i) {
+ sp[calleecode->memuse + i] = calleeframe->syncslots[i].p;
+ }
+
+ /* set the PV */
+
+ es->pv = calleecode->entrypoint;
+
+ /* redirect future invocations */
+
+ if (callerframe && rpcall) {
+#if defined(REPLACE_PATCH_ALL)
+ if (rpcall->type == callerframe->fromrp->type)
+#else
+ if (rpcall == callerframe->fromrp)
+#endif
+ replace_patch_future_calls(ra, callerframe, calleeframe);
+ }
+}
+
+
+/* replace_find_replacement_point **********************************************
+
+ Find the replacement point in the given code corresponding to the
+ position given in the source frame.
+
+ IN:
+ code.............the codeinfo in which to search the rplpoint
+ frame............the source frame defining the position to look for
+ parent...........parent replacement point to match
+
+ RETURN VALUE:
+ the replacement point
+
+*******************************************************************************/
+
+rplpoint * replace_find_replacement_point(codeinfo *code,
+ sourceframe_t *frame,
+ rplpoint *parent)
+{
+ methodinfo *m;
+ rplpoint *rp;
+ s4 i;
+ s4 j;
+ s4 stacki;
+ rplalloc *ra;
+
+ assert(code);
+ assert(frame);
+
+ DOLOG( printf("searching replacement point for:\n");
+ replace_source_frame_println(frame); );
+
+ m = frame->method;
+
+ DOLOG( printf("code = %p\n", (void*)code); );
+
+ rp = code->rplpoints;
+ i = code->rplpointcount;
+ while (i--) {
+ if (rp->id == frame->id && rp->method == frame->method
+ && rp->parent == parent
+ && replace_normalize_type_map[rp->type] == frame->type)
+ {
+ /* check if returnAddresses match */
+ /* XXX optimize: only do this if JSRs in method */
+ DOLOG( printf("checking match for:");
+ replace_replacement_point_println(rp, 1); fflush(stdout); );
+ ra = rp->regalloc;
+ stacki = 0;
+ for (j = rp->regalloccount; j--; ++ra) {
+ if (ra->type == TYPE_RET) {
+ if (ra->index == RPLALLOC_STACK) {
+ assert(stacki < frame->javastackdepth);
+ if (frame->javastack[stacki].i != ra->regoff)
+ goto no_match;
+ stacki++;
+ }
+ else {
+ assert(ra->index >= 0 && ra->index < frame->javalocalcount);
+ if (frame->javalocals[ra->index].i != ra->regoff)
+ goto no_match;
+ }
+ }
+ }
+
+ /* found */
+ return rp;
+ }
+no_match:
+ rp++;
+ }
+
+#if !defined(NDEBUG)
+ printf("candidate replacement points were:\n");
+ rp = code->rplpoints;
+ i = code->rplpointcount;
+ for (; i--; ++rp) {
+ replace_replacement_point_println(rp, 1);
+ }
+#endif
+
+ vm_abort("no matching replacement point found");
+ return NULL; /* NOT REACHED */
+}
+
+
+/* replace_find_replacement_point_for_pc ***************************************
+
+ Find the nearest replacement point at or before the given PC. The
+ given PC has to be between (rp->pc) and (rp->pc+rp->callsize) for
+ the replacement point to be found.
+
+ IN:
+ code.............compilation unit the PC is in
+ pc...............the machine code PC
+
+ RETURN VALUE:
+ the replacement point found, or
+ NULL if no replacement point was found
+
+*******************************************************************************/
+
+rplpoint *replace_find_replacement_point_for_pc(codeinfo *code, u1 *pc)
+{
+ rplpoint *found;
+ rplpoint *rp;
+ s4 i;
+
+ DOLOG( printf("searching for rp at pc:%p in %p ", (void*)pc, (void*)code);
+ method_println(code->m); );
+
+ found = NULL;
+
+ rp = code->rplpoints;
+ for (i=0; i<code->rplpointcount; ++i, ++rp) {
+ DOLOG( replace_replacement_point_println(rp, 2); );
+ if (rp->pc <= pc && rp->pc + rp->callsize >= pc)
+ found = rp;
+ }
+
+ return found;
+}
+
+
+/* replace_pop_native_frame ****************************************************
+
+ Unroll a native frame in the execution state and create a source frame
+ for it.
+
+ IN:
+ es...............current execution state
+ ss...............the current source state
+ sfi..............stackframeinfo for the native frame
+
+ OUT:
+ es...............execution state after unrolling the native frame
+ ss...............gets the added native source frame
+
+*******************************************************************************/
+
+static void replace_pop_native_frame(executionstate_t *es,
+ sourcestate_t *ss,
+ stackframeinfo_t *sfi)
+{
+ sourceframe_t *frame;
+ codeinfo *code;
+ s4 i,j;
+
+ assert(sfi);
+
+ frame = replace_new_sourceframe(ss);
+
+ frame->sfi = sfi;
+
+ /* remember pc and size of native frame */
+
+ frame->nativepc = es->pc;
+ frame->nativeframesize = (es->sp != 0) ? (sfi->sp - es->sp) : 0;
+ assert(frame->nativeframesize >= 0);
+
+ /* remember values of saved registers */
+
+ j = 0;
+ for (i=0; i<INT_REG_CNT; ++i) {
+ if (nregdescint[i] == REG_SAV)
+ frame->nativesavint[j++] = es->intregs[i];
+ }
+
+ j = 0;
+ for (i=0; i<FLT_REG_CNT; ++i) {
+ if (nregdescfloat[i] == REG_SAV)
+ frame->nativesavflt[j++] = es->fltregs[i];
+ }
+
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+ j = 0;
+ for (i=0; i<ADR_REG_CNT; ++i) {
+ if (nregdescadr[i] == REG_SAV)
+ frame->nativesavadr[j++] = es->adrregs[i];
+ }
+#endif
+
+ /* restore saved registers */
+
+#if defined(ENABLE_GC_CACAO) && !defined(HAS_ADDRESS_REGISTER_FILE)
+ j = 0;
+ for (i=0; i<INT_REG_CNT; ++i) {
+ if (nregdescint[i] == REG_SAV)
+ es->intregs[i] = sfi->intregs[j++];
+ }
+#else
+ /* XXX we don't have them, yet, in the sfi, so clear them */
+
+ for (i=0; i<INT_REG_CNT; ++i) {
+ if (nregdescint[i] == REG_SAV)
+ es->intregs[i] = 0;
+ }
+#endif
+
+ /* XXX we don't have float registers in the sfi, so clear them */
+
+ for (i=0; i<FLT_REG_CNT; ++i) {
+ if (nregdescfloat[i] == REG_SAV)
+ es->fltregs[i] = 0.0;
+ }
+
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+# if defined(ENABLE_GC_CACAO)
+ j = 0;
+ for (i=0; i<ADR_REG_CNT; ++i) {
+ if (nregdescadr[i] == REG_SAV)
+ es->adrregs[i] = sfi->adrregs[j++];
+ }
+# else
+ for (i=0; i<ADR_REG_CNT; ++i) {
+ if (nregdescadr[i] == REG_SAV)
+ es->adrregs[i] = 0;
+ }
+# endif
+#endif
+
+ /* restore codeinfo of the native stub */
+
+ code = code_get_codeinfo_for_pv(sfi->pv);
+
+ /* restore sp, pv, pc and codeinfo of the parent method */
+
+ /* XXX michi: use this instead:
+ es->sp = sfi->sp + code->stackframesize; */
+ es->sp = sfi->sp + (*(s4 *) (sfi->pv + FrameSize));
+#if defined(REPLACE_RA_BETWEEN_FRAMES)
+ es->sp += SIZE_OF_STACKSLOT; /* skip return address */
+#endif
+ es->pv = md_codegen_get_pv_from_pc(sfi->ra);
+ es->pc = ((sfi->xpc) ? sfi->xpc : sfi->ra) - 1;
+ es->code = code_get_codeinfo_for_pv(es->pv);
+}
+
+
+/* replace_push_native_frame ***************************************************
+
+ Rebuild a native frame onto the execution state and remove its source frame.
+
+ Note: The native frame is "rebuild" by setting fields like PC and stack
+ pointer in the execution state accordingly. Values in the
+ stackframeinfo may be modified, but the actual stack frame of the
+ native code is not touched.
+
+ IN:
+ es...............current execution state
+ ss...............the current source state
+
+ OUT:
+ es...............execution state after re-rolling the native frame
+ ss...............the native source frame is removed
+
+*******************************************************************************/
+
+static void replace_push_native_frame(executionstate_t *es, sourcestate_t *ss)
+{
+ sourceframe_t *frame;
+ s4 i,j;
+
+ assert(es);
+ assert(ss);
+
+ DOLOG( printf("pushing native frame\n"); );
+
+ /* remove the frame from the source state */
+
+ frame = ss->frames;
+ assert(frame);
+ assert(REPLACE_IS_NATIVE_FRAME(frame));
+
+ ss->frames = frame->down;
+
+ /* skip sp for the native stub */
+
+ es->sp -= (*(s4 *) (frame->sfi->pv + FrameSize));
+#if defined(REPLACE_RA_BETWEEN_FRAMES)
+ es->sp -= SIZE_OF_STACKSLOT; /* skip return address */
+#endif
+
+ /* assert that the native frame has not moved */
+
+ assert(es->sp == frame->sfi->sp);
+
+ /* update saved registers in the stackframeinfo */
+
+#if defined(ENABLE_GC_CACAO)
+ j = 0;
+# if !defined(HAS_ADDRESS_REGISTER_FILE)
+ for (i=0; i<INT_REG_CNT; ++i) {
+ if (nregdescint[i] == REG_SAV)
+ frame->sfi->intregs[j++] = es->intregs[i];
+ }
+# else
+ for (i=0; i<ADR_REG_CNT; ++i) {
+ if (nregdescadr[i] == REG_SAV)
+ frame->sfi->adrregs[j++] = es->adrregs[i];
+ }
+# endif
+
+ /* XXX leave float registers untouched here */
+#endif
+
+ /* restore saved registers */
+
+ j = 0;
+ for (i=0; i<INT_REG_CNT; ++i) {
+ if (nregdescint[i] == REG_SAV)
+ es->intregs[i] = frame->nativesavint[j++];
+ }
+
+ j = 0;
+ for (i=0; i<FLT_REG_CNT; ++i) {
+ if (nregdescfloat[i] == REG_SAV)
+ es->fltregs[i] = frame->nativesavflt[j++];
+ }
+
+#if defined(HAS_ADDRESS_REGISTER_FILE)
+ j = 0;
+ for (i=0; i<ADR_REG_CNT; ++i) {
+ if (nregdescadr[i] == REG_SAV)
+ es->adrregs[i] = frame->nativesavadr[j++];
+ }
+#endif
+
+ /* skip the native frame on the machine stack */
+
+ es->sp -= frame->nativeframesize;
+
+ /* set the pc the next frame must return to */
+
+ es->pc = frame->nativepc;
+}
+
+
+/* replace_recover_source_state ************************************************
+
+ Recover the source state from the given replacement point and execution
+ state.
+
+ IN:
+ rp...............replacement point that has been reached, if any
+ sfi..............stackframeinfo, if called from native code
+ es...............execution state at the replacement point rp
+
+ RETURN VALUE:
+ the source state
+
+*******************************************************************************/
+
+sourcestate_t *replace_recover_source_state(rplpoint *rp,
+ stackframeinfo_t *sfi,
+ executionstate_t *es)
+{
+ sourcestate_t *ss;
+ u1 *ra;
+ bool locked;
+#if defined(REPLACE_STATISTICS)
+ s4 depth;
+#endif
+
+ /* create the source frame structure in dump memory */
+
+ ss = DNEW(sourcestate_t);
+ ss->frames = NULL;
+
+ /* each iteration of the loop recovers one source frame */
+
+ depth = 0;
+ locked = false;
+
+ while (rp || sfi) {
+
+ DOLOG( replace_executionstate_println(es); );
+
+ /* if we are not at a replacement point, it is a native frame */
+
+ if (rp == NULL) {
+ DOLOG( printf("native frame: sfi: "); replace_stackframeinfo_println(sfi); );
+
+ locked = true;
+ replace_pop_native_frame(es, ss, sfi);
+ sfi = sfi->prev;
+
+ if (es->code == NULL)
+ continue;
+
+ goto after_machine_frame;
+ }
+
+ /* read the values for this source frame from the execution state */
+
+ DOLOG( printf("recovering source state for%s:\n",
+ (ss->frames == NULL) ? " TOPFRAME" : "");
+ replace_replacement_point_println(rp, 1); );
+
+ replace_read_executionstate(rp, es, ss, ss->frames == NULL);
+
+#if defined(ENABLE_VMLOG)
+ vmlog_cacao_unrol_method(ss->frames->method);
+#endif
+
+#if defined(REPLACE_STATISTICS)
+ REPLACE_COUNT(stat_frames);
+ depth++;
+ replace_statistics_source_frame(ss->frames);
+#endif
+
+ /* in locked areas (below native frames), identity map the frame */
+
+ if (locked) {
+ ss->frames->torp = ss->frames->fromrp;
+ ss->frames->tocode = ss->frames->fromcode;
+ }
+
+ /* unroll to the next (outer) frame */
+
+ if (rp->parent) {
+ /* this frame is in inlined code */
+
+ DOLOG( printf("INLINED!\n"); );
+
+ rp = rp->parent;
+
+ assert(rp->type == RPLPOINT_TYPE_INLINE);
+ REPLACE_COUNT(stat_unroll_inline);
+ }
+ else {
+ /* this frame had been called at machine-level. pop it. */
+
+ DOLOG( printf("UNWIND\n"); );
+
+ ra = replace_pop_activation_record(es, ss->frames);
+ if (ra == NULL) {
+ DOLOG( printf("REACHED NATIVE CODE\n"); );
+
+ rp = NULL;
+
+#if !defined(ENABLE_GC_CACAO)
+ break; /* XXX remove to activate native frames */
+#endif
+ continue;
+ }
+
+ /* find the replacement point at the call site */
+
+after_machine_frame:
+ rp = replace_find_replacement_point_for_pc(es->code, es->pc);
+
+ if (rp == NULL)
+ vm_abort("could not find replacement point while unrolling call");
+
+ DOLOG( printf("found replacement point.\n");
+ replace_replacement_point_println(rp, 1); );
+
+ assert(rp->type == RPLPOINT_TYPE_CALL);
+ REPLACE_COUNT(stat_unroll_call);
+ }
+ } /* end loop over source frames */
+
+ REPLACE_COUNT_DIST(stat_dist_frames, depth);
+
+ return ss;
+}
+
+
+/* replace_map_source_state ****************************************************
+
+ Map each source frame in the given source state to a target replacement
+ point and compilation unit. If no valid code is available for a source
+ frame, it is (re)compiled.
+
+ IN:
+ ss...............the source state
+
+ OUT:
+ ss...............the source state, modified: The `torp` and `tocode`
+ fields of each source frame are set.
+
+ RETURN VALUE:
+ true.............everything went ok
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+static bool replace_map_source_state(sourcestate_t *ss)
+{
+ sourceframe_t *frame;
+ codeinfo *code;
+ rplpoint *rp;
+ rplpoint *parent; /* parent of inlined rplpoint */
+#if defined(REPLACE_STATISTICS)
+ codeinfo *oldcode;
+#endif
+
+ parent = NULL;
+ code = NULL;
+
+ /* iterate over the source frames from outermost to innermost */
+
+ for (frame = ss->frames; frame != NULL; frame = frame->down) {
+
+ /* XXX skip native frames */
+
+ if (REPLACE_IS_NATIVE_FRAME(frame)) {
+ parent = NULL;
+ continue;
+ }
+
+ /* map frames which are not already mapped */
+
+ if (frame->tocode) {
+ code = frame->tocode;
+ rp = frame->torp;
+ assert(rp);
+ }
+ else {
+ assert(frame->torp == NULL);
+
+ if (parent == NULL) {
+ /* find code for this frame */
+
+#if defined(REPLACE_STATISTICS)
+ oldcode = frame->method->code;
+#endif
+ /* request optimization of hot methods and their callers */
+
+ if (frame->method->hitcountdown < 0
+ || (frame->down && frame->down->method->hitcountdown < 0))
+ jit_request_optimization(frame->method);
+
+ code = jit_get_current_code(frame->method);
+
+ if (code == NULL)
+ return false; /* exception */
+
+ REPLACE_COUNT_IF(stat_recompile, code != oldcode);
+ }
+
+ assert(code);
+
+ /* map this frame */
+
+ rp = replace_find_replacement_point(code, frame, parent);
+
+ frame->tocode = code;
+ frame->torp = rp;
+ }
+
+ if (rp->type == RPLPOINT_TYPE_CALL) {
+ parent = NULL;
+ }
+ else {
+ /* inlining */
+ parent = rp;
+ }
+ }
+
+ return true;
+}
+
+
+/* replace_map_source_state_identity *******************************************
+
+ Map each source frame in the given source state to the same replacement
+ point and compilation unit it was derived from. This is mainly used for
+ garbage collection.
+
+ IN:
+ ss...............the source state
+
+ OUT:
+ ss...............the source state, modified: The `torp` and `tocode`
+ fields of each source frame are set.
+
+*******************************************************************************/
+
+#if defined(ENABLE_GC_CACAO)
+static void replace_map_source_state_identity(sourcestate_t *ss)
+{
+ sourceframe_t *frame;
+
+ /* iterate over the source frames from outermost to innermost */
+
+ for (frame = ss->frames; frame != NULL; frame = frame->down) {
+
+ /* skip native frames */
+
+ if (REPLACE_IS_NATIVE_FRAME(frame)) {
+ continue;
+ }
+
+ /* map frames using the identity mapping */
+
+ if (frame->tocode) {
+ assert(frame->tocode == frame->fromcode);
+ assert(frame->torp == frame->fromrp);
+ } else {
+ assert(frame->tocode == NULL);
+ assert(frame->torp == NULL);
+ frame->tocode = frame->fromcode;
+ frame->torp = frame->fromrp;
+ }
+ }
+}
+#endif
+
+
+/* replace_build_execution_state ***********************************************
+
+ Build an execution state for the given (mapped) source state.
+
+ !!! CAUTION: This function rewrites the machine stack !!!
+
+ THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!
+
+ IN:
+ ss...............the source state. Must have been mapped by
+ replace_map_source_state before.
+ es...............the base execution state on which to build
+
+ OUT:
+ *es..............the new execution state
+
+*******************************************************************************/
+
+static void replace_build_execution_state(sourcestate_t *ss,
+ executionstate_t *es)
+{
+ rplpoint *rp;
+ sourceframe_t *prevframe;
+ rplpoint *parent;
+
+ parent = NULL;
+ prevframe = NULL;
+ rp = NULL;
+
+ while (ss->frames) {
+
+ if (REPLACE_IS_NATIVE_FRAME(ss->frames)) {
+ prevframe = ss->frames;
+ replace_push_native_frame(es, ss);
+ parent = NULL;
+ rp = NULL;
+ continue;
+ }
+
+ if (parent == NULL) {
+ /* create a machine-level stack frame */
+
+ DOLOG( printf("pushing activation record for:\n");
+ if (rp) replace_replacement_point_println(rp, 1);
+ else printf("\tfirst frame\n"); );
+
+ replace_push_activation_record(es, rp, prevframe, ss->frames);
+
+ DOLOG( replace_executionstate_println(es); );
+ }
+
+ rp = ss->frames->torp;
+ assert(rp);
+
+ DOLOG( printf("creating execution state for%s:\n",
+ (ss->frames->down == NULL) ? " TOPFRAME" : "");
+ replace_replacement_point_println(ss->frames->fromrp, 1);
+ replace_replacement_point_println(rp, 1); );
+
+ es->code = ss->frames->tocode;
+ prevframe = ss->frames;
+
+#if defined(ENABLE_VMLOG)
+ vmlog_cacao_rerol_method(ss->frames->method);
+#endif
+
+ replace_write_executionstate(rp, es, ss, ss->frames->down == NULL);
+
+ DOLOG( replace_executionstate_println(es); );
+
+ if (rp->type == RPLPOINT_TYPE_CALL) {
+ parent = NULL;
+ }
+ else {
+ /* inlining */
+ parent = rp;
+ }
+ }
+}
+
+
+/* replace_me ******************************************************************
+
+ This function is called by the signal handler when a thread reaches
+ a replacement point. `replace_me` must map the execution state to the
+ target replacement point and let execution continue there.
+
+ THIS FUNCTION MUST BE CALLED USING A SAFE STACK AREA!