📄 machine.c
字号:
getInsnPC(int pc, codeinfo* codeInfo, nativeCodeInfo *code){ int res; int maxPc = codeInfo->codelen; for (;pc<maxPc;pc++) { res = INSNPC(pc); if (res != -1) { return (res); } } return code->codelen;}/* * Install the compiled code in the method. * Returns true if successful */voidinstallMethodCode(void* ignore, Method* meth, nativeCodeInfo* code){ uint32 i; jexceptionEntry* e; void *tramp;#if defined(KAFFE_XPROFILER) || defined(KAFFE_XDEBUGGING) struct mangled_method *mm = 0;#endif#if defined(KAFFE_FEEDBACK) char *sym = 0;#endif /* Work out new estimate of code per bytecode */ code_generated += code->memlen; bytecode_processed += METHOD_BYTECODE_LEN(meth); /* When using GCJ, the only use for the translator may be to output * JNI wrappers which have zero bytecode ;-); hence the test */ if (bytecode_processed > 0) { codeperbytecode = code_generated / bytecode_processed; } //GC_WRITE(meth, code->mem); tramp = METHOD_NATIVECODE(meth); SET_METHOD_JITCODE(meth, code->code); if( meth->c.bcode.code ) gc_free(meth->c.bcode.code); meth->c.ncode.ncode_start = code->mem; meth->c.ncode.ncode_end = (void*)((uintp)code->code + code->codelen); #if defined(KAFFE_FEEDBACK) if( kaffe_feedback_file && !meth->class->loader ) { sym = gc_malloc(strlen(CLASS_CNAME(meth->class)) + 1 + /* '/' */ strlen(meth->name->data) + strlen(METHOD_SIGD(meth)) + 1, GC_ALLOC_JITTEMP); sprintf(sym, "%s/%s%s", CLASS_CNAME(meth->class), meth->name->data, METHOD_SIGD(meth)); feedbackJITMethod(sym, code->code, code->codelen, true); gc_free(sym); }#endif#if defined(KAFFE_XPROFILER) || defined(KAFFE_XDEBUGGING) if( (#if defined(KAFFE_XPROFILER) xProfFlag ||#else 0 ||#endif#if defined(KAFFE_XDEBUGGING) machine_debug_file#else 0#endif ) && (mm = createMangledMethod()) ) { mangleMethod(mm, meth); }#endif#if defined(KAFFE_XPROFILER) profileFunction(mm, code->code, code->codelen);#endif /* Flush code out of cache */#if defined(FLUSH_DCACHE) FLUSH_DCACHE(code->code, (void*)((uintp)code->code + code->codelen));#endif gc_free(tramp); /* Translate exception table and make it available */ if (meth->exception_table != 0) { for (i = 0; i < meth->exception_table->length; i++) { e = &meth->exception_table->entry[i]; e->start_pc = getInsnPC(e->start_pc, codeInfo, code) + (uintp)code->code; e->end_pc = getInsnPC(e->end_pc, codeInfo, code) + (uintp)code->code; e->handler_pc = getInsnPC(e->handler_pc, codeInfo, code) + (uintp)code->code; if (e->start_pc >= e->end_pc) fprintf(stderr, "WARNING Bad bytecode! Illegal exception table entry:" " start_pc=%d is not lower than end_pc=%d in method %s.%s(%s)\n" "See Java Virtual Machine Specification 2nd Edition $4.7.3 for details.\n" "Please report this bug to the developers of the application you're running on kaffe.\n" "A simple fix might be to use another java compiler to build the application.\n", e->start_pc, e->end_pc, CLASS_CNAME(meth->class), meth->name->data, METHOD_SIGD(meth)); } } /* Translate line numbers table */ if (meth->lines != 0) {#if defined(KAFFE_XDEBUGGING) struct debug_file *df = machine_debug_file; if( df ) { /* Mark the start of this source file */ addDebugInfo(df, DIA_SourceFile, meth->class->sourcefile, code->code, DIA_Function, meth, mm, meth->lines->entry[0].line_nr, code->code, code->codelen, DIA_DONE); }#endif for (i = 0; i < meth->lines->length; i++) { meth->lines->entry[i].start_pc = getInsnPC(meth->lines->entry[i].start_pc, codeInfo, code) + (uintp)code->code;#if defined(KAFFE_XDEBUGGING) if( df ) { /* Add line debugging */ addDebugInfo(df, DIA_SourceLine, meth->lines->entry[i].line_nr, meth->lines->entry[i].start_pc - (uintp)code->code, DIA_DONE); }#endif }#if defined(KAFFE_XDEBUGGING) if( df ) { /* * Mark the end of the function. This needs to be here * so that gdb doesn't get confused about the range of * the function since that will be determined by the * next debugging information that is added. */ addDebugInfo(df, DIA_EndFunction, code->code + code->codelen, DIA_DONE); }#endif } else {#if defined(KAFFE_XDEBUGGING) /* * No line debugging, but we'd like a symbol to show up anyways */ if( machine_debug_file ) { addDebugInfo(machine_debug_file, DIA_SourceFile, meth->class->sourcefile, code->code, DIA_Function, meth, mm, 0, code->code, code->codelen, DIA_EndFunction, code->code + code->codelen, DIA_DONE); }#endif }#if defined(KAFFE_XPROFILER) || defined(KAFFE_XDEBUGGING) deleteMangledMethod(mm);#endif /* record framesize for gcj unwinding information */#if defined(LABEL_Lframe) LABEL_Lframe(&meth->framesize, /* unused */ 0, /* unused */ 0);#endif}/* * Init instruction generation. */jbooleaninitInsnSequence(Method* meth, int codesize, int localsz, int stacksz, errorInfo* einfo){ /* Clear various counters */ tmpslot = 0; maxTemp = 0; maxPush = 0; stackno = localsz + stacksz; npc = 0; /* Do any machine dependent JIT initialization */#if defined(INIT_JIT_MD) INIT_JIT_MD(meth);#endif initSeq(); initRegisters(); initSlots(stackno); /* Before generating code, try to guess how much space we'll need. */ codeblock_size = ALLOCCODEBLOCKSZ; codeblock = gc_malloc(codeblock_size + CODEBLOCKREDZONE, GC_ALLOC_JIT_CODEBLOCK); if (codeblock == 0) { postOutOfMemory(einfo); return (false); } CODEPC = 0; /* * add the method as the first entry to the constant pool to speed up * finding a method for a given pc. */ newConstant(CPref, meth); return (true);}/* * Generate instructions from current set of sequences. */staticjbooleangenerateInsnSequence(errorInfo* einfo){ sequence* t; int i; int m; for (t = firstSeq; t != currSeq; t = t->next) { /* If we overrun the codeblock, reallocate and continue. */ if (CODEPC >= codeblock_size) { nativecode *new_codeblock; codeblock_size += ALLOCCODEBLOCKSZ; new_codeblock = gc_realloc(codeblock, codeblock_size + CODEBLOCKREDZONE, GC_ALLOC_JIT_CODEBLOCK); if (new_codeblock == NULL) { gc_free(codeblock); codeblock = NULL; postOutOfMemory(einfo); return (false); } else { codeblock = new_codeblock; } }SCHK( sanityCheck(); ); /* Generate sequences */ assert(t->func != 0); if (t->refed != 0) { (*(t->func))(t); } else { /* printf("discard instruction\n"); */ } /* Handle dead slots */ m = t->lastuse; if (m != 0) { for (i = 0; m != 0; m = m >> 1, i++) { if ((m & 1) != 0) { assert(!isGlobal(t->u[i].slot)); slot_kill_readonce(t->u[i].slot); /* * If this sequence is in an exception * handler we need to spill the slot * in case its used in a subsequent * basic block. */ if( t->jflags.ANY ) { spillAndUpdate(t->u[i].slot, true); } slot_invalidate(t->u[i].slot); } } } } /* Reset */ initSeq(); return (true);}/* * check what synchronous exceptions are caught for a given instruction */staticvoid checkCaughtExceptions(Method* meth, uint32 pc){ unsigned int i; willcatch.ANY = false; willcatch.BADARRAYINDEX = false; willcatch.NULLPOINTER = false; if (meth->exception_table == 0) return; /* Determine various exception conditions */ for (i = 0; i < meth->exception_table->length; i++) { Hjava_lang_Class* etype; /* include only if exception handler range matches pc */ if (meth->exception_table->entry[i].start_pc > pc || meth->exception_table->entry[i].end_pc <= pc) continue; willCatch(ANY); etype = meth->exception_table->entry[i].catch_type; if (etype == 0) { willCatch(BADARRAYINDEX); willCatch(NULLPOINTER); } else { if (instanceof(javaLangArrayIndexOutOfBoundsException, etype)) { willCatch(BADARRAYINDEX); } if (instanceof(javaLangNullPointerException, etype)) { willCatch(NULLPOINTER); } } }}/* * Start a new instruction. */voidstartInsn(sequence* s){ SET_INSNPC(const_int(2), CODEPC);}voiddoSpill(sequence* s){ SlotData** mem; SlotData* sd; int type; int old_ro;SCHK( sanityCheck(); ) type = s->u[2].value.i; old_ro = enable_readonce; if (type == SR_SYNC) { enable_readonce = 0; } /* Spill the registers */ for (mem = s->u[1].smask; *mem != 0; mem++) { sd = *mem; /* Determine if we need to spill this slot at all */ if ((sd->modified & rwrite) != 0 && sd->regno != NOREG) { switch (type) { case SR_BASIC: case SR_SUBBASIC: /* We only spill if it's not global */ if (!isGlobal(sd)) { spillAndUpdate(sd, true); } break; case SR_SYNC: spillAndUpdate(sd, false); break; case SR_FUNCTION: if (calleeSave(sd->regno) == 0 || s->jflags.ANY != 0) { spillAndUpdate(sd, true); } break; default: ABORT(); } } } /* If this isn't being done for a function call we can free the * spill mask now. Otherwise it will be freed by the function * reloader. */ if (type != SR_FUNCTION) { gc_free(s->u[1].smask); } enable_readonce = old_ro;SCHK( sanityCheck(); )}voiddoReload(sequence* s){ SlotData* sd; SlotData** mem; int type;SCHK( sanityCheck(); ) type = s->u[2].value.i; for (mem = s->u[1].smask; *mem != 0; mem++) { sd = *mem; if (sd->regno != NOREG && !isGlobal(sd)) { switch (type) { case SR_BASIC: case SR_SUBBASIC: slot_invalidate(sd); break; case SR_FUNCTION: if (calleeSave(sd->regno) == 0) { slot_invalidate(sd); } break; case SR_START: case SR_EXCEPTION: break; default: ABORT(); } } } /* Deal with global reloading */ for (mem = s->u[1].smask; *mem != 0; mem++) { sd = *mem; if (isGlobal(sd)) { switch (type) { case SR_BASIC: case SR_SUBBASIC: if (!isGlobalReadonly(sd)) { sd->modified = rwrite; } break; case SR_FUNCTION: break; case SR_START: if (isGlobalPreload(sd)) { reload(sd); } break; case SR_EXCEPTION: reload(sd); break; default: ABORT(); } } } gc_free(s->u[1].smask);SCHK( sanityCheck(); )}/* * Create the spill/reload mask. * This contains a list of slot/global pairs indicating which slots are * active and should be spilled or reloaded now. The global flag indicates * that at this point the slot is global (ie. carried between basic blocks) * so should be handled with care. */SlotData**createSpillMask(void)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -