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; }
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; }
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); } }
fint Lookup::argCountForLookupError(oop_t selector, fint perform_arg_count, LookupType lookupType) { fint argc; if (isPerformLookupType(lookupType)) { assert(perform_arg_count >= 0); // should have a static selector or a perform arg count argc = perform_arg_count; } else { assert(is_byteVector(selector)); // should be a string if static argc = ByteVectorObj::from(selector)->arg_count(); } assert(argc >= 0 && argc < MAX_ARGS); return argc; }
void sendDesc::print() { if (isPrimCall()) { PrimDesc *pd= getPrimDescOfFirstInstruction(jump_addr(), true); lprintf("primitive: %s\n", pd->name()); return; } printIndent(); printLookupType(raw_lookupType()); LookupType l= lookupType(); if (isPerformLookupType(l)) { lprintf(": argc: %ld", arg_count()); } else { lprintf(": selector: "); selector()->print_real_oop(); } if (l & DelegateeStaticBit) { lprintf(": delegatee: "); delegatee()->print_real_oop(); } Indent++; printIndent(); lprintf("addr: %#lx", jump_addr()); if (Memory->code->contains(jump_addr())) { lprintf(" (nmethod %#lx)", nmethod::findNMethod(jump_addr())); } lprintf("; mask: "); printMask(mask()); lprintf("\n"); printIndent(); lprintf("dependency: "); dependency()->print(); lprintf("\n"); if (pic()) { printIndent(); lprintf("PIC: p ((CacheStub*)%#lx)->print()\n", pic()); } if (countStub()) { printIndent(); lprintf("count stub: p ((CountStub*)%#lx)->print()\n", countStub()); } Indent --; }
void sendDesc::extend(nmethod* nm, mapOop receiverMapOop, CountStub *cs_from_pic) { char *addr; bool isPerform= isPerformLookupType(raw_lookupType()); if ( PIC && !isPerform && (addr= jump_addr(), addr != lookupRoutine())) { // already has at least one nmethod linked to the send CacheStub* s= pic(); # if GENERATE_DEBUGGING_AIDS if (CheckAssertions) { assert(cs_from_pic==NULL, "discarding countStub?"); if (!s) { // turning monomorphic ic into PIC; PIC will carry dependencies assert(dependency()->notEmpty(), "shouldn't be empty"); // check for duplicate nmethod & rcvr map CountStub *oldcs= countStub(); nmethod *oldnm= oldcs ? oldcs->target() : nmethod::findNMethod(addr); assert( oldnm != nm || receiverMapOop != oldnm->key.receiverMapOop(), "already linked to this nmethod, why rebind?? (maybe I-cache did not get flushed)"); } } # endif s= s->extend(this, nm, receiverMapOop); assert(s, "should have a PIC now"); assert(dependency()->next == dependency()->prev, "more than one link"); } else { // first time we execute this send, or PICs disabled, or perform, or // rebinding after a PIC has been removed, or non-map related misses if (isPerform) NumberOfPerformMisses++; if (!PIC) { CacheStub *s= pic(); // remove existing PIC if (s) s->deallocate(); } rebind(nm, NULL, cs_from_pic); } MachineCache::flush_instruction_cache_for_debugging(); if (VerifyZoneOften) verify(); }
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! }
bool sendDesc::verify() { if (isPrimCall()) return true; LookupType l= lookupType(); bool flag= checkLookupTypeAndEntryPoint(); if (isPerformLookupType(l)) { if (arg_count() < 0 || arg_count() > 100) { error2("sendDesc %#lx arg count %ld is invalid", this, arg_count()); flag = false; } } else { if (! oop(selector())->verify_oop()) { flag = false; } else if (! selector()->is_string()) { error1("sendDesc %#lx selector isn't a string", this); flag = false; } nmethod* nm = target(); if (nm == NULL) { CountStub* cs = countStub(); if (cs) nm = cs->target(); } if (nm == NULL) { CacheStub* cs = pic(); if (cs) { nm= cs->get_method(0); oop sel= nm->key.selector; for (fint i= 1; i < cs->arity(); ++i) if (cs->get_method(i)->key.selector != sel) error2("sendDesc %#lx: selector != PIC case %d selector", this, i); } } if (nm && nm->key.selector != selector()) error1("sendDesc %#lx: selector != target nmethod's selector", this); } if (l & DelegateeStaticBit) { if (! delegatee()->verify_oop()) { flag = false; } else if (baseLookupType(l) == DirectedResendLookupType && ! delegatee()->is_string()) { error1("sendDesc %#lx delegatee isn't a string", this); flag = false; } } if (!dependency()->verify_list_integrity()) { lprintf("\tof sendDesc %#lx\n", this); flag = false; } if (pic()) { if (dependency()->next != dependency()->prev) error1("sendDesc %#lx: more than one elem in dependency chain", this); pic()->verify(); } else { CountStub *cs= countStub(); if (cs == NULL) { if (isCounting() && jump_addr() != lookupRoutine()) error1("sendDesc %#lx: doesn't have countStub but is counting", this); } else { if (!isCounting() && !cs->isAgingStub()) error1("sendDesc %#lx: has countStub but is not counting", this); if (dependency()->next != dependency()->prev) error1("sendDesc %#lx: more than one elem in dependency chain", this); countStub()->verify2(NULL); } } return flag; }