📄 machine.c
字号:
if (codeblock_size < ALLOCCODEBLOCKSZ) { codeblock_size = ALLOCCODEBLOCKSZ; } codeblock = gc_malloc(codeblock_size + CODEBLOCKREDZONE, GC_ALLOC_JITTEMP); if (codeblock == 0) { postOutOfMemory(einfo); return (false); } CODEPC = 0; 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) { codeblock_size += ALLOCCODEBLOCKSZ; codeblock = gc_realloc(codeblock, codeblock_size + CODEBLOCKREDZONE, GC_ALLOC_JITTEMP); if (codeblock == 0) { postOutOfMemory(einfo); return (false); } }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); slot_invalidate(t->u[i].slot); } } } } /* Reset */ initSeq(); return (true);}/* * 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 || canCatch(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){ SlotData** mem; SlotData* d; int i; int c; /* Count the number of slots we need to remember. Note: we * include the number of potentially active temps. */ i = maxLocal + maxStack + tmpslot; c = 0; for (i--; i >= 0; i--) { d = slotinfo[i].slot; if (d->rseq != 0 || d->wseq != 0 || isGlobal(d)) { c++; } }#if defined(STACK_LIMIT) d = stack_limit->slot; if (d->rseq != 0 || d->wseq != 0) { c++; }#endif c++; /* Add null slot on the end */ mem = gc_malloc(c * sizeof(SlotData*), GC_ALLOC_JITCODE); i = maxLocal + maxStack + tmpslot; c = 0; for (i--; i >= 0; i--) { d = slotinfo[i].slot; if (d->rseq != 0 || d->wseq != 0 || isGlobal(d)) { mem[c++] = d; } }#if defined(STACK_LIMIT) d = stack_limit->slot; if (d->rseq != 0 || d->wseq != 0) { mem[c++] = d; }#endif return (mem);}/* * Alias one slot's register to reference another. */voidslotAlias(sequence* s){ int reg; SlotData* to; SlotData* from; int type;SCHK( sanityCheck(); ) to = s->u[0].slot; type = s->u[1].value.i; from = s->u[2].slot; /* If this slot has a register we must invalidate it before we * overwrite it. */ if (to->regno != NOREG) { /* If it has the register already then don't do anything */ if (from->regno == to->regno) { return; } assert(isGlobal(to) == 0); slot_invalidate(to); } /* Get the register we're aliasing and attach the 'to' slot * to it. */ reg = slotRegister(from, type, rread, NOREG); reginfo[reg].refs++; to->regno = reg; to->modified = rwrite; /* Prepend slot onto register use lists */ to->rnext = reginfo[reg].slot; reginfo[reg].slot = to;SCHK( sanityCheck(); )}staticintsortSlots(const void* s1, const void* s2){ localUse* lcluse1; localUse* lcluse2; lcluse1 = &codeInfo->localuse[*((SlotInfo**)s1) - localinfo]; lcluse2 = &codeInfo->localuse[*((SlotInfo**)s2) - localinfo]; if (lcluse1->use == lcluse2->use) { return (0); } else if (lcluse1->use > lcluse2->use) { return (-1); } else { return (1); }}staticvoidbindSlotToGlobal(int lcl, int r, int type){ kregs* reg; SlotData* dslot; int gtype; reg = ®info[r]; dslot = localinfo[lcl].slot; reg->ctype = type; reg->type |= Rglobal; reg->refs++; reg->slot = dslot; dslot->regno = r; gtype = GL_ISGLOBAL; /* If this is an argument then pre-load */ if (lcl < maxArgs) { gtype |= GL_PRELOAD; } /* If this slot is never written note that the global is * read only. */ if (codeInfo->localuse[lcl].write == -1) { gtype |= GL_RONLY; } setGlobal(dslot, gtype);}/* * Setup global registers */voidsetupGlobalRegisters(void){#if defined(NR_GLOBALS) SlotInfo** slots; int j; int max; /* If we don't have any code info we can't do any global * optimization */ if (codeInfo == 0) { return; } /* Allocate an array for the slot pointers and copy them in */ slots = gc_malloc((1+maxLocal) * sizeof(SlotInfo*), GC_ALLOC_JITCODE); for (j = 0; j < maxLocal; j++) { slots[j] = &localinfo[j]; } /* Sort the slots to the most used is first */ qsort(slots, maxLocal, sizeof(SlotInfo*), sortSlots); /* Allocate the slots to globals */ max = NR_GLOBALS; for (j = 0; j < maxLocal && max > 0; j++) { int k; int i; localUse* lcl; i = slots[j] - localinfo; lcl = &codeInfo->localuse[i]; for (k = 0; k < MAXREG; k++) { kregs* reg; reg = ®info[k]; if ((reg->flags & Rglobal) == 0) { /* Not a global */ } else if ((reg->type & Rglobal) != 0) { /* Already used */ } else if (lcl->type == TINT && (reg->type & Rint) != 0) { bindSlotToGlobal(i, k, Rint); max--; break; } else if (lcl->type == TOBJ && (reg->type & Rref) != 0) { bindSlotToGlobal(i, k, Rref); max--; break; } } } gc_free(slots);#endif}voidsetupArgumentRegisters(void){#if defined(NR_ARGUMENTS) int args; int i; static sequence argseq[1]; args = maxArgs; if (args > NR_ARGUMENTS) { args = NR_ARGUMENTS; } for (i = 0; i < args; i++) { writeslot(argseq, i, &localinfo[i], 1); localinfo[i].slot->modified = rwrite; }#if defined(STACK_LIMIT) if (args < NR_ARGUMENTS) { writeslot(argseq, i, stack_limit, 1); stack_limit->slot->modified = rwrite; }#endif#endif}/* * Build multi-dimensional array. * This is sufficiently different from the standard * to require our own routine. */void*jit_soft_multianewarray(Hjava_lang_Class* class, jint dims, ...){ errorInfo einfo; int array[16]; Hjava_lang_Object* obj; jint arg; int i; int* arraydims; va_list ap; if (dims < 16-1) { arraydims = array; } else { arraydims = checkPtr(gc_calloc(dims+1, sizeof(int), GC_ALLOC_JITCODE)); } /* Extract the dimensions into an array */ va_start(ap, dims); for (i = 0; i < dims; i++) { arg = va_arg(ap, jint); if (arg < 0) { if (arraydims != array) { gc_free (arraydims); } throwException(NegativeArraySizeException); } arraydims[i] = arg; } arraydims[i] = -1; va_end(ap); /* Mmm, okay now build the array using the wonders of recursion */ obj = newMultiArrayChecked(class, arraydims, &einfo); if (arraydims != array) { gc_free(arraydims); } if (!obj) { throwError(&einfo); } /* Return the base object */ return (obj);}/* * Include the machine specific trampoline functions. */#include "trampolines.c"staticvoidnullCall(void){}typedef struct _fakeCall { struct _fakeCall* next; label* from; label* to; void* func;} fakeCall;static fakeCall* firstFake;static fakeCall* lastFake;static fakeCall* currFake;/* * Build a fake call to a function. * A fake call has a return address which is different from where it's * actually called from. */label*newFakeCall(void* func, uintp currpc){ label* from; label* to; /* This is used to mark where I'm calling from */ from = reference_code_label(currpc); /* This is where I'm calling to */ to = newLabel(); to->type = Linternal; to->at = 0; to->to = 0; to->from = 0; if (currFake == 0) { currFake = gc_malloc(sizeof(fakeCall), GC_ALLOC_JITCODE); if (lastFake == 0) { firstFake = currFake; } else { lastFake->next = currFake; } lastFake = currFake; } currFake->from = from; currFake->to = to; currFake->func = func; currFake = currFake->next; return (to);}staticvoidmakeFakeCalls(void){ fakeCall* c; for (c = firstFake; c != currFake; c = c->next) { softcall_fakecall(c->from, c->to, c->func); } currFake = firstFake;}/* * return what engine we're using */char*getEngine(void){ return "kaffe.jit";}#if defined(KAFFE_PROFILER)static jlong click_multiplier;static profiler_click_t click_divisor;static FILE *prof_output;static intprofilerClassStat(Hjava_lang_Class *clazz, void *param){ Method *meth; int mindex; for (mindex = clazz->nmethods, meth = clazz->methods; mindex-- > 0; meth++) { if (meth->callsCount == 0) continue; fprintf(prof_output, "%10d %10.6g %10.6g %10.6g %10.6g %s.%s%s\n", meth->callsCount, (click_multiplier * ((double)meth->totalClicks)) / click_divisor, (click_multiplier * ((double)(meth->totalClicks - meth->totalChildrenClicks))) / click_divisor, (click_multiplier * ((double)meth->totalChildrenClicks)) / click_divisor, (click_multiplier * ((double)meth->jitClicks)) / click_divisor, meth->class->name->data, meth->name->data, METHOD_SIGD(meth) ); } return 0;}static voidprintProfilerStats(void){ profiler_click_t start, end; jlong m_start, m_end; /* If the profFlag == 0, don't bother printing anything */ if (profFlag == 0) return; /* open file */ prof_output = fopen("prof.out", "w"); if (prof_output == NULL) { return; } /* Need to figure out what profiler_click _really_ is. * Use currentTime() to guest how long is a second. Call it before * to don't count dynamic linker resolve time. */ m_start = currentTime(); profiler_get_clicks(start); sleep (1); m_end = currentTime(); profiler_get_clicks(end); click_multiplier = m_end - m_start; click_divisor = end - start; fprintf(prof_output, "# clockTick: %lld per 1/%lld seconds aka %lld per milliseconds\n", click_divisor, click_multiplier, click_divisor / click_multiplier); fprintf(prof_output, "%10s %10s %10s %10s %10s %s\n", "# count", "total", "self", "children", "jit", "method-name"); /* Traverse through class hash table */ walkClassPool(profilerClassStat, NULL); fclose(prof_output);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -