void nmethod::remove_me_from_inline_cache() { static int n = 0; while (linkedSends.notEmpty()) { nmln *x= linkedSends.next; assert(x->next != NULL, ""); findThing(x)->unlink_me(x); } }
fint nmethod::invocationCount() { if (useCount[id]) { // nmethod counts in prologue (to save space for count stubs) return useCount[id]; } else { fint count = 0; for (nmln* l = linkedSends.next; l != &linkedSends; l = l->next) { NCodeBase* s = findThing(l); if (s->isCountStub()) count += ((CountStub*)s)->count(); } return count; } }
void nmethod::forwardLinkedSends(nmethod* to) { // the to nmethod is about to replace the receiver; replace receiver in // all inline caches if (key.receiverMapOop() != to->key.receiverMapOop()) { // receiver map has changed - either through programming or because // a block map has changed -- don't forward (too complicated e.g. if // called by CountStub via a PIC) return; } while(linkedSends.notEmpty()) { nmln *x = linkedSends.next; findThing(x)->forwardLinkedSend(x, to); } }
bool sendDesc::checkLookupTypeAndEntryPoint() { char *insts= jump_addr(); if (insts == lookupRoutine()) return true; NCodeBase *n= findThing(insts); if (n->isCacheStub()) { return true; // checked in CacheStub::verify } nmethod* nm; if (n->isNMethod()) { nm= (nmethod*)n; } else { assert(n->isCountStub(), "what is it?"); CountStub *cs= (CountStub*)n; nm= cs->target(); insts= cs->jump_addr(); } return checkLookupTypeAndEntryPoint(nm, insts); }
void nmethod::makeOld() { flags.isYoung= 0; // remove all AgingStubs nmln* nextl; for (nmln* l= linkedSends.next; l != &linkedSends; l= nextl) { nextl= l->next; // because we're mutating l NCodeBase* s= findThing(l); if (s->isAgingStub()) { AgingStub *a= (AgingStub*)s; sendDesc* sd= a->sd(); if (sd) { a->deallocate(); sd->setCounting(NonCounting); sd->rebind(this); } else { CacheStub *pic= a->pic(); assert(pic, "no pic for sendDesc"); pic->rebind(a->sdLink.next, this, NULL); a->deallocate(); } } } }
void handleMapLoadTrap(InterruptedContext* c) { int32* pc = (int32*)c->pc(); assert(isMapLoad(pc), "not a map load"); assert(c->next_pc() == c->pc() + 4, "flow should be sequential"); Location dest = Location(rd(pc)); mapOop resultMap; // get the result map to load # if TARGET_OS_VERSION == SOLARIS_VERSION_broken // disabled for now -- there's some bug in get_reg --Urs 8/94 Location src = Location(rs1(pc)); fint rcvrTag = int(c->get_reg(src)) & Tag_Mask; if (rcvrTag == Int_Tag) { resultMap = Memory->smi_map->enclosing_mapOop(); } else if (rcvrTag == Float_Tag) { resultMap = Memory->float_map->enclosing_mapOop(); } else { fatal("bad receiver tag in map load trap"); } # else // Can't read registers, and signal handler doesn't get faulting address, // so don't know what the correct map is. But it's not really needed // (only important thing is that it's different from any mem map) since // the map testing code always checks the tag if an immediate is expected. resultMap = NULL; # endif NCodeBase* thing = findThing(pc); if (!thing->isNMethod()) { // a PIC -- no problem, will fix itself to eliminate trap } else { nmethod* nm = findNMethod(pc); if ((char*)pc >= nm->verifiedEntryPoint()) { // the trap happened in the body, not in the prologue if (nm->flags.trapCount > MapLoadTrapLimit) { // recompile the nmethod on next invocation to eliminate the traps nm->makeToBeRecompiled(); if (nm->isYoung()) // manipulate counters to provoke recompilation nm->makeVeryYoung(); else nm->makeYoung(); } else { nm->flags.trapCount++; if (nm->flags.trapCount <= 0) { // counter overflowed nm->flags.trapCount--; } } } } # if TARGET_OS_VERSION == SOLARIS_VERSION // simply set the destination register and continue c->set_reg(dest, resultMap); c->set_pc(c->next_pc()); c->set_next_pc(c->pc() + 4); # elif TARGET_OS_VERSION == SUNOS_VERSION // can't set register in interrupt handler - argh!! if (mapLoadHandler[dest]) { char* cont = c->next_pc(); InterruptedContext::set_continuation_address(first_inst_addr(mapLoadHandler[dest]), true, true); continuePC = cont; mapToLoad = resultMap; } else { fatal1("map load trap: bad destination register %d", dest); } # endif }
void nmethod::moveTo_inner(NCodeBase* p, int32 delta, int32 size) { nmethod* to = (nmethod*)p; if (this == to) return; if (PrintCodeCompaction) { lprintf("*moving nmethod %#lx (", this); printName(0, key.selector); lprintf(") to %#lx\n", to); } OopNCode::moveTo_inner(to, delta, size); assert(iabs((char*)to - (char*)this) >= sizeof(NCodeBase), "nmethods overlap too much"); assert(sizeof(NCodeBase) % oopSize == 0, "should be word-aligned"); // init to's vtable copy_words((int32*)this, (int32*)to, sizeof(NCodeBase) / sizeof(int32)); scopes->_nmethod_backPointer = to; *dBackLinkAddr() = to; flatProfiler->move(insts(), instsEnd(), to->insts()); zoneLink.shift(delta); FOR_MY_CODETABLE_ENTRIES(e) { e->nm= to; } for (nmln *x = linkedSends.next, *y = x->next; x != &linkedSends; x = y, y = y->next) { NCodeBase* s = findThing(x); s->shift_target(x, delta); } linkedSends.shift(delta, this); if (diLink.notEmpty()) { assert(diLink.next->next == &diLink, "diLink should be a pair"); diLink.next->asDIDesc()->shift_jump_addr(delta); } diLink.shift(delta); for (addrDesc* q = locs(), *pend = locsEnd(); q < pend; q++) { if (q->isSendDesc()) { sendDesc* sd = q->asSendDesc(this); sd->shift(delta, this); } else if (q->isDIDesc()) { nmln* l = q->asDIDesc(this)->dependency(); l->shift(delta); } q->shift(this, delta); } if (frame_chain != NoFrameChain && frame_chain != SavedFrameChain) frame_chain->nmethod_moved_by(delta, this); }