// Test the size of the assembler generated sendDesc in // EnterSelf (<machine>.runtime.s). Lars July 92 void sendDesc::init() { sendDesc::init_platform(); # if HOST_ARCH == PPC_ARCH && TARGET_ARCH == I386_ARCH if (true) return; // just testing asm # endif sendDesc* f = sendDesc::first_sendDesc(); // cannot do this test on sparc, it has a register-call which does not read as a call // if (!isCall((int32*)f->jump_addr_addr())) // fatal("first_sendDesc() does not have a call"); if (f->raw_lookupType() != StaticNormalLookupType) fatal5("first_sendDesc() has wrong lookup type: 0x%x, should be: 0x%x\n" " firstSelfFrame_returnPC: 0x%x, first_inst_addr: 0x%x, first_sendDesc 0x%x", f->raw_lookupType(), StaticNormalLookupType, firstSelfFrame_returnPC, first_inst_addr((void*)firstSelfFrame_returnPC), sendDesc::first_sendDesc()); char* computedEnd = (char*) f + f->endOffset(); char* realEnd = first_inst_addr((void*)firstSelfFrameSendDescEnd); if (computedEnd != realEnd) fatal2("sendDesc of firstSelfFrame has wrong size, " "computedEnd = 0x%x, realEnd = 0x%x", computedEnd, realEnd); }
char* abstractSlotRef::interpretForCompiledSender(oop receiver, oop sel, oop arg1 ) { oop res = interpretData( receiver, sel, arg1 ); if ( res != badOop ) { ReturnResult_stub_result = res; return first_inst_addr(ReturnResult_stub); } else { sneaky_method_argument_to_interpret = contents(); return first_inst_addr(interpret_from_compiled_sender); } }
void InterruptedContext::setupPreemptionFromSignal() { InterruptedContext::the_interrupted_context->must_be_in_self_thread(); if (continuePC) fatal("recursive setSPLimit"); if ( the_interrupted_context->pc() >= first_inst_addr( setSPLimitAndContinue ) && the_interrupted_context->pc() < first_inst_addr( setSPLimitAndContinueEnd ) || the_interrupted_context->next_pc() >= first_inst_addr( setSPLimitAndContinue ) && the_interrupted_context->next_pc() < first_inst_addr( setSPLimitAndContinueEnd )) { return; // already patched or just about to do it } newSPLimit = currentProcess->stackEnd(); set_continuation_address(first_inst_addr(setSPLimitAndContinue), false, true); }
Label* CodeGen::cPrimCall(PrimDesc* p, RegisterState* s, bool continueNLR, bool trust_fns_arg_count, fint arg_and_rcvr_count) { a.Comment("cPrimCall"); Label* where_nlr_jumps_to = NULL; // WARNING: following code sequences are known to get_target_of_Self_call_site // and set_target_of_Self_call_site // Also, getPrimCallEndOffset assumes continuation is right after sequence. a.call( (int32) first_inst_addr(p->fn()), PVMAddressOperand ); // inline cache: Label past_nlr(a.printing); a.jmp(&past_nlr); // skip over mask and nlr code s->genMask(); // used register mask for GC if ( p->needsNLRCode() ) { if (continueNLR) { // NLR returns from this method, up NLR chain (only for calling intr check after stack overflow & nonLifo trap) continueNonLocalReturn(); } else { // do the NLR bit where_nlr_jumps_to = new Label(a.printing); a.jmp(where_nlr_jumps_to); } } past_nlr.define(); return where_nlr_jumps_to; }
Label* CodeGen::cPrimCall(PrimDesc* p, RegisterState* s, bool continueNLR, bool /*trust_fn_arg_count */, fint /* arg_and_rcvr_count */) { // call <primitive> // add o7, oopSize, o7 // so C skips the mask // .data mask // need mask for scavenging // *if needsNLRCode // <continueNonLocalReturn> // for prims like AbortProcess // *endif a.CallP( first_inst_addr( p->fn() ) ); a.AddI(CalleeReturnAddr, p->needsNLRCode() ? sendDesc::abortable_prim_end_offset - sendDesc::nonabortable_prim_end_offset + oopSize : oopSize, CalleeReturnAddr); // skip register mask upon return s->genMask(); // used register mask if ( !p->needsNLRCode()) { return NULL; } else if (continueNLR) { continueNonLocalReturn(); return NULL; } else { Label* l = a.BraForward(true); a.Nop(); return l; } }
bool SignalInterface::handle_SIC_OS_signal(int ossig, char* addr, int32 code) { InterruptedContext::the_interrupted_context->must_be_in_self_thread(); assert( !(ossig == SIGNonLifo && code == ST_ShouldNeverHappen), "SIC compiler error: should never get to this trap instruction"); if ( FastMapTest && is_map_load_signal(ossig) && isMapLoad((int32*)InterruptedContext::the_interrupted_context->pc())) { FlagSetting fs2(_is_in_map_load, true); handleMapLoadTrap(InterruptedContext::the_interrupted_context); return true; } if (ossig == SIGUncommon && handleUncommonTrap()) // was uncommon branch trap return true; if (ossig == SIGNonLifo && is_uplevel_trap(code) || ossig == SIGBadHomeRef && NLRSupport::is_bad_home_reference(addr) && Memory->code->contains(InterruptedContext::the_interrupted_context->pc())) { // continue in NLRSupport::non_lifo_abort // This is much easier than doing it here because the stack is in a mess right now. InterruptedContext::continue_abort_at(first_inst_addr(NLRSupport::non_lifo_abort_from_continuePC), false); return true; } return false; }
bool Conversion::createFrame(fint i, nmethod *newNM) { // create new frame, store it in newFr and initialize it // XXXX what if fr is interp frame? // this routine seems to use sd and sp, // and to set sd, sp, and newFr // figure out new value for sd and if isInInterruptCheck sendDesc* prev_sd= vf[i]->fr->send_desc(); // Have to be careful when converting a frame at the bottom of the // stack which has just returned from interruptCheck, after a process // switch, or while single stepping -- otherwise the next send is // omitted. MIW 6/8/94 bool isInInterruptCheck= prev_sd // eliminate uncommon branches && prev_sd->isPrimCall() && prev_sd->jump_addr() == first_inst_addr(interruptCheck); assert(vf[i]->fr->is_aligned(), "frame alignment check"); sendDesc* sd_of_created_frame = newNM->sendDescFor(vf[i], isInInterruptCheck); assert( i == 1 || newVF[i-1], "Mac has no null check"); RegisterLocator* caller_rl_before_creating_frame = i == 1 ? nonvols_for_caller // vf[0] could be null, so don't do vf[0]->reg_loc() // going to be smashing regs saved below last created frame, so copy them : newVF[i-1]->reg_loc()->for_copied_frame(NULL); // ppc frames contain their own return addresses, so use sd_of_created_frame ppc_sp* newSP = ((ppc_sp*) sp)->push_new_sp( sd_of_created_frame->return_pc(), newNM->frameSize(), true ); if (stk->isStackOverflow(newSP)) { fatal("stack overflow while converting stack frame"); } sp = (char*)newSP; newFr = (frame*)newSP; rlFr = (frame*)newSP->push_new_sp((char*)&ReturnTrap_returnPC, ReturnTrap_frame_size, true); // PPC needs frame for all saved regs newFrRl = RegisterLocator::for_NonVolSaving_frame(rlFr); RegisterLocator* caller_rl_after_creating_frame = newFrRl->sender(); // make sure all saved non vol regs for higher frames // are saved in either this frame or the spoof SaveNonVolRegs frame for (fint i = LowestLocalNonVolReg; i <= HighestNonVolReg; ++i ) { oop* srcp = caller_rl_before_creating_frame->address_of(Location(i)); oop* dstp = caller_rl_after_creating_frame ->address_of(Location(i)); *dstp = *srcp; } sd = sd_of_created_frame; return isInInterruptCheck; }
void AgingStub::init(nmethod* nm) { CountCodePattern* patt = CountStub::pattern[Comparing]; set_recompile_addr(first_inst_addr(MakeOld_stub)); set_count_addr(patt, (int32)&sendCounts[id()]); int32* p = (int32*)(int32(insts()) + patt->limit_offset); assert(*p == patt->initial_limit, "???"); fint limit = nm->agingLimit(); *p = limit; set_count(1); }
void BlockCloneNode::genCall() { Location dest = block()->loc; genHelper->loadImmediateOop(block()->block, CReceiverReg); // load block Oop theAssembler->CallP(first_inst_addr(blockClone->fn())); theAssembler->OrR(SP, G0, Arg1); // load home frame assert(!blockClone->canScavenge() && !blockClone->needsNLRCode(), "need to rewrite this"); genHelper->moveRegToLoc(ResultReg, dest); if (block()->uplevelR && isRegister(dest)) { // flush to stack theAssembler->StoreI(SP, spOffset(dest), dest); } }
void AgingStub::init(nmethod* nm) { CountCodePattern* patt = CountStub::pattern[Comparing]; int32* p = (int32*)insts(); set_recompile_addr(first_inst_addr(MakeOld_stub)); set_count_addr(patt, (int32)&sendCounts[id()]); fint limit = nm->agingLimit(); if (limit > 1023) { setSetHiImm(p + patt->limit_sethi_offset, limit); } else { // setHi would set to 0, so use an add instead p[patt->limit_sethi_offset] = add_inst; setArithImm(p + patt->limit_sethi_offset, limit); } set_count(1); }
void PrimNode::gen() { BasicNode::gen(); assert(bci() != IllegalBCI, "should have legal bci"); if (pd->canWalkStack()) genPcDesc(); theAssembler->CallP(first_inst_addr(pd->fn())); fint skip = pd->canScavenge() ? oopSize : 0; // reg. mask if (pd->needsNLRCode()) skip += sendDesc::abortable_prim_end_offset - sendDesc::nonabortable_prim_end_offset; if (skip) { // skip register mask / NLR code upon return theAssembler->AddI(CalleeReturnAddr, skip, CalleeReturnAddr); theAssembler->Data(mask()); if (pd->needsNLRCode()) nlrCode(); } else { theAssembler->Nop(); } }
void SICGenHelper::checkRecompilation(fint countID) { // test for recompilation // sethi &counter, t3 // load [t3 + lo%(&counter)], t4 // add t4, 1, t4 // cmp t4, recompileLimit // bne ok // store t4, [t3 + lo%(&counter)] // <jumpTo recompiler> // nop // ok: // di recompilation doesn't work right now - see recompile.c if (theSIC->diLink) return; Assembler* ass = theAssembler; ass->Comment("test for recompilation"); void* counter = &useCount[countID]; ass->SetHiA(counter, Temp3); ass->LoadA(Temp3, counter, Temp2); ass->AddI(Temp2, 1, Temp2); fint limit = recompileLimit(0); if (limit < maxImmediate) { ass->SubCCI(Temp2, limit, G0); } else { ass->SetHiI2(limit, Temp1); // limit is multiple of 1024 ass->SubCCR(Temp2, Temp1, G0); } Label* ok = ass->BneForward(false); // call recompiler void* fnaddr = first_inst_addr( theSIC->diLink ? Memory->zone->DIRecompile_stub_td() : Memory->zone-> Recompile_stub_td() ); Location linkReg = theSIC->diLink ? DIRecompileLinkReg : RecompileLinkReg; jumpTo(fnaddr, linkReg, linkReg); // The store below is always executed so that we will call the recompiler // exactly once (even if it cannot recompile for some reason). ok->define(); assert(Temp3 != linkReg, "counter addr reg will be trashed by jump"); ass->StoreA(Temp3, counter, Temp2); }
// Handle an OS signal that won't be passed to Self void SignalInterface::handle_OS_signal(int ossig, char* addr, int32 code) { FlagSettingInt fs(errno, 0); // save errno if (eventLog != NULL) // might not exist yet LOG_EVENT3("signal %ld pc %#lx npc %#lx", ossig, InterruptedContext::the_interrupted_context->pc(), InterruptedContext::the_interrupted_context->next_pc()); # if TARGET_OS_VERSION != MACOSX_VERSION assert(!is_off_signal_stack(), "should be on interrupt stack"); # endif // Linux??? if (handle_SIC_OS_signal(ossig, addr, code)) return; # if TARGET_OS_VERSION == LINUX_VERSION lprintf("\nInternal error: signal %d code %d addr 0x%lx pc 0x%lx.\n", (void*)ossig, (void*)code, (void*)(long unsigned)addr, (void*)(long unsigned)(InterruptedContext::the_interrupted_context->pc())); # else lprintf("\nInternal error: signal %d (sig%s) code %d addr 0x%lx pc 0x%lx.\n", (void*)ossig, (void*)sys_signame[ossig], (void*)code, (void*)(long unsigned)addr, (void*)(long unsigned)(InterruptedContext::the_interrupted_context->pc())); # endif error_breakpoint(); if (WizardAbortMode) { // for better VM debugging - see regs and stack undisturbed, but // printing/traversing Self stack may break InterruptedContext::fatal_menu(); } else { // let user print the stack etc; easier to do in user context WizardAbortMode = true; // next bit might fail over and over InterruptedContext::continue_abort_at(first_inst_addr(InterruptedContext::fatal_menu), true); AbortContext.set(InterruptedContext::the_interrupted_context); } }
Location frame::location_of_interpreter_of_block_scope(void* entry_point) { return entry_point == first_inst_addr(interpret) ? CReceiverReg : IllegalLocation; }
sendDesc* sendDesc::first_sendDesc() { // assertion is in sendDes::init return sendDesc::sendDesc_from_return_PC( first_inst_addr((void*)firstSelfFrame_returnPC)); }
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 }
Location frame::location_of_interpreter_of_block_scope(void* entry_point) { return entry_point == first_inst_addr(interpret) ? Location(IArgLocation(0)) : IllegalLocation; }