📄 machine.c
字号:
/* machine.c * Translate the Kaffe instruction set to the native one. * * Copyright (c) 1996-1999 * Transvirtual Technologies, Inc. All rights reserved. * * Cross-language profiling changes contributed by * the Flux Research Group, Department of Computer Science, * University of Utah, http://www.cs.utah.edu/flux/ * * See the file "license.terms" for information on usage and redistribution * of this file. */#define SCHK(s) s#define SUSE(s)#include "config.h"#include "config-std.h"#include "config-mem.h"#include "gtypes.h"#include "md.h"#include "classMethod.h"#include "bytecode.h"#include "slots.h"#include "registers.h"#include "seq.h"#include "gc.h"#include "machine.h"#include "basecode.h"#include "icode.h"#include "labels.h"#include "constpool.h"#include "codeproto.h"#include "checks.h"#include "access.h"#include "object.h"#include "constants.h"#include "baseClasses.h"#include "code.h"#include "access.h"#include "lookup.h"#include "exception.h"#include "errors.h"#include "locks.h"#include "code-analyse.h"#include "external.h"#include "soft.h"#include "thread.h"#include "itypes.h"#include "methodCache.h"#include "support.h"#include "xprofiler.h"#include "feedback.h"#include "debugFile.h"#include "fileSections.h"#include "mangle.h"char* engine_name = "Just-in-time v3";char* engine_version = KAFFEVERSION;int stackno;int maxStack;int maxLocal;int maxTemp;int maxArgs;int maxPush;int isStatic;codeinfo* codeInfo;int tmpslot;int argcount = 0; /* Function call argument count */uint32 pc;uint32 npc;/* Various exception related things */jitflags willcatch;/* jit3 specific prototypes from icode.c */void explicit_check_null (int x, SlotInfo* obj, int y);void check_null (int x, SlotInfo* obj, int y);void check_div (int x, SlotInfo* obj, int y);void check_div_long (int x, SlotInfo* obj, int y);void softcall_fakecall (label* from,label* to, void* func);/* Unit in which code block is increased when overrun */#define ALLOCCODEBLOCKSZ 8192/* Codeblock redzone - allows for safe overrun when generating instructions */#define CODEBLOCKREDZONE 256int codeblock_size;static int code_generated;static int bytecode_processed;static int codeperbytecode;iLock *translatorlock;struct { int time;} jitStats;static jboolean generateInsnSequence(errorInfo*);static void nullCall(void);static void makeFakeCalls(void);/* Desktop edition */#include "debug.h"#if defined(KAFFE_PROFILER)int profFlag;Method *globalMethod;static void printProfilerStats(void);#endif/* * Translate a method into native code. */jbooleantranslate(Method* xmeth, errorInfo* einfo){ int i; jint low; jint high; jvalue tmpl; int idx; SlotInfo* tmp; SlotInfo* tmp2; SlotInfo* mtable; bytecode* base; uint32 len; callInfo cinfo; fieldInfo finfo; Hjava_lang_Class* crinfo; codeinfo* mycodeInfo; nativeCodeInfo ncode; int64 tms = 0; int64 tme; static bool reinvoke = false; jboolean success = true; int iLockRoot; lockMutex(xmeth->class->centry); if (METHOD_TRANSLATED(xmeth)) { goto done3; } /* If this code block is native, then just set it up and return */ if ((xmeth->accflags & ACC_NATIVE) != 0) { success = native(xmeth, einfo); if (success == true) { KAFFEJIT_TO_NATIVE(xmeth); } goto done3; } /* Scan the code and determine the basic blocks */ success = verifyMethod(xmeth, &mycodeInfo, einfo); if (success == false) { goto done3; }#if defined(KAFFE_FEEDBACK) if( kaffe_feedback_file ) lockMutex(kaffe_feedback_file);#endif /* Only one in the translator at once. Must check the translation * hasn't been done by someone else once we get it. */ enterTranslator(); if (Kaffe_JavaVMArgs[0].enableVerboseJIT) { tms = currentTime(); }DBG(MOREJIT, dprintf("callinfo = %p\n", &cinfo); )#if defined(KAFFE_PROFILER) if (profFlag) { static int init = 0; if (!init) { atexit(printProfilerStats); init = 1; } profiler_get_clicks(xmeth->jitClicks); xmeth->callsCount = 0; xmeth->totalClicks = 0; xmeth->totalChildrenClicks = 0; globalMethod = xmeth; }#endif codeInfo = mycodeInfo; /* Handle null calls specially */ if (METHOD_BYTECODE_LEN(xmeth) == 1 && METHOD_BYTECODE_CODE(xmeth)[0] == RETURN) { /* 'nc' is a Workaround for KFREE ? : bug in gcc 2.7.2 */ void *nc = METHOD_NATIVECODE(xmeth); KFREE(nc); SET_METHOD_NATIVECODE(xmeth, (nativecode*)nullCall); goto done; } assert(reinvoke == false); reinvoke = true; maxLocal = xmeth->localsz; maxStack = xmeth->stacksz; maxArgs = sizeofSigMethod(xmeth, false); if (maxArgs == -1) { goto done; } if (xmeth->accflags & ACC_STATIC) { isStatic = 1; } else { isStatic = 0; maxArgs += 1; }DBG(MOREJIT, dprintf("Method: %s.%s%s\n", CLASS_CNAME(xmeth->class), xmeth->name->data, METHOD_SIGD(xmeth)); for (i = 0; i < maxLocal; i++) { dprintf(" L%d: %2d", i, codeInfo->localuse[i].use); } dprintf("\n");) base = (bytecode*)METHOD_BYTECODE_CODE(xmeth); len = METHOD_BYTECODE_LEN(xmeth); willcatch.ANY = false; willcatch.BADARRAYINDEX = false; /* Deterimine various exception conditions */ if (xmeth->exception_table != 0) { willCatch(ANY); for (i = 0; i < (int)xmeth->exception_table->length; i++) { Hjava_lang_Class* etype; etype = xmeth->exception_table->entry[i].catch_type; if (etype == 0) { willCatch(BADARRAYINDEX); } else { if (instanceof(javaLangArrayIndexOutOfBoundsException, etype)) { willCatch(BADARRAYINDEX); } } } } /* * Initialise the translator. */ success = initInsnSequence(xmeth, codeperbytecode * METHOD_BYTECODE_LEN(xmeth), xmeth->localsz, xmeth->stacksz, einfo); if (success == false) { goto done; } /***************************************/ /* Next reduce bytecode to native code */ /***************************************/ pc = 0; start_function(); check_stack_limit(); if (Kaffe_JavaVMArgs[0].enableVerboseCall != 0) { softcall_trace(xmeth); } monitor_enter(); if (IS_STARTOFBASICBLOCK(0)) { end_basic_block(); success = generateInsnSequence(einfo); if (success == false) { goto done; } start_basic_block(); } for (; pc < len; pc = npc) { assert(stackno <= maxStack+maxLocal); assert(stackno >= 0); npc = pc + insnLen[base[pc]]; /* Skip over the generation of any unreachable basic blocks */ if (IS_UNREACHABLE(pc)) { while (npc < len && !IS_STARTOFBASICBLOCK(npc) && !IS_STARTOFEXCEPTION(npc)) { npc = npc + insnLen[base[npc]]; }DBG(JIT, dprintf("unreachable basic block pc [%d:%d]\n", pc, npc - 1); ) if (IS_STARTOFBASICBLOCK(npc)) { end_basic_block(); start_basic_block(); stackno = STACKPOINTER(npc); } continue; } start_instruction(); /* Note start of exception handling blocks */ if (IS_STARTOFEXCEPTION(pc)) { stackno = xmeth->localsz + xmeth->stacksz - 1; start_exception_block(); } switch (base[pc]) { default: printf("Unknown bytecode %d\n", base[pc]); leaveTranslator();#if defined(KAFFE_FEEDBACK) if( kaffe_feedback_file ) unlockMutex(kaffe_feedback_file);#endif unlockMutex(xmeth->class->centry); postException(einfo, JAVA_LANG(VerifyError)); success = false; break;#include "kaffe.def" } /* Note maximum number of temp slots used and reset it */ if (tmpslot > maxTemp) { maxTemp = tmpslot; } tmpslot = 0;SCHK( sanityCheck(); ) if (IS_STARTOFBASICBLOCK(npc)) { end_basic_block(); success = generateInsnSequence(einfo); if (success == false) { goto done; } start_basic_block(); stackno = STACKPOINTER(npc);SCHK( sanityCheck(); ) } } end_function(); makeFakeCalls(); assert(maxTemp < MAXTEMPS); finishInsnSequence(0, &ncode, einfo); installMethodCode(0, xmeth, &ncode);done:; tidyVerifyMethod(&codeInfo); reinvoke = false;#if defined(KAFFE_PROFILER) if (profFlag) { profiler_click_t end; profiler_get_clicks(end); xmeth->jitClicks = end - xmeth->jitClicks; globalMethod = 0; }#endifDBG(MOREJIT, dprintf("Translating %s.%s%s (%s) %p\n", xmeth->class->name->data, xmeth->name->data, METHOD_SIGD(xmeth), isStatic ? "static" : "normal", METHOD_NATIVECODE(xmeth)); ) if (Kaffe_JavaVMArgs[0].enableVerboseJIT) { tme = currentTime(); jitStats.time += (int)(tme - tms); printf("<JIT: %s.%s%s time %dms (%dms) @ %p (%p)>\n", CLASS_CNAME(xmeth->class), xmeth->name->data, METHOD_SIGD(xmeth), (int)(tme - tms), jitStats.time, METHOD_NATIVECODE(xmeth), xmeth); } leaveTranslator();#if defined(KAFFE_FEEDBACK) if( kaffe_feedback_file ) unlockMutex(kaffe_feedback_file);#endifdone3:; unlockMutex(xmeth->class->centry); return (success);}/* * Generate the code. */jbooleanfinishInsnSequence(void* dummy, nativeCodeInfo* code, errorInfo* einfo){ uint32 constlen; nativecode* methblock; nativecode* codebase; jboolean success; /* Emit pending instructions */ success = generateInsnSequence(einfo); if (success == false) { return (false); } /* Okay, put this into malloc'ed memory */ constlen = nConst * sizeof(union _constpoolval); methblock = gc_malloc(constlen + CODEPC, GC_ALLOC_JITCODE); if (methblock == 0) { postOutOfMemory(einfo); return (false); } codebase = methblock + constlen; memcpy(codebase, codeblock, CODEPC); gc_free(codeblock); /* Establish any code constants */ establishConstants(methblock); /* Link it */ linkLabels((uintp)codebase); /* Note info on the compiled code for later installation */ code->mem = methblock; code->memlen = constlen + CODEPC; code->code = codebase; code->codelen = CODEPC; return (true);}/* * Get the instruction offset corresponding to the given PC. * If the PC doesn't point at the start of a valid instruction, * look forward until we find one. */staticintgetInsnPC(int pc){ int res; for (;;) { res = INSNPC(pc); if (res != -1) { return (res); } pc++; }}/* * Install the compiled code in the method. * Returns true if successful */voidinstallMethodCode(void* ignore, Method* meth, nativeCodeInfo* code){ uint32 i; bool res; jexceptionEntry* e;#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); { /* Workaround for KFREE() ? : bug on gcc 2.7.2 */ void *nc = METHOD_NATIVECODE(meth); KFREE(nc); } 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 = KMALLOC(strlen(CLASS_CNAME(meth->class)) + 1 + /* '/' */ strlen(meth->name->data) + strlen(METHOD_SIGD(meth)) + 1); sprintf(sym, "%s/%s%s", CLASS_CNAME(meth->class), meth->name->data, METHOD_SIGD(meth)); feedbackJITMethod(sym, code->code, code->codelen, true); KFREE(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 /* 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) + (uintp)code->code; e->end_pc = getInsnPC(e->end_pc) + (uintp)code->code; e->handler_pc = getInsnPC(e->handler_pc) + (uintp)code->code; } } /* 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) + (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 res = makeMethodActive(meth); assert(res == true); /* 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); resetLabels(); /* Before generating code, try to guess how much space we'll need. */ codeblock_size = codesize;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -