char* sendDesc::fastCacheLookupAndBackpatch( LookupType t, mapOop receiverMapOop, oop sel, oop del ) { if (needsDelegatee(t) || isResendLookupType(t) || isPerformLookupType(t)) { // too complicated to short-circuit these lookups return NULL; } // try mh-independent MethodLookupKey key(t, MH_TBD, receiverMapOop, sel, del); nmethod* nm= Memory->code->lookup(key); if (nm == NULL) { NumberOfFastLookupMisses++; return NULL; } NumberOfFastLookupHits++; if (nm->needToRecompileFor(this)) return NULL; if (InlineCache) { NumberOfICMisses++; extend(nm, receiverMapOop, NULL); } return nm->verifiedEntryPoint(); }
void SendNode::gen() { BasicNode::gen(); offset = theAssembler->offset(); assert(bci() != IllegalBCI, "should have legal bci"); genPcDesc(); genBreakpointBeforeCall(); theAssembler->CallB(Memory->code->trapdoors->SendMessage_stub_td()); theAssembler->Nop(); theAssembler->Data(mask()); nlrCode(); theAssembler->Zero(); // nmlns theAssembler->Zero(); if (sel != badOop) { if (isPerformLookupType(l)) { assert_smi(sel, "should be an integer argcount"); theAssembler->Data(smiOop(sel)->value()); // really arg count } else { assert_string(sel, "should be a string constant"); theAssembler->Data(sel); // constant selector } } if ((l & UninlinableSendMask) == 0) theSIC->noInlinableSends = false; theAssembler->Data(l); verifySendInfo(); if (del) { assert(needsDelegatee(l), "shouldn't have a delegatee"); theAssembler->Data(del); } }
Label* CodeGen::SendDesc(RegisterState* s, LookupType lookupType, oop selector, oop delegatee) { a.Comment("begin SendDesc"); Label past_send_desc(a.printing); a.jmp(&past_send_desc); s->genMask(); // mask of used regs Label* l = new Label(a.printing); a.jmp(l); // non-local return code assert((a.offset() & Tag_Mask) == 0, "must be aligned"); a.Zero(); // nmlns a.Zero(); if (selector != badOop) { if (isPerformLookupType(lookupType)) { assert_smi(selector, "should be an integer argcount"); a.Data(smiOop(selector)->value(), true); // really arg count } else { assert_string(selector, "should be a string constant"); a.Data(selector, true); // constant selector } } # ifdef SIC_COMPILER if (theCompiler->containsLoop) { // need counters for the sends to know how often the loop executes a.Data(withCountBits(lookupType, Counting), true); } else { a.Data(lookupType, true); } # else a.Data(lookupType, true); # endif # if GENERATE_DEBUGGING_AIDS if (CheckAssertions) switch (lookupType) { case DirectedResendLookupType: assert(lookupType & DelegateeStaticBit, "should have static delegatee"); assert_string(delegatee, "should be a string"); // fall through case ImplicitSelfLookupType: case ResendLookupType: case StaticNormalLookupType: case NormalLookupType: assert(!isPerformLookupType(lookupType), "should have a static selector"); assert_string(selector, "should be a string"); break; default: break; } # endif if (delegatee != badOop) { assert(needsDelegatee(lookupType), "shouldn't have a delegatee"); a.Data(delegatee, true); } past_send_desc.define(); a.Comment("end SendDesc"); return l; }
fint sendDesc::endOffset(LookupType l) { fint offset = normal_sendDesc_end_offset; if (needsDelegatee(l) && (l & DelegateeStaticBit)) { // add space for delegatee word offset += sizeof(oop); } return offset; }
Label* CodeGen::SendDesc(RegisterState* s, LookupType lookupType, oop selector, oop delegatee) { s->genMask(); // mask of used regs Label* l = a.BraForward(true); // non-local return code a.Nop(); a.Zero(); // nmlns a.Zero(); if (selector != badOop) { if (isPerformLookupType(lookupType)) { assert_smi(selector, "should be an integer argcount"); a.Data(smiOop(selector)->value()); // really arg count } else { assert_string(selector, "should be a string constant"); a.Data(selector); // constant selector } } if (theCompiler->containsLoop) { // need counters for the sends to know how often the loop executes a.Data(withCountBits(lookupType, Counting)); } else { a.Data(lookupType); } # if GENERATE_DEBUGGING_AIDS if (CheckAssertions) switch (lookupType) { case DirectedResendLookupType: assert(lookupType & DelegateeStaticBit, "should have static delegatee"); assert_string(delegatee, "should be a string"); // fall through case ImplicitSelfLookupType: case ResendLookupType: case StaticNormalLookupType: case NormalLookupType: assert(!isPerformLookupType(lookupType), "should have a static selector"); assert_string(selector, "should be a string"); break; default: break; } # endif if (delegatee != badOop) { assert(needsDelegatee(lookupType), "shouldn't have a delegatee"); a.Data(delegatee); } return l; }
bool cacheProbingLookup::mightBeAbleToReuseNMethod() { if ( !canReuseNM ) return false; // user-disabled if ( compiler != NIC ) // haven't figured out SIC reuse yet return false; // calling convention is different for methods with a static delegatee // send desc is one word longer to hold del, so return has different offset LookupType l= lookupType(); if ( needsDelegatee(l) && isDelegateeStatic() ) return false; if ( isPerformLookupType(l) ) return false; // send desc is also different // for immediate oops, the prologue is different so cannot reuse // non-imm oop method for immediate, and imms have no descendants if ( key.receiverMap()->is_smi() || key.receiverMap()->is_float() ) return false; // accessor methods not reusable cause offset might not match & // we don't check it yet switch ( resultType() ) { case dataResult: case assignmentResult: return false; default: break; } // cannot deal with DI, so forget it if have dc (DI desc) if (dc != NULL) return false; return true; // TA DA! }
void CodeGen::prologue(bool isAccessMethod, fint nargs) { /* ; make stack enter 1-last_extra_offset*4, $0 // make space for current_pc nmethod_frame_chain */ // *if not DI child // <smi/float/memOop prologue> // _verified: (entry point from PICs) // if necessary <check selector> // if necessary <check delegatee> // *endif DI // _diCheck: (entry point after recompile) // <verify assignable parents> // *if using recompilation // <checkRecompilation> // *endif // *if haveStackFrame // save sp, -frameSize*oopSize, sp // *endif // <clear stack temporaries and excess argument locations // CAUTION: use only Temp1/4 for temps in prologue; other temps // may contain lookup parameters. a.Comment("prologue"); fint assignableParents = L->adeps->length(); MethodKind kind = isAccessMethod ? MethodKind(-1) : theCompiler->method()->kind(); _incoming_arg_count = nargs; // for eventual putting into nmethod if (diLink == 0) { if (!L->isReceiverStatic()) { // test receiver map # if GENERATE_DEBUGGING_AIDS if (CheckAssertions) switch (L->lookupType()) { case NormalLookupType: break; case StaticNormalLookupType: case ImplicitSelfLookupType: case ResendLookupType: case DirectedResendLookupType: fatal("shouldn't miss"); break; default: break; } # endif Map* m = L->receiverMap(); bool imm = m == Memory->smi_map || m == Memory->float_map; if (m == Memory->smi_map) { smiOop_prologue(); } else if (m == Memory->float_map) { floatOop_prologue(); } else { memOop_prologue(); } } verifiedOffset = a.offset(); Label generalMiss(a.printing, NULL); a.Comment("verified entry point:"); if (L->isPerform()) { a.Comment("check selector"); checkOop(generalMiss, L->selector(), PerformSelectorLoc); } if (needsDelegatee(L->lookupType()) && !L->isDelegateeStatic()) { a.Comment("check delegatee"); checkOop(generalMiss, L->delegatee(), PerformDelegateeLoc); } } else { // don't check receiver map, selector, delegatee if a DI cache miss assert(assignableParents > 0, "should have some di parents to check"); } diCheckOffset = a.offset(); a.Comment("DI entry point:"); if (assignableParents > 0) { a.Comment("verify state of assignable parents"); fint count = 0; for (fint i = 0; i < assignableParents; i ++) { objectLookupTarget* target = L->adeps->start()[i]; Location t = loadPath(Temp2, target, LReceiverReg, Temp1); count = verifyParents(target, t, count); } } bool recomp = needRecompileCode(theCompiler->level()); if (recomp) checkRecompilation(); if (!haveStackFrame) { prologueAddr = NULL; } else { a.Comment("make stack frame (next instruction will be backpatched)"); a.enter(-0 * oopSize); // will be backpatched for locals prologueAddr = a.addr(); // will be used to patch enter with right frame size frameCreationOffset = a.offset(); // used by nmethod to find save instr, must have frame by this point XXXintel really? callPatchAddr = a.addr(); a.nop(); a.nop(); a.nop(); a.nop(); a.nop(); endCallPatchAddr = a.addr(); } if (GenerateCountCode) { int32* counter; if (assignableParents != 0) { counter = &NumberOfDIMethodCalls; } else if (isAccessMethod) { counter = &NumberOfAccessMethodCalls; } else if (kind == BlockMethodType) { counter = &NumberOfBlockMethodCalls; } else { counter = &NumberOfMethodCalls; } genCountCode(counter); } if (!isAccessMethod) { if (!recomp && GenerateLRUCode) { // this code is rarely generated in practice (recomp is usually true) a.Comment("reset unused bit"); void* unused_addr = &LRUflag[Memory->code->nextNMethodID()]; a.movl(0, NumberOperand, no_reg, int32(unused_addr), VMAddressOperand); } // don't keep uplevel-accessed names in regs // (for now, just flush everything) assert(haveStackFrame, "just checking"); } else { assert(!haveStackFrame, "just checking"); } a.Comment("End Prologue"); }
void CodeGen::prologue(bool isAccessMethod, fint nargs ) { // *if not DI child // <smi/float/memOop prologue> // _verified: (entry point from PICs) // if necessary <check selector> // if necessary <check delegatee> // *endif DI // _diCheck: (entry point after recompile) // <verify assignable parents> // *if using recompilation // <checkRecompilation> // *endif // *if haveStackFrame // save sp, -frameSize*oopSize, sp // *endif // <flush register windows if neceessary> // <clear stack temporaries and excess argument locations // CAUTION: use only Temp1/4 for temps in prologue; other temps // may contain lookup parameters. assert(Temp1 != PerformSelectorLoc && Temp1 != PerformDelegateeLoc, "will trash lookup parameters"); assert(Temp2 != PerformSelectorLoc && Temp2 != PerformDelegateeLoc, "will trash lookup parameters"); fint assignableParents = L->adeps->length(); MethodKind kind = isAccessMethod ? MethodKind(-1) : theCompiler->method()->kind(); _incoming_arg_count = nargs; // for eventual putting into nmethod if (diLink == 0) { if (!L->isReceiverStatic()) { // test receiver map # if GENERATE_DEBUGGING_AIDS if (CheckAssertions) switch (L->lookupType()) { case NormalLookupType: break; case StaticNormalLookupType: case ImplicitSelfLookupType: case ResendLookupType: case DirectedResendLookupType: fatal("shouldn't miss"); break; default: break; } # endif Map* m = L->receiverMap(); bool imm = m == Memory->smi_map || m == Memory->float_map; if (SICCountTypeTests) { a.startTypeTest(1, true, imm); a.doOneTypeTest(); } if (m == Memory->smi_map) { smiOop_prologue(Memory->code->trapdoors->SendMessage_stub_td()); } else if (m == Memory->float_map) { floatOop_prologue(Memory->code->trapdoors->SendMessage_stub_td()); } else { memOop_prologue(Memory->code->trapdoors->SendMessage_stub_td()); } } verifiedOffset = a.offset(); if (SICCountTypeTests) a.endTypeTest(); Label generalMiss(a.printing, NULL); a.Comment("verified entry point:"); if (L->isPerform()) { a.Comment("check selector"); checkOop(generalMiss, L->selector(), PerformSelectorLoc); } if (needsDelegatee(L->lookupType()) && !L->isDelegateeStatic()) { a.Comment("check delegatee"); checkOop(generalMiss, L->delegatee(), PerformDelegateeLoc); } } else { // don't check receiver map, selector, delegatee if a DI cache miss assert(assignableParents > 0, "should have some di parents to check"); } diCheckOffset = a.offset(); a.Comment("DI entry point:"); if (assignableParents > 0) { a.Comment("verify state of assignable parents"); fint count = 0; for (fint i = 0; i < assignableParents; i ++) { objectLookupTarget* target = L->adeps->start()[i]; Location t = loadPath(Temp2, target, ReceiverReg, Temp1); count = verifyParents(target, t, count); } } bool recomp = needRecompileCode(theCompiler->level()); if (recomp) checkRecompilation(); if (haveStackFrame) { prologueAddr = a.addr(); a.SaveI(SP, -1, SP); // correct frame size is patched in later frameCreationOffset = a.offset(); } else { prologueAddr = NULL; } if (GenerateCountCode) { int32* counter; if (assignableParents != 0) { counter = &NumberOfDIMethodCalls; } else if (isAccessMethod) { counter = &NumberOfAccessMethodCalls; } else if (kind == BlockMethodType) { counter = &NumberOfBlockMethodCalls; } else { counter = &NumberOfMethodCalls; } genCountCode(counter); } if (!isAccessMethod) { if (!recomp && GenerateLRUCode) { // this code is rarely generated in practice (recomp is usually true) a.Comment("reset unused bit"); void* unused_addr = &LRUflag[Memory->code->nextNMethodID()]; a.SetHiA(unused_addr, Temp2); a.StoreA(Temp2, unused_addr, G0); } // don't keep uplevel-accessed names in regs // (for now, just flush everything) if (nargs > NumIArgRegisters) nargs = NumIArgRegisters; a.Comment("flush incoming args to stack"); for (fint i = 0; i < nargs; i++) { flushToStack(IArgLocation(i), NULL); } flushToStack(IReceiverReg, NULL); // flush receiver to stack switch (kind) { case BlockMethodType: if (theCompiler->needRegWindowFlushes) flushRegisterWindows(); break; case OuterMethodType: if (needToFlushRegWindow) { // we inlined the receiver block if (theCompiler->needRegWindowFlushes) flushRegisterWindows(); } else { // receiver is parent, do nothing } break; default: fatal1("unknown kind: %ld", kind); break; } } a.Comment("End Prologue"); }