void CodeGeneratorMIPS64::visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool) { MTableSwitch* mir = ool->mir(); masm.haltingAlign(sizeof(void*)); masm.bind(ool->jumpLabel()->target()); masm.addCodeLabel(*ool->jumpLabel()); for (size_t i = 0; i < mir->numCases(); i++) { LBlock* caseblock = skipTrivialBlocks(mir->getCase(i))->lir(); Label* caseheader = caseblock->label(); uint32_t caseoffset = caseheader->offset(); // The entries of the jump table need to be absolute addresses and thus // must be patched after codegen is finished. Each table entry uses 8 // instructions (4 for load address, 2 for branch, and 2 padding). CodeLabel cl; masm.ma_li(ScratchRegister, cl.patchAt()); masm.branch(ScratchRegister); masm.as_nop(); masm.as_nop(); cl.target()->bind(caseoffset); masm.addCodeLabel(cl); } }
void AssemblerX86Shared::processCodeLabels(IonCode *code) { for (size_t i = 0; i < codeLabels_.length(); i++) { CodeLabel *label = codeLabels_[i]; Bind(code, label->dest(), code->raw() + label->src()->offset()); } }
bool ModuleGenerator::finishLinkData(Bytes& code) { // Inflate the global bytes up to page size so that the total bytes are a // page size (as required by the allocator functions). linkData_.globalDataLength = AlignBytes(linkData_.globalDataLength, gc::SystemPageSize()); // Add links to absolute addresses identified symbolically. for (size_t i = 0; i < masm_.numAsmJSAbsoluteAddresses(); i++) { AsmJSAbsoluteAddress src = masm_.asmJSAbsoluteAddress(i); if (!linkData_.symbolicLinks[src.target].append(src.patchAt.offset())) return false; } // Relative link metadata: absolute addresses that refer to another point within // the asm.js module. // CodeLabels are used for switch cases and loads from floating-point / // SIMD values in the constant pool. for (size_t i = 0; i < masm_.numCodeLabels(); i++) { CodeLabel cl = masm_.codeLabel(i); LinkData::InternalLink inLink(LinkData::InternalLink::CodeLabel); inLink.patchAtOffset = masm_.labelToPatchOffset(*cl.patchAt()); inLink.targetOffset = cl.target()->offset(); if (!linkData_.internalLinks.append(inLink)) return false; } #if defined(JS_CODEGEN_X86) // Global data accesses in x86 need to be patched with the absolute // address of the global. Globals are allocated sequentially after the // code section so we can just use an InternalLink. for (GlobalAccess a : masm_.globalAccesses()) { LinkData::InternalLink inLink(LinkData::InternalLink::RawPointer); inLink.patchAtOffset = masm_.labelToPatchOffset(a.patchAt); inLink.targetOffset = code.length() + a.globalDataOffset; if (!linkData_.internalLinks.append(inLink)) return false; } #elif defined(JS_CODEGEN_X64) // Global data accesses on x64 use rip-relative addressing and thus we can // patch here, now that we know the final codeLength. for (GlobalAccess a : masm_.globalAccesses()) { void* from = code.begin() + a.patchAt.offset(); void* to = code.end() + a.globalDataOffset; X86Encoding::SetRel32(from, to); } #else // Global access is performed using the GlobalReg and requires no patching. MOZ_ASSERT(masm_.globalAccesses().length() == 0); #endif return true; }
uint32_t MacroAssembler::pushFakeReturnAddress(Register scratch) { CodeLabel cl; ma_li(scratch, cl.patchAt()); Push(scratch); bind(cl.target()); uint32_t retAddr = currentOffset(); addCodeLabel(cl); return retAddr; }
uint32_t MacroAssembler::pushFakeReturnAddress(Register scratch) { CodeLabel cl; mov(cl.dest(), scratch); Push(scratch); bind(cl.src()); uint32_t retAddr = currentOffset(); addCodeLabel(cl); return retAddr; }
bool ModuleGenerator::finishStaticLinkData(uint8_t* code, uint32_t codeBytes, StaticLinkData* link) { // Add links to absolute addresses identified symbolically. StaticLinkData::SymbolicLinkArray& symbolicLinks = link->symbolicLinks; for (size_t i = 0; i < masm_.numAsmJSAbsoluteAddresses(); i++) { AsmJSAbsoluteAddress src = masm_.asmJSAbsoluteAddress(i); if (!symbolicLinks[src.target].append(src.patchAt.offset())) return false; } // Relative link metadata: absolute addresses that refer to another point within // the asm.js module. // CodeLabels are used for switch cases and loads from floating-point / // SIMD values in the constant pool. for (size_t i = 0; i < masm_.numCodeLabels(); i++) { CodeLabel cl = masm_.codeLabel(i); StaticLinkData::InternalLink inLink(StaticLinkData::InternalLink::CodeLabel); inLink.patchAtOffset = masm_.labelToPatchOffset(*cl.patchAt()); inLink.targetOffset = cl.target()->offset(); if (!link->internalLinks.append(inLink)) return false; } #if defined(JS_CODEGEN_X86) // Global data accesses in x86 need to be patched with the absolute // address of the global. Globals are allocated sequentially after the // code section so we can just use an InternalLink. for (size_t i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) { AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i); StaticLinkData::InternalLink inLink(StaticLinkData::InternalLink::RawPointer); inLink.patchAtOffset = masm_.labelToPatchOffset(a.patchAt); inLink.targetOffset = codeBytes + a.globalDataOffset; if (!link->internalLinks.append(inLink)) return false; } #endif #if defined(JS_CODEGEN_X64) // Global data accesses on x64 use rip-relative addressing and thus do // not need patching after deserialization. uint8_t* globalData = code + codeBytes; for (size_t i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) { AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i); masm_.patchAsmJSGlobalAccess(a.patchAt, code, globalData, a.globalDataOffset); } #endif return true; }
// Builds an exit frame on the stack, with a return address to an internal // non-function. Returns offset to be passed to markSafepointAt(). bool MacroAssemblerX86Shared::buildFakeExitFrame(const Register &scratch, uint32_t *offset) { mozilla::DebugOnly<uint32_t> initialDepth = framePushed(); CodeLabel cl; mov(cl.dest(), scratch); uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS); Push(Imm32(descriptor)); Push(scratch); bind(cl.src()); *offset = currentOffset(); JS_ASSERT(framePushed() == initialDepth + IonExitFrameLayout::Size()); return addCodeLabel(cl); }
// Builds an exit frame on the stack, with a return address to an internal // non-function. Returns offset to be passed to markSafepointAt(). void MacroAssemblerX86Shared::buildFakeExitFrame(Register scratch, uint32_t* offset) { mozilla::DebugOnly<uint32_t> initialDepth = asMasm().framePushed(); CodeLabel cl; mov(cl.dest(), scratch); uint32_t descriptor = MakeFrameDescriptor(asMasm().framePushed(), JitFrame_IonJS); asMasm().Push(Imm32(descriptor)); asMasm().Push(scratch); bind(cl.src()); *offset = currentOffset(); MOZ_ASSERT(asMasm().framePushed() == initialDepth + ExitFrameLayout::Size()); addCodeLabel(cl); }
bool ModuleGenerator::finish(HeapUsage heapUsage, CacheableChars filename, CacheableCharsVector&& prettyFuncNames, UniqueModuleData* module, UniqueStaticLinkData* linkData, SlowFunctionVector* slowFuncs) { MOZ_ASSERT(!activeFunc_); MOZ_ASSERT(finishedFuncs_); module_->heapUsage = heapUsage; module_->filename = Move(filename); module_->prettyFuncNames = Move(prettyFuncNames); if (!GenerateStubs(*this, UsesHeap(heapUsage))) return false; masm_.finish(); if (masm_.oom()) return false; // Start global data on a new page so JIT code may be given independent // protection flags. Note assumption that global data starts right after // code below. module_->codeBytes = AlignBytes(masm_.bytesNeeded(), AsmJSPageSize); // Inflate the global bytes up to page size so that the total bytes are a // page size (as required by the allocator functions). module_->globalBytes = AlignBytes(module_->globalBytes, AsmJSPageSize); // Allocate the code (guarded by a UniquePtr until it is given to the Module). module_->code = AllocateCode(cx_, module_->totalBytes()); if (!module_->code) return false; // Delay flushing until Module::dynamicallyLink. The flush-inhibited range // is set by executableCopy. AutoFlushICache afc("ModuleGenerator::finish", /* inhibit = */ true); uint8_t* code = module_->code.get(); masm_.executableCopy(code); // c.f. JitCode::copyFrom MOZ_ASSERT(masm_.jumpRelocationTableBytes() == 0); MOZ_ASSERT(masm_.dataRelocationTableBytes() == 0); MOZ_ASSERT(masm_.preBarrierTableBytes() == 0); MOZ_ASSERT(!masm_.hasSelfReference()); // Convert the CallSiteAndTargetVector (needed during generation) to a // CallSiteVector (what is stored in the Module). if (!module_->callSites.appendAll(masm_.callSites())) return false; // The MacroAssembler has accumulated all the heap accesses during codegen. module_->heapAccesses = masm_.extractHeapAccesses(); // Add links to absolute addresses identified symbolically. StaticLinkData::SymbolicLinkArray& symbolicLinks = link_->symbolicLinks; for (size_t i = 0; i < masm_.numAsmJSAbsoluteAddresses(); i++) { AsmJSAbsoluteAddress src = masm_.asmJSAbsoluteAddress(i); if (!symbolicLinks[src.target].append(src.patchAt.offset())) return false; } // Relative link metadata: absolute addresses that refer to another point within // the asm.js module. // CodeLabels are used for switch cases and loads from floating-point / // SIMD values in the constant pool. for (size_t i = 0; i < masm_.numCodeLabels(); i++) { CodeLabel cl = masm_.codeLabel(i); StaticLinkData::InternalLink link(StaticLinkData::InternalLink::CodeLabel); link.patchAtOffset = masm_.labelToPatchOffset(*cl.patchAt()); link.targetOffset = cl.target()->offset(); if (!link_->internalLinks.append(link)) return false; } #if defined(JS_CODEGEN_X86) // Global data accesses in x86 need to be patched with the absolute // address of the global. Globals are allocated sequentially after the // code section so we can just use an InternalLink. for (size_t i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) { AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i); StaticLinkData::InternalLink link(StaticLinkData::InternalLink::RawPointer); link.patchAtOffset = masm_.labelToPatchOffset(a.patchAt); link.targetOffset = module_->codeBytes + a.globalDataOffset; if (!link_->internalLinks.append(link)) return false; } #endif #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) // On MIPS we need to update all the long jumps because they contain an // absolute adress. The values are correctly patched for the current address // space, but not after serialization or profiling-mode toggling. for (size_t i = 0; i < masm_.numLongJumps(); i++) { size_t off = masm_.longJump(i); StaticLinkData::InternalLink link(StaticLinkData::InternalLink::InstructionImmediate); link.patchAtOffset = off; link.targetOffset = Assembler::ExtractInstructionImmediate(code + off) - uintptr_t(code); if (!link_->internalLinks.append(link)) return false; } #endif #if defined(JS_CODEGEN_X64) // Global data accesses on x64 use rip-relative addressing and thus do // not need patching after deserialization. uint8_t* globalData = code + module_->codeBytes; for (size_t i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) { AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i); masm_.patchAsmJSGlobalAccess(a.patchAt, code, globalData, a.globalDataOffset); } #endif *module = Move(module_); *linkData = Move(link_); *slowFuncs = Move(slowFuncs_); return true; }