📄 machine.c
字号:
/* machine.c * Translate the Kaffe instruction set to the native one. * * Copyright (c) 1996, 1997 * Transvirtual Technologies, Inc. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. */#include "config.h"#include "debug.h"#include "config-std.h"#include "config-mem.h"#include "classMethod.h"#include "gtypes.h"#include "kaffe/jmalloc.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 "icode_internal.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 "md.h"#include "locks.h"#include "code-analyse.h"#include "external.h"#include "soft.h"#include "stringSupport.h"#include "jni.h"#include "thread.h"#include "jthread.h"#include "stats.h"#include "support.h"#include "native-wrapper.h"#include "jvmpi_kaffe.h"/* * Define information about this engine. */char* engine_name = "Just-in-time";iStaticLock translatorlock; /* lock to protect the variables below */int stackno;int maxStack;int maxLocal;int maxTemp;int maxArgs;int maxPush;int isStatic;int tmpslot;int argcount = 0; /* Function call argument count */uint32 pc;uint32 npc;jitflags willcatch;#define EXPLICIT_CHECK_NULL(_i, _s, _n) \ cbranch_ref_const_ne((_s), NULL, reference_label(_i, _n)); \ softcall_nullpointer(); \ set_label(_i, _n)/* Define CREATE_NULLPOINTER_CHECKS in md.h when your machine cannot use the * MMU for detecting null pointer accesses */#if defined(CREATE_NULLPOINTER_CHECKS)#define CHECK_NULL(_i, _s, _n) \ EXPLICIT_CHECK_NULL(_i, _s, _n)#else/* * If we rely on the MMU to catch null pointer accesses, we must spill * the registers to their home locations if that exception can be caught, * since the exception handler will load its registers from there. * For now, we use prepare_function_call() to do that. (Tim?) */#define CHECK_NULL(_i, _s, _n) \ if (canCatch(NULLPOINTER)) { \ prepare_function_call(); \ }#endif/* For JIT3 compatibility */#define check_array_store(a,b) softcall_checkarraystore(a,b)#define explicit_check_null(x,obj,y) EXPLICIT_CHECK_NULL(x,obj,y)#define check_null(x,obj,y) CHECK_NULL(x,obj,y)#define check_div(x,obj,y)#define check_div_long(x,obj,y)/* Unit in which code block is increased when overrun */#define ALLOCCODEBLOCKSZ 8192/* Codeblock redzone - allows for safe overrun when generating instructions */#define CODEBLOCKREDZONE 256nativecode* codeblock;int codeblock_size;static int code_generated;static int bytecode_processed;static int codeperbytecode;int CODEPC;Method *globalMethod;#if defined(KAFFE_PROFILER)int profFlag; /* flag to control profiling */static void printProfilerStats(void);#endifstruct { int time;} jitStats;static void generateInsnSequence(codeinfo* codeInfo);static void checkCaughtExceptions(Method* meth, unsigned int pc);void endBlock(sequence*);void startBlock(sequence*);void endSubBlock(sequence*);void startSubBlock(sequence*);void cancelNoWriteback(void);jlong currentTime(void);static JTHREAD_JMPBUF JIT_jumpExitWithOOM;void KaffeJIT_exitWithOOM(){ JTHREAD_LONGJMP(JIT_jumpExitWithOOM, 1);}bool KaffeJIT_setupExitWithOOM(struct _errorInfo* einfo){ if (!JTHREAD_SETJMP(JIT_jumpExitWithOOM)) return false; postOutOfMemory(einfo); return true;}/* * By default, we comply with the Java spec and turn stack overflow checks * on. Note that this involves a noticeable performance penalty. If you * feel adventurous, undef this. */#define CHECK_STACKOVERFLOW#if defined(CHECK_STACKOVERFLOW)static void checkStackOverflow(void){ /* XXX fix this. * We should not have to access current just to do the stack check */ threadData *thread_data = KTHREAD(get_data)(KTHREAD(current)()); if (KTHREAD(stackcheck)(thread_data->needOnStack)) { return; } if (thread_data->needOnStack == STACK_LOW) { dprintf( "Panic: unhandled StackOverflowError()\n"); KAFFEVM_ABORT(); } { Hjava_lang_Throwable *th; errorInfo einfo; thread_data->needOnStack = STACK_LOW; th = (Hjava_lang_Throwable *)newObjectChecked (javaLangStackOverflowError, &einfo); thread_data->needOnStack = STACK_HIGH; throwException(th); }}#endif /* CHECK_STACKOVERFLOW *//* * Translate a method into native code. * * Return true if successful, false otherwise. */booltranslate(Method* meth, errorInfo *einfo){ jint low; jint high; jvalue tmpl; int idx; SlotInfo* tmp; SlotInfo* tmp2; SlotInfo* mtable; bytecode* base; unsigned int len; callInfo cinfo; fieldInfo finfo; Hjava_lang_Class* crinfo; bool success = true; nativeCodeInfo ncode; codeinfo* codeInfo; int64 tms = 0; int64 tme; static Method* jitting = NULL; /* DEBUG */ lockClass(meth->class); /* Must check the translation * hasn't been done by someone else once we get it. */ if (METHOD_TRANSLATED(meth)) { goto done3; } if (Kaffe_JavaVMArgs.enableVerboseJIT) { tms = currentTime(); }DBG(MOREJIT, dprintf("asked to translate = %s.%s(%s)\n", meth->class->name->data, meth->name->data, METHOD_SIGD(meth)); ); /* If this code block is native, then just set it up and return */ if (methodIsNative(meth)) { void *func = native(meth, einfo); if (func == NULL) { success = false; goto done3; } engine_create_wrapper(meth, func); KAFFEJIT_TO_NATIVE(meth); /* Note that this is a real function not a trampoline. */ if (meth->c.ncode.ncode_end == 0) meth->c.ncode.ncode_end = METHOD_NATIVECODE(meth); goto done3; } /* Scan the code and determine the basic blocks */ success = analyzeMethod(meth, &codeInfo, einfo); if (success == false) { if (METHOD_TRANSLATED(meth)) success = true; goto done3; }DBG(MOREJIT, dprintf("successfully verified = %s.%s(%s)\n", meth->class->name->data, meth->name->data, METHOD_SIGD(meth)); ); /* Only one in the translator at once. */ enterTranslator(); startTiming(&jit_time, "jittime"); if (KaffeJIT_setupExitWithOOM(einfo)) { success = false; goto done2; }#if defined(KAFFE_PROFILER) if (profFlag) { static int init = 0; if (!init) { atexit(printProfilerStats); init = 1; } profiler_get_clicks(meth->jitClicks); meth->callsCount = 0; meth->totalClicks = 0; meth->totalChildrenClicks = 0; globalMethod = meth; }#endifDBG(MOREJIT, if (jitting) { dprintf("but still jitting = %s.%s(%s)\n", jitting->class->name->data, jitting->name->data, METHOD_SIGD(jitting)); } ); /* start modifying global variables now */ assert(jitting == 0 || !!!"reentered jitter"); /* DEBUG */ jitting = meth; /* DEBUG */ maxLocal = meth->localsz; maxStack = meth->stacksz; maxArgs = sizeofSigMethod(meth, false); if (maxArgs == -1) { goto done2; } if (meth->accflags & ACC_STATIC) { isStatic = 1; } else { isStatic = 0; maxArgs += 1; } base = (bytecode*)meth->c.bcode.code; len = meth->c.bcode.codelen; /***************************************/ /* Next reduce bytecode to native code */ /***************************************/ if (!(success = initInsnSequence(meth, codeperbytecode * len, meth->localsz, meth->stacksz, einfo))) { goto done1; } start_basic_block(); start_function();#if defined(CHECK_STACKOVERFLOW) prepare_function_call(); call_soft(checkStackOverflow); fixup_function_call();#endif monitor_enter(); if (IS_STARTOFBASICBLOCK(0)) { end_basic_block(); start_basic_block(); } for (pc = 0; pc < len; pc = npc) { assert(stackno <= maxStack+maxLocal); 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; }DBG(JIT, dprintf("pc = %d, npc = %d\n", pc, npc); ); /* Determine various exception conditions */ checkCaughtExceptions(meth, pc); start_instruction(); /* Note start of exception handling blocks */ if (IS_STARTOFEXCEPTION(pc)) { stackno = meth->localsz + meth->stacksz - 1; start_exception_block(); } switch (base[pc]) { default: dprintf("Unknown bytecode %d\n", base[pc]); postException(einfo, JAVA_LANG(VerifyError)); success = false; goto done;#include "kaffe.def" } /* Note maximum number of temp slots used and reset it */ if (tmpslot > maxTemp) { maxTemp = tmpslot; } tmpslot = 0; cancelNoWriteback(); if (IS_STARTOFBASICBLOCK(npc)) { end_basic_block(); start_basic_block(); stackno = STACKPOINTER(npc); } generateInsnSequence(codeInfo); } end_function(); assert(maxTemp < MAXTEMPS); if (finishInsnSequence(codeInfo, &ncode, einfo) == false) { success = false; goto done; } installMethodCode(codeInfo, meth, &ncode);done: tidyAnalyzeMethod(&codeInfo);DBG(JIT, dprintf("Translated %s.%s%s (%s) %p\n", meth->class->name->data, meth->name->data, METHOD_SIGD(meth), isStatic ? "static" : "normal", METHOD_NATIVECODE(meth)); ); if (Kaffe_JavaVMArgs.enableVerboseJIT) { tme = currentTime(); jitStats.time += (tme - tms); printf("<JIT: %s.%s%s time %dms (%dms) @ %p>\n", CLASS_CNAME(meth->class), meth->name->data, METHOD_SIGD(meth), (int)(tme - tms), jitStats.time, METHOD_NATIVECODE(meth)); }done1:#if defined(KAFFE_PROFILER) if (profFlag) { profiler_click_t end; profiler_get_clicks(end); meth->jitClicks = end - meth->jitClicks; globalMethod = NULL; }#endifdone2: jitting = NULL; /* DEBUG */ stopTiming(&jit_time); leaveTranslator();done3: unlockClass(meth->class); #if defined(ENABLE_JVMPI) if (success && JVMPI_EVENT_ISENABLED(JVMPI_EVENT_COMPILED_METHOD_LOAD) ) { JVMPI_Event ev; jvmpiFillMethodLoad(&ev, meth); jvmpiPostEvent(&ev); }#endif return (success);}#ifndef ALIGNMENT_OF_SIZE#define ALIGNMENT_OF_SIZE(S) (S)#endif/* * Generate the code. */boolfinishInsnSequence(codeinfo* codeInfo, nativeCodeInfo* code, errorInfo *einfo){#if defined(CALLTARGET_ALIGNMENT) unsigned int align = CALLTARGET_ALIGNMENT;#else unsigned int align = 0;#endif#if defined(MD_JIT_EXCEPTION_INFO_LENGTH) int exc_len = MD_JIT_EXCEPTION_INFO_LENGTH;#else int exc_len = 0;#endif uintp const_align = sizeof(union _constpoolval) - 1; uint32 constlen; jitCodeHeader *jch; nativecode* methblock; /* Emit pending instructions */ generateInsnSequence(codeInfo); /* Okay, put this into malloc'ed memory. We have to align the pool for * some double-word aligned instructions. */ constlen = KaffeJIT_getNumberOfConstants() * sizeof(union _constpoolval); /* Allocate some padding to align codebase if so desired */ methblock = gc_malloc(sizeof(jitCodeHeader) + exc_len + constlen + const_align + CODEPC + (align ? (align - ALIGNMENT_OF_SIZE(sizeof(jdouble))) : 0), KGC_ALLOC_JITCODE); if (methblock == 0) { postOutOfMemory(einfo); return (false); } jch = (jitCodeHeader *)methblock; jch->pool = (void *)((char *)(jch + 1)) + exc_len; jch->pool = (void *)(((uintp)jch->pool + const_align) & ~const_align ); jch->code_start = ((nativecode *)jch->pool) + constlen; jch->code_len = CODEPC; /* align entry point if so desired */ if (align != 0 && (unsigned long)jch->code_start % align != 0) { unsigned int pad = (align - (unsigned long)jch->code_start % align); assert(pad <= align - ALIGNMENT_OF_SIZE(sizeof(jdouble))); jch->code_start = jch->code_start + pad; } memcpy(jch->code_start, codeblock, CODEPC); addToCounter(&jitcodeblock, "jitmem-codeblock", 1, -(jlong)GCSIZEOF(codeblock)); KFREE(codeblock); /* Establish any code constants */ KaffeJIT_establishConstants(jch->pool); /* Link it */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -