BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations, BailoutStack *bailout) : machine_(bailout->machine()) { uint8_t *sp = bailout->parentStackPointer(); framePointer_ = sp + bailout->frameSize(); topFrameSize_ = framePointer_ - sp; JSScript *script = ScriptFromCalleeToken(((JitFrameLayout *) framePointer_)->calleeToken()); JitActivation *activation = activations.activation()->asJit(); topIonScript_ = script->ionScript(); attachOnJitActivation(activations); if (bailout->frameClass() == FrameSizeClass::None()) { snapshotOffset_ = bailout->snapshotOffset(); return; } // Compute the snapshot offset from the bailout ID. JSRuntime *rt = activation->compartment()->runtimeFromMainThread(); JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass()); uintptr_t tableOffset = bailout->tableOffset(); uintptr_t tableStart = reinterpret_cast<uintptr_t>(Assembler::BailoutTableStart(code->raw())); MOZ_ASSERT(tableOffset >= tableStart && tableOffset < tableStart + code->instructionsSize()); MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1; MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE); snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId); }
IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *bailout) : IonFrameIterator(activations), machine_(bailout->machine()) { uint8_t *sp = bailout->parentStackPointer(); uint8_t *fp = sp + bailout->frameSize(); current_ = fp; type_ = IonFrame_OptimizedJS; topFrameSize_ = current_ - sp; topIonScript_ = script()->ionScript(); if (bailout->frameClass() == FrameSizeClass::None()) { snapshotOffset_ = bailout->snapshotOffset(); return; } // Compute the snapshot offset from the bailout ID. JitActivation *activation = activations.activation()->asJit(); JSRuntime *rt = activation->compartment()->runtimeFromMainThread(); JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass()); uintptr_t tableOffset = bailout->tableOffset(); uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw()); JS_ASSERT(tableOffset >= tableStart && tableOffset < tableStart + code->instructionsSize()); JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1; JS_ASSERT(bailoutId < BAILOUT_TABLE_SIZE); snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId); }
BailoutEnvironment::BailoutEnvironment(JitCompartment *ion, void **sp) : sp_(sp) { bailout_ = reinterpret_cast<ExtendedBailoutStack *>(sp); if (bailout_->frameClass() != FrameSizeClass::None()) { frameSize_ = bailout_->frameSize(); frame_ = &sp_[sizeof(BailoutStack) / sizeof(void *)]; // Compute the bailout ID. JitCode *code = ion->getBailoutTable(bailout_->frameClass()); uintptr_t tableOffset = bailout_->tableOffset(); uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw()); JS_ASSERT(tableOffset >= tableStart && tableOffset < tableStart + code->instructionsSize()); JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); bailoutId_ = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1; JS_ASSERT(bailoutId_ < BAILOUT_TABLE_SIZE); } else { frameSize_ = bailout_->frameSize(); frame_ = &sp_[sizeof(ExtendedBailoutStack) / sizeof(void *)]; } }
JitCode* Linker::newCode(JSContext* cx, CodeKind kind) { JS::AutoAssertNoGC nogc(cx); if (masm.oom()) return fail(cx); masm.performPendingReadBarriers(); static const size_t ExecutableAllocatorAlignment = sizeof(void*); static_assert(CodeAlignment >= ExecutableAllocatorAlignment, "Unexpected alignment requirements"); // We require enough bytes for the code, header, and worst-case alignment padding. size_t bytesNeeded = masm.bytesNeeded() + sizeof(JitCodeHeader) + (CodeAlignment - ExecutableAllocatorAlignment); if (bytesNeeded >= MAX_BUFFER_SIZE) return fail(cx); // ExecutableAllocator requires bytesNeeded to be aligned. bytesNeeded = AlignBytes(bytesNeeded, ExecutableAllocatorAlignment); ExecutablePool* pool; uint8_t* result = (uint8_t*)cx->runtime()->jitRuntime()->execAlloc().alloc(cx, bytesNeeded, &pool, kind); if (!result) return fail(cx); // The JitCodeHeader will be stored right before the code buffer. uint8_t* codeStart = result + sizeof(JitCodeHeader); // Bump the code up to a nice alignment. codeStart = (uint8_t*)AlignBytes((uintptr_t)codeStart, CodeAlignment); MOZ_ASSERT(codeStart + masm.bytesNeeded() <= result + bytesNeeded); uint32_t headerSize = codeStart - result; JitCode* code = JitCode::New<NoGC>(cx, codeStart, bytesNeeded - headerSize, headerSize, pool, kind); if (!code) return fail(cx); if (masm.oom()) return fail(cx); awjc.emplace(result, bytesNeeded); code->copyFrom(masm); masm.link(code); if (masm.embedsNurseryPointers()) cx->runtime()->gc.storeBuffer().putWholeCell(code); return code; }
JitCode* Linker::newCode(JSContext* cx, CodeKind kind, bool hasPatchableBackedges /* = false */) { MOZ_ASSERT(masm.numAsmJSAbsoluteAddresses() == 0); MOZ_ASSERT_IF(hasPatchableBackedges, kind == ION_CODE); gc::AutoSuppressGC suppressGC(cx); if (masm.oom()) return fail(cx); ExecutablePool* pool; size_t bytesNeeded = masm.bytesNeeded() + sizeof(JitCode*) + CodeAlignment; if (bytesNeeded >= MAX_BUFFER_SIZE) return fail(cx); // ExecutableAllocator requires bytesNeeded to be word-size aligned. bytesNeeded = AlignBytes(bytesNeeded, sizeof(void*)); ExecutableAllocator& execAlloc = hasPatchableBackedges ? cx->runtime()->jitRuntime()->backedgeExecAlloc() : cx->runtime()->jitRuntime()->execAlloc(); uint8_t* result = (uint8_t*)execAlloc.alloc(bytesNeeded, &pool, kind); if (!result) return fail(cx); // The JitCode pointer will be stored right before the code buffer. uint8_t* codeStart = result + sizeof(JitCode*); // Bump the code up to a nice alignment. codeStart = (uint8_t*)AlignBytes((uintptr_t)codeStart, CodeAlignment); uint32_t headerSize = codeStart - result; JitCode* code = JitCode::New<allowGC>(cx, codeStart, bytesNeeded - headerSize, headerSize, pool, kind); if (!code) return nullptr; if (masm.oom()) return fail(cx); awjc.emplace(result, bytesNeeded); code->copyFrom(masm); masm.link(code); if (masm.embedsNurseryPointers()) cx->runtime()->gc.storeBuffer.putWholeCell(code); return code; }
static bool Execute(JSContext* cx, MacroAssembler& masm) { AllocatableRegisterSet regs(RegisterSet::Volatile()); LiveRegisterSet save(regs.asLiveSet()); masm.PopRegsInMask(save); masm.ret(); // Add return statement to be sure. if (masm.oom()) return false; Linker linker(masm); JitCode* code = linker.newCode<CanGC>(cx, OTHER_CODE); if (!code) return false; if (!ExecutableAllocator::makeExecutable(code->raw(), code->bufferSize())) return false; EnterTest test = code->as<EnterTest>(); test(); return true; }
IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *bailout) : JitFrameIterator(activations), machine_(bailout->machine()) { uint8_t *sp = bailout->parentStackPointer(); uint8_t *fp = sp + bailout->frameSize(); kind_ = Kind_BailoutIterator; current_ = fp; type_ = JitFrame_IonJS; topFrameSize_ = current_ - sp; switch (mode_) { case SequentialExecution: topIonScript_ = script()->ionScript(); break; case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break; default: MOZ_ASSUME_UNREACHABLE("No such execution mode"); } if (bailout->frameClass() == FrameSizeClass::None()) { snapshotOffset_ = bailout->snapshotOffset(); return; } // Compute the snapshot offset from the bailout ID. JitActivation *activation = activations.activation()->asJit(); JSRuntime *rt = activation->compartment()->runtimeFromMainThread(); JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass()); uintptr_t tableOffset = bailout->tableOffset(); uintptr_t tableStart = reinterpret_cast<uintptr_t>(Assembler::BailoutTableStart(code->raw())); JS_ASSERT(tableOffset >= tableStart && tableOffset < tableStart + code->instructionsSize()); JS_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0); uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1; JS_ASSERT(bailoutId < BAILOUT_TABLE_SIZE); snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId); }