📄 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 "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"/* * Define information about this engine. */char* engine_name = "Just-in-time";char* engine_version = KVER;iLock* 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), 0, 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;#if defined(KAFFE_PROFILER)int profFlag; /* flag to control profiling */Method *globalMethod;static void printProfilerStats(void);#endifstruct { int time;} jitStats;static void generateInsnSequence(codeinfo* codeInfo);static void checkCaughtExceptions(Method* meth, int pc);void endBlock(sequence*);void startBlock(sequence*);void endSubBlock(sequence*);void startSubBlock(sequence*);void cancelNoWriteback(void);jlong currentTime(void);/* * 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){ Hjava_lang_Throwable* overflow; /* XXX fix this. * We should not have to access current just to do the stack check */ Hjava_lang_Thread* current = getCurrentThread(); jint *needOnStack; if (current == 0) { return; } needOnStack = &unhand(current)->needOnStack; if (jthread_stackcheck(*needOnStack)) { return; } overflow = (Hjava_lang_Throwable*)unhand(current)->stackOverflowError; if (overflow != 0) { if (*needOnStack == STACK_LOW) { dprintf( "Panic: unhandled StackOverflowError()\n"); ABORT(); } *needOnStack = STACK_LOW; throwException(overflow); }}#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; int len; callInfo cinfo; fieldInfo finfo; Hjava_lang_Class* crinfo; bool success = true; nativeCodeInfo ncode; codeinfo* codeInfo; int64 tms = 0; int64 tme; int iLockRoot; static Method* jitting = 0; /* DEBUG */ /* lock class to protect the method. Even though meth->class is a Java Object, this lock is not in the Java abstraction layer; it is just a detail of implementation, so we must use lockMutex instead of lockObject. */ lockMutex(&meth->class->head); /* Must check the translation * hasn't been done by someone else once we get it. */ if (METHOD_TRANSLATED(meth)) { goto done3; } if (Kaffe_JavaVMArgs[0].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 ((meth->accflags & ACC_NATIVE) != 0) { success = native(meth, einfo); if (success == false) { goto done3; } 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 = verifyMethod(meth, &codeInfo, einfo); if (success == false) { 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 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: tidyVerifyMethod(&codeInfo);DBG(JIT, dprintf("Translated %s.%s%s (%s) %p\n", meth->class->name->data, meth->name->data, METHOD_SIGD(meth), isStatic ? "static" : "normal", meth->ncode); ) if (Kaffe_JavaVMArgs[0].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 = 0; }#endifdone2: jitting = 0; /* DEBUG */ stopTiming(&jit_time); leaveTranslator();done3: unlockMutex(&meth->class->head); return (success);}/* * Generate the code. */boolfinishInsnSequence(codeinfo* codeInfo, nativeCodeInfo* code, errorInfo *einfo){#if defined(CALLTARGET_ALIGNMENT) int align = CALLTARGET_ALIGNMENT;#else 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 uint32 constlen; nativecode* methblock; nativecode* codebase; /* Emit pending instructions */ generateInsnSequence(codeInfo); /* Okay, put this into malloc'ed memory */ constlen = nConst * sizeof(union _constpoolval); /* Allocate some padding to align codebase if so desired * NB: we assume the allocator returns at least 8-byte aligned * addresses. XXX: this should really be gc_memalign */ methblock = gc_malloc(exc_len + constlen + CODEPC + (align ? (align - 8) : 0), GC_ALLOC_JITCODE); if (methblock == 0) { postOutOfMemory(einfo); return (false); } codebase = methblock + exc_len + constlen; /* align entry point if so desired */ if (align != 0 && (unsigned long)codebase % align != 0) { int pad = (align - (unsigned long)codebase % align); /* assert the allocator indeed returned 8 bytes aligned addrs */ assert(pad <= align - 8); codebase = (char*)codebase + pad; } memcpy(codebase, codeblock, CODEPC); addToCounter(&jitcodeblock, "jitmem-codeblock", 1, -(jlong)GCSIZEOF(codeblock)); gc_free(codeblock); /* Establish any code constants */ establishConstants(methblock + exc_len); /* Link it */ linkLabels(codeInfo, (uintp)codebase); /* Note info on the compiled code for later installation */ code->mem = methblock; code->memlen = exc_len + constlen + CODEPC; code->code = codebase; code->codelen = CODEPC; return (true);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -