зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1057082 - 2/7 - Add profiler exit and enter frame instrumentation code. r=jandem
This commit is contained in:
Родитель
c3fed7ebbb
Коммит
b6f5b5ee44
|
@ -46,6 +46,12 @@ CompileRuntime::addressOfJitActivation()
|
||||||
return &runtime()->mainThread.jitActivation;
|
return &runtime()->mainThread.jitActivation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const void *
|
||||||
|
CompileRuntime::addressOfProfilingActivation()
|
||||||
|
{
|
||||||
|
return (const void *) &runtime()->mainThread.profilingActivation_;
|
||||||
|
}
|
||||||
|
|
||||||
const void *
|
const void *
|
||||||
CompileRuntime::addressOfJitStackLimit()
|
CompileRuntime::addressOfJitStackLimit()
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,6 +37,9 @@ class CompileRuntime
|
||||||
// &mainThread.jitActivation
|
// &mainThread.jitActivation
|
||||||
const void *addressOfJitActivation();
|
const void *addressOfJitActivation();
|
||||||
|
|
||||||
|
// &mainThread.profilingActivation
|
||||||
|
const void *addressOfProfilingActivation();
|
||||||
|
|
||||||
// rt->mainThread.jitStackLimit;
|
// rt->mainThread.jitStackLimit;
|
||||||
const void *addressOfJitStackLimit();
|
const void *addressOfJitStackLimit();
|
||||||
|
|
||||||
|
|
|
@ -153,6 +153,7 @@ JitRuntime::JitRuntime()
|
||||||
ionAlloc_(nullptr),
|
ionAlloc_(nullptr),
|
||||||
exceptionTail_(nullptr),
|
exceptionTail_(nullptr),
|
||||||
bailoutTail_(nullptr),
|
bailoutTail_(nullptr),
|
||||||
|
profilerExitFrameTail_(nullptr),
|
||||||
enterJIT_(nullptr),
|
enterJIT_(nullptr),
|
||||||
bailoutHandler_(nullptr),
|
bailoutHandler_(nullptr),
|
||||||
argumentsRectifier_(nullptr),
|
argumentsRectifier_(nullptr),
|
||||||
|
@ -202,6 +203,11 @@ JitRuntime::initialize(JSContext *cx)
|
||||||
if (!functionWrappers_ || !functionWrappers_->init())
|
if (!functionWrappers_ || !functionWrappers_->init())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
JitSpew(JitSpew_Codegen, "# Emitting profiler exit frame tail stub");
|
||||||
|
profilerExitFrameTail_ = generateProfilerExitFrameTailStub(cx);
|
||||||
|
if (!profilerExitFrameTail_)
|
||||||
|
return false;
|
||||||
|
|
||||||
JitSpew(JitSpew_Codegen, "# Emitting exception tail stub");
|
JitSpew(JitSpew_Codegen, "# Emitting exception tail stub");
|
||||||
|
|
||||||
void *handler = JS_FUNC_TO_DATA_PTR(void *, jit::HandleException);
|
void *handler = JS_FUNC_TO_DATA_PTR(void *, jit::HandleException);
|
||||||
|
|
|
@ -158,6 +158,9 @@ class JitRuntime
|
||||||
// Shared post-bailout-handler tail.
|
// Shared post-bailout-handler tail.
|
||||||
JitCode *bailoutTail_;
|
JitCode *bailoutTail_;
|
||||||
|
|
||||||
|
// Shared profiler exit frame tail.
|
||||||
|
JitCode *profilerExitFrameTail_;
|
||||||
|
|
||||||
// Trampoline for entering JIT code. Contains OSR prologue.
|
// Trampoline for entering JIT code. Contains OSR prologue.
|
||||||
JitCode *enterJIT_;
|
JitCode *enterJIT_;
|
||||||
|
|
||||||
|
@ -234,6 +237,7 @@ class JitRuntime
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JitCode *generateLazyLinkStub(JSContext *cx);
|
JitCode *generateLazyLinkStub(JSContext *cx);
|
||||||
|
JitCode *generateProfilerExitFrameTailStub(JSContext *cx);
|
||||||
JitCode *generateExceptionTailStub(JSContext *cx, void *handler);
|
JitCode *generateExceptionTailStub(JSContext *cx, void *handler);
|
||||||
JitCode *generateBailoutTailStub(JSContext *cx);
|
JitCode *generateBailoutTailStub(JSContext *cx);
|
||||||
JitCode *generateEnterJIT(JSContext *cx, EnterJitType type);
|
JitCode *generateEnterJIT(JSContext *cx, EnterJitType type);
|
||||||
|
@ -323,6 +327,10 @@ class JitRuntime
|
||||||
return bailoutTail_;
|
return bailoutTail_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JitCode *getProfilerExitFrameTail() const {
|
||||||
|
return profilerExitFrameTail_;
|
||||||
|
}
|
||||||
|
|
||||||
JitCode *getBailoutTable(const FrameSizeClass &frameClass) const;
|
JitCode *getBailoutTable(const FrameSizeClass &frameClass) const;
|
||||||
|
|
||||||
JitCode *getArgumentsRectifier() const {
|
JitCode *getArgumentsRectifier() const {
|
||||||
|
|
|
@ -5022,3 +5022,18 @@ template void
|
||||||
js::jit::MacroAssemblerARMCompat::atomicFetchOp(int nbytes, bool signExtend, AtomicOp op,
|
js::jit::MacroAssemblerARMCompat::atomicFetchOp(int nbytes, bool signExtend, AtomicOp op,
|
||||||
const Register &value, const BaseIndex &mem,
|
const Register &value, const BaseIndex &mem,
|
||||||
Register temp, Register output);
|
Register temp, Register output);
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroAssemblerARMCompat::profilerEnterFrame(Register framePtr, Register scratch)
|
||||||
|
{
|
||||||
|
AbsoluteAddress activation(GetJitContext()->runtime->addressOfProfilingActivation());
|
||||||
|
loadPtr(activation, scratch);
|
||||||
|
storePtr(framePtr, Address(scratch, JitActivation::offsetOfLastProfilingFrame()));
|
||||||
|
storePtr(ImmPtr(nullptr), Address(scratch, JitActivation::offsetOfLastProfilingCallSite()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroAssemblerARMCompat::profilerExitFrame()
|
||||||
|
{
|
||||||
|
branch(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
|
||||||
|
}
|
||||||
|
|
|
@ -1838,6 +1838,10 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||||
void pushReturnAddress() {
|
void pushReturnAddress() {
|
||||||
push(lr);
|
push(lr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Instrumentation for entering and leaving the profiler.
|
||||||
|
void profilerEnterFrame(Register framePtr, Register scratch);
|
||||||
|
void profilerExitFrame();
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef MacroAssemblerARMCompat MacroAssemblerSpecific;
|
typedef MacroAssemblerARMCompat MacroAssemblerSpecific;
|
||||||
|
|
|
@ -997,3 +997,294 @@ JitRuntime::generateBailoutTailStub(JSContext *cx)
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JitCode *
|
||||||
|
JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
|
||||||
|
{
|
||||||
|
MacroAssembler masm;
|
||||||
|
|
||||||
|
Register scratch1 = r5;
|
||||||
|
Register scratch2 = r6;
|
||||||
|
Register scratch3 = r7;
|
||||||
|
Register scratch4 = r8;
|
||||||
|
|
||||||
|
//
|
||||||
|
// The code generated below expects that the current stack pointer points
|
||||||
|
// to an Ion or Baseline frame, at the state it would be immediately
|
||||||
|
// before a ret(). Thus, after this stub's business is done, it executes
|
||||||
|
// a ret() and returns directly to the caller script, on behalf of the
|
||||||
|
// callee script that jumped to this code.
|
||||||
|
//
|
||||||
|
// Thus the expected stack is:
|
||||||
|
//
|
||||||
|
// StackPointer ----+
|
||||||
|
// v
|
||||||
|
// ..., ActualArgc, CalleeToken, Descriptor, ReturnAddr
|
||||||
|
// MEM-HI MEM-LOW
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// The generated jitcode is responsible for overwriting the
|
||||||
|
// jitActivation->lastProfilingFrame field with a pointer to the previous
|
||||||
|
// Ion or Baseline jit-frame that was pushed before this one. It is also
|
||||||
|
// responsible for overwriting jitActivation->lastProfilingCallSite with
|
||||||
|
// the return address into that frame. The frame could either be an
|
||||||
|
// immediate "caller" frame, or it could be a frame in a previous
|
||||||
|
// JitActivation (if the current frame was entered from C++, and the C++
|
||||||
|
// was entered by some caller jit-frame further down the stack).
|
||||||
|
//
|
||||||
|
// So this jitcode is responsible for "walking up" the jit stack, finding
|
||||||
|
// the previous Ion or Baseline JS frame, and storing its address and the
|
||||||
|
// return address into the appropriate fields on the current jitActivation.
|
||||||
|
//
|
||||||
|
// There are a fixed number of different path types that can lead to the
|
||||||
|
// current frame, which is either a baseline or ion frame:
|
||||||
|
//
|
||||||
|
// <Baseline-Or-Ion>
|
||||||
|
// ^
|
||||||
|
// |
|
||||||
|
// ^--- Ion
|
||||||
|
// |
|
||||||
|
// ^--- Baseline Stub <---- Baseline
|
||||||
|
// |
|
||||||
|
// ^--- Argument Rectifier
|
||||||
|
// | ^
|
||||||
|
// | |
|
||||||
|
// | ^--- Ion
|
||||||
|
// | |
|
||||||
|
// | ^--- Baseline Stub <---- Baseline
|
||||||
|
// |
|
||||||
|
// ^--- Entry Frame (From C++)
|
||||||
|
//
|
||||||
|
Register actReg = scratch4;
|
||||||
|
AbsoluteAddress activationAddr(GetJitContext()->runtime->addressOfProfilingActivation());
|
||||||
|
masm.loadPtr(activationAddr, actReg);
|
||||||
|
|
||||||
|
Address lastProfilingFrame(actReg, JitActivation::offsetOfLastProfilingFrame());
|
||||||
|
Address lastProfilingCallSite(actReg, JitActivation::offsetOfLastProfilingCallSite());
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Ensure that frame we are exiting is current lastProfilingFrame
|
||||||
|
{
|
||||||
|
masm.loadPtr(lastProfilingFrame, scratch1);
|
||||||
|
Label checkOk;
|
||||||
|
masm.branchPtr(Assembler::Equal, scratch1, ImmWord(0), &checkOk);
|
||||||
|
masm.branchPtr(Assembler::Equal, StackPointer, scratch1, &checkOk);
|
||||||
|
masm.assumeUnreachable(
|
||||||
|
"Mismatch between stored lastProfilingFrame and current stack pointer.");
|
||||||
|
masm.bind(&checkOk);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Load the frame descriptor into |scratch1|, figure out what to do depending on its type.
|
||||||
|
masm.loadPtr(Address(StackPointer, JitFrameLayout::offsetOfDescriptor()), scratch1);
|
||||||
|
|
||||||
|
// Going into the conditionals, we will have:
|
||||||
|
// FrameDescriptor.size in scratch1
|
||||||
|
// FrameDescriptor.type in scratch2
|
||||||
|
masm.ma_and(Imm32((1 << FRAMESIZE_SHIFT) - 1), scratch1, scratch2);
|
||||||
|
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch1);
|
||||||
|
|
||||||
|
// Handling of each case is dependent on FrameDescriptor.type
|
||||||
|
Label handle_IonJS;
|
||||||
|
Label handle_BaselineStub;
|
||||||
|
Label handle_Rectifier;
|
||||||
|
Label handle_Entry;
|
||||||
|
Label end;
|
||||||
|
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_IonJS), &handle_IonJS);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineJS), &handle_IonJS);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineStub), &handle_BaselineStub);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Rectifier), &handle_Rectifier);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Entry), &handle_Entry);
|
||||||
|
|
||||||
|
masm.assumeUnreachable("Invalid caller frame type when exiting from Ion frame.");
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_IonJS
|
||||||
|
//
|
||||||
|
// Stack layout:
|
||||||
|
// ...
|
||||||
|
// Ion-Descriptor
|
||||||
|
// Prev-FP ---> Ion-ReturnAddr
|
||||||
|
// ... previous frame data ... |- Descriptor.Size
|
||||||
|
// ... arguments ... |
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- JitFrameLayout::Size()
|
||||||
|
// Descriptor |
|
||||||
|
// FP -----> ReturnAddr |
|
||||||
|
//
|
||||||
|
masm.bind(&handle_IonJS);
|
||||||
|
{
|
||||||
|
// |scratch1| contains Descriptor.size
|
||||||
|
|
||||||
|
// returning directly to an IonJS frame. Store return addr to frame
|
||||||
|
// in lastProfilingCallSite.
|
||||||
|
masm.loadPtr(Address(StackPointer, JitFrameLayout::offsetOfReturnAddress()), scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingCallSite);
|
||||||
|
|
||||||
|
// Store return frame in lastProfilingFrame.
|
||||||
|
// scratch2 := StackPointer + Descriptor.size*1 + JitFrameLayout::Size();
|
||||||
|
masm.ma_add(StackPointer, scratch1, scratch2);
|
||||||
|
masm.ma_add(scratch2, Imm32(JitFrameLayout::Size()), scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_BaselineStub
|
||||||
|
//
|
||||||
|
// Look past the stub and store the frame pointer to
|
||||||
|
// the baselineJS frame prior to it.
|
||||||
|
//
|
||||||
|
// Stack layout:
|
||||||
|
// ...
|
||||||
|
// BL-Descriptor
|
||||||
|
// Prev-FP ---> BL-ReturnAddr
|
||||||
|
// +-----> BL-PrevFramePointer
|
||||||
|
// | ... BL-FrameData ...
|
||||||
|
// | BLStub-Descriptor
|
||||||
|
// | BLStub-ReturnAddr
|
||||||
|
// | BLStub-StubPointer |
|
||||||
|
// +------ BLStub-SavedFramePointer |- Descriptor.Size
|
||||||
|
// ... arguments ... |
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- JitFrameLayout::Size()
|
||||||
|
// Descriptor |
|
||||||
|
// FP -----> ReturnAddr |
|
||||||
|
//
|
||||||
|
// We take advantage of the fact that the stub frame saves the frame
|
||||||
|
// pointer pointing to the baseline frame, so a bunch of calculation can
|
||||||
|
// be avoided.
|
||||||
|
//
|
||||||
|
masm.bind(&handle_BaselineStub);
|
||||||
|
{
|
||||||
|
masm.ma_add(StackPointer, scratch1, scratch3);
|
||||||
|
Address stubFrameReturnAddr(scratch3,
|
||||||
|
JitFrameLayout::Size() +
|
||||||
|
BaselineStubFrameLayout::offsetOfReturnAddress());
|
||||||
|
masm.loadPtr(stubFrameReturnAddr, scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingCallSite);
|
||||||
|
|
||||||
|
Address stubFrameSavedFramePtr(scratch3,
|
||||||
|
JitFrameLayout::Size() - (2 * sizeof(void *)));
|
||||||
|
masm.loadPtr(stubFrameSavedFramePtr, scratch2);
|
||||||
|
masm.addPtr(Imm32(sizeof(void *)), scratch2); // Skip past BL-PrevFramePtr
|
||||||
|
masm.storePtr(scratch2, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_Rectifier
|
||||||
|
//
|
||||||
|
// The rectifier frame can be preceded by either an IonJS or a
|
||||||
|
// BaselineStub frame.
|
||||||
|
//
|
||||||
|
// Stack layout if caller of rectifier was Ion:
|
||||||
|
//
|
||||||
|
// Ion-Descriptor
|
||||||
|
// Ion-ReturnAddr
|
||||||
|
// ... ion frame data ... |- Rect-Descriptor.Size
|
||||||
|
// < COMMON LAYOUT >
|
||||||
|
//
|
||||||
|
// Stack layout if caller of rectifier was Baseline:
|
||||||
|
//
|
||||||
|
// BL-Descriptor
|
||||||
|
// Prev-FP ---> BL-ReturnAddr
|
||||||
|
// +-----> BL-SavedFramePointer
|
||||||
|
// | ... baseline frame data ...
|
||||||
|
// | BLStub-Descriptor
|
||||||
|
// | BLStub-ReturnAddr
|
||||||
|
// | BLStub-StubPointer |
|
||||||
|
// +------ BLStub-SavedFramePointer |- Rect-Descriptor.Size
|
||||||
|
// ... args to rectifier ... |
|
||||||
|
// < COMMON LAYOUT >
|
||||||
|
//
|
||||||
|
// Common stack layout:
|
||||||
|
//
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- IonRectitiferFrameLayout::Size()
|
||||||
|
// Rect-Descriptor |
|
||||||
|
// Rect-ReturnAddr |
|
||||||
|
// ... rectifier data & args ... |- Descriptor.Size
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- JitFrameLayout::Size()
|
||||||
|
// Descriptor |
|
||||||
|
// FP -----> ReturnAddr |
|
||||||
|
//
|
||||||
|
masm.bind(&handle_Rectifier);
|
||||||
|
{
|
||||||
|
// scratch2 := StackPointer + Descriptor.size*1 + JitFrameLayout::Size();
|
||||||
|
masm.ma_add(StackPointer, scratch1, scratch2);
|
||||||
|
masm.add32(Imm32(JitFrameLayout::Size()), scratch2);
|
||||||
|
masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfDescriptor()), scratch3);
|
||||||
|
masm.ma_lsr(Imm32(FRAMESIZE_SHIFT), scratch3, scratch1);
|
||||||
|
masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch3);
|
||||||
|
|
||||||
|
// Now |scratch1| contains Rect-Descriptor.Size
|
||||||
|
// and |scratch2| points to Rectifier frame
|
||||||
|
// and |scratch3| contains Rect-Descriptor.Type
|
||||||
|
|
||||||
|
// Check for either Ion or BaselineStub frame.
|
||||||
|
Label handle_Rectifier_BaselineStub;
|
||||||
|
masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS),
|
||||||
|
&handle_Rectifier_BaselineStub);
|
||||||
|
|
||||||
|
// Handle Rectifier <- IonJS
|
||||||
|
// scratch3 := RectFrame[ReturnAddr]
|
||||||
|
masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfReturnAddress()), scratch3);
|
||||||
|
masm.storePtr(scratch3, lastProfilingCallSite);
|
||||||
|
|
||||||
|
// scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size()
|
||||||
|
masm.ma_add(scratch2, scratch1, scratch3);
|
||||||
|
masm.add32(Imm32(RectifierFrameLayout::Size()), scratch3);
|
||||||
|
masm.storePtr(scratch3, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
|
||||||
|
// Handle Rectifier <- BaselineStub <- BaselineJS
|
||||||
|
masm.bind(&handle_Rectifier_BaselineStub);
|
||||||
|
#ifdef DEBUG
|
||||||
|
{
|
||||||
|
Label checkOk;
|
||||||
|
masm.branch32(Assembler::Equal, scratch3, Imm32(JitFrame_BaselineStub), &checkOk);
|
||||||
|
masm.assumeUnreachable("Unrecognized frame preceding baselineStub.");
|
||||||
|
masm.bind(&checkOk);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
masm.ma_add(scratch2, scratch1, scratch3);
|
||||||
|
Address stubFrameReturnAddr(scratch3, RectifierFrameLayout::Size() +
|
||||||
|
BaselineStubFrameLayout::offsetOfReturnAddress());
|
||||||
|
masm.loadPtr(stubFrameReturnAddr, scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingCallSite);
|
||||||
|
|
||||||
|
Address stubFrameSavedFramePtr(scratch3,
|
||||||
|
RectifierFrameLayout::Size() - (2 * sizeof(void *)));
|
||||||
|
masm.loadPtr(stubFrameSavedFramePtr, scratch2);
|
||||||
|
masm.addPtr(Imm32(sizeof(void *)), scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_Entry
|
||||||
|
//
|
||||||
|
// If at an entry frame, store null into both fields.
|
||||||
|
//
|
||||||
|
masm.bind(&handle_Entry);
|
||||||
|
{
|
||||||
|
masm.movePtr(ImmPtr(nullptr), scratch1);
|
||||||
|
masm.storePtr(scratch1, lastProfilingCallSite);
|
||||||
|
masm.storePtr(scratch1, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
Linker linker(masm);
|
||||||
|
AutoFlushICache afc("ProfilerExitFrameTailStub");
|
||||||
|
JitCode *code = linker.newCode<NoGC>(cx, OTHER_CODE);
|
||||||
|
|
||||||
|
#ifdef JS_ION_PERF
|
||||||
|
writePerfSpewerJitCodeProfile(code, "ProfilerExitFrameStub");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
|
@ -3669,3 +3669,18 @@ MacroAssemblerMIPSCompat::branchValueIsNurseryObject(Condition cond, ValueOperan
|
||||||
|
|
||||||
bind(&done);
|
bind(&done);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroAssemblerMIPSCompat::profilerEnterFrame(Register reg)
|
||||||
|
{
|
||||||
|
AbsoluteAddress activation(GetJitContext()->runtime->addressOfProfilingActivation());
|
||||||
|
loadPtr(activation, scratch);
|
||||||
|
storePtr(framePtr, Address(scratch, JitActivation::offsetOfLastProfilingFrame()));
|
||||||
|
storePtr(ImmPtr(nullptr), Address(scratch, JitActivation::offsetOfLastProfilingCallSite()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroAssemblerMIPSCompat::profilerExitFrame()
|
||||||
|
{
|
||||||
|
branch(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
|
||||||
|
}
|
||||||
|
|
|
@ -1470,6 +1470,10 @@ public:
|
||||||
MOZ_ASSERT(Imm16::IsInSignedRange(AsmJSHeapGlobalDataOffset - AsmJSGlobalRegBias));
|
MOZ_ASSERT(Imm16::IsInSignedRange(AsmJSHeapGlobalDataOffset - AsmJSGlobalRegBias));
|
||||||
loadPtr(Address(GlobalReg, AsmJSHeapGlobalDataOffset - AsmJSGlobalRegBias), HeapReg);
|
loadPtr(Address(GlobalReg, AsmJSHeapGlobalDataOffset - AsmJSGlobalRegBias), HeapReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Instrumentation for entering and leaving the profiler.
|
||||||
|
void profilerEnterFrame(Register framePtr, Register scratch);
|
||||||
|
void profilerExitFrame();
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef MacroAssemblerMIPSCompat MacroAssemblerSpecific;
|
typedef MacroAssemblerMIPSCompat MacroAssemblerSpecific;
|
||||||
|
|
|
@ -1002,3 +1002,293 @@ JitRuntime::generateBailoutTailStub(JSContext *cx)
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JitCode *
|
||||||
|
JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
|
||||||
|
{
|
||||||
|
MacroAssembler masm;
|
||||||
|
|
||||||
|
Register scratch1 = t0;
|
||||||
|
Register scratch2 = t1;
|
||||||
|
Register scratch3 = t2;
|
||||||
|
Register scratch3 = t3;
|
||||||
|
|
||||||
|
//
|
||||||
|
// The code generated below expects that the current stack pointer points
|
||||||
|
// to an Ion or Baseline frame, at the state it would be immediately
|
||||||
|
// before a ret(). Thus, after this stub's business is done, it executes
|
||||||
|
// a ret() and returns directly to the caller script, on behalf of the
|
||||||
|
// callee script that jumped to this code.
|
||||||
|
//
|
||||||
|
// Thus the expected stack is:
|
||||||
|
//
|
||||||
|
// StackPointer ----+
|
||||||
|
// v
|
||||||
|
// ..., ActualArgc, CalleeToken, Descriptor, ReturnAddr
|
||||||
|
// MEM-HI MEM-LOW
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// The generated jitcode is responsible for overwriting the
|
||||||
|
// jitActivation->lastProfilingFrame field with a pointer to the previous
|
||||||
|
// Ion or Baseline jit-frame that was pushed before this one. It is also
|
||||||
|
// responsible for overwriting jitActivation->lastProfilingCallSite with
|
||||||
|
// the return address into that frame. The frame could either be an
|
||||||
|
// immediate "caller" frame, or it could be a frame in a previous
|
||||||
|
// JitActivation (if the current frame was entered from C++, and the C++
|
||||||
|
// was entered by some caller jit-frame further down the stack).
|
||||||
|
//
|
||||||
|
// So this jitcode is responsible for "walking up" the jit stack, finding
|
||||||
|
// the previous Ion or Baseline JS frame, and storing its address and the
|
||||||
|
// return address into the appropriate fields on the current jitActivation.
|
||||||
|
//
|
||||||
|
// There are a fixed number of different path types that can lead to the
|
||||||
|
// current frame, which is either a baseline or ion frame:
|
||||||
|
//
|
||||||
|
// <Baseline-Or-Ion>
|
||||||
|
// ^
|
||||||
|
// |
|
||||||
|
// ^--- Ion
|
||||||
|
// |
|
||||||
|
// ^--- Baseline Stub <---- Baseline
|
||||||
|
// |
|
||||||
|
// ^--- Argument Rectifier
|
||||||
|
// | ^
|
||||||
|
// | |
|
||||||
|
// | ^--- Ion
|
||||||
|
// | |
|
||||||
|
// | ^--- Baseline Stub <---- Baseline
|
||||||
|
// |
|
||||||
|
// ^--- Entry Frame (From C++)
|
||||||
|
//
|
||||||
|
Register actReg = scratch4;
|
||||||
|
AbsoluteAddress activationAddr(GetJitContext()->runtime->addressOfProfilingActivation());
|
||||||
|
masm.loadPtr(activationAddr, actReg);
|
||||||
|
|
||||||
|
Address lastProfilingFrame(actReg, JitActivation::offsetOfLastProfilingFrame());
|
||||||
|
Address lastProfilingCallSite(actReg, JitActivation::offsetOfLastProfilingCallSite());
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Ensure that frame we are exiting is current lastProfilingFrame
|
||||||
|
{
|
||||||
|
masm.loadPtr(lastProfilingFrame, scratch1);
|
||||||
|
Label checkOk;
|
||||||
|
masm.branchPtr(Assembler::Equal, scratch1, ImmWord(0), &checkOk);
|
||||||
|
masm.branchPtr(Assembler::Equal, StackPointer, scratch1, &checkOk);
|
||||||
|
masm.assumeUnreachable(
|
||||||
|
"Mismatch between stored lastProfilingFrame and current stack pointer.");
|
||||||
|
masm.bind(&checkOk);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Load the frame descriptor into |scratch1|, figure out what to do depending on its type.
|
||||||
|
masm.loadPtr(Address(StackPointer, JitFrameLayout::offsetOfDescriptor()), scratch1);
|
||||||
|
|
||||||
|
// Going into the conditionals, we will have:
|
||||||
|
// FrameDescriptor.size in scratch1
|
||||||
|
// FrameDescriptor.type in scratch2
|
||||||
|
masm.ma_and(scratch2, scratch1, Imm32((1 << FRAMESIZE_SHIFT) - 1));
|
||||||
|
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch1);
|
||||||
|
|
||||||
|
// Handling of each case is dependent on FrameDescriptor.type
|
||||||
|
Label handle_IonJS;
|
||||||
|
Label handle_BaselineStub;
|
||||||
|
Label handle_Rectifier;
|
||||||
|
Label handle_Entry;
|
||||||
|
Label end;
|
||||||
|
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_IonJS), &handle_IonJS);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineJS), &handle_IonJS);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineStub), &handle_BaselineStub);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Rectifier), &handle_Rectifier);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Entry), &handle_Entry);
|
||||||
|
|
||||||
|
masm.assumeUnreachable("Invalid caller frame type when exiting from Ion frame.");
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_IonJS
|
||||||
|
//
|
||||||
|
// Stack layout:
|
||||||
|
// ...
|
||||||
|
// Ion-Descriptor
|
||||||
|
// Prev-FP ---> Ion-ReturnAddr
|
||||||
|
// ... previous frame data ... |- Descriptor.Size
|
||||||
|
// ... arguments ... |
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- JitFrameLayout::Size()
|
||||||
|
// Descriptor |
|
||||||
|
// FP -----> ReturnAddr |
|
||||||
|
//
|
||||||
|
masm.bind(&handle_IonJS);
|
||||||
|
{
|
||||||
|
// |scratch1| contains Descriptor.size
|
||||||
|
|
||||||
|
// returning directly to an IonJS frame. Store return addr to frame
|
||||||
|
// in lastProfilingCallSite.
|
||||||
|
masm.loadPtr(Address(StackPointer, JitFrameLayout::offsetOfReturnAddress()), scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingCallSite);
|
||||||
|
|
||||||
|
// Store return frame in lastProfilingFrame.
|
||||||
|
// scratch2 := StackPointer + Descriptor.size*1 + JitFrameLayout::Size();
|
||||||
|
masm.ma_add(scratch2, StackPointer, scratch1);
|
||||||
|
masm.ma_add(scratch2, scratch2, Imm32(JitFrameLayout::Size()));
|
||||||
|
masm.storePtr(scratch2, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_BaselineStub
|
||||||
|
//
|
||||||
|
// Look past the stub and store the frame pointer to
|
||||||
|
// the baselineJS frame prior to it.
|
||||||
|
//
|
||||||
|
// Stack layout:
|
||||||
|
// ...
|
||||||
|
// BL-Descriptor
|
||||||
|
// Prev-FP ---> BL-ReturnAddr
|
||||||
|
// +-----> BL-PrevFramePointer
|
||||||
|
// | ... BL-FrameData ...
|
||||||
|
// | BLStub-Descriptor
|
||||||
|
// | BLStub-ReturnAddr
|
||||||
|
// | BLStub-StubPointer |
|
||||||
|
// +------ BLStub-SavedFramePointer |- Descriptor.Size
|
||||||
|
// ... arguments ... |
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- JitFrameLayout::Size()
|
||||||
|
// Descriptor |
|
||||||
|
// FP -----> ReturnAddr |
|
||||||
|
//
|
||||||
|
// We take advantage of the fact that the stub frame saves the frame
|
||||||
|
// pointer pointing to the baseline frame, so a bunch of calculation can
|
||||||
|
// be avoided.
|
||||||
|
//
|
||||||
|
masm.bind(&handle_BaselineStub);
|
||||||
|
{
|
||||||
|
masm.ma_add(scratch3, StackPointer, scratch1);
|
||||||
|
Address stubFrameReturnAddr(scratch3,
|
||||||
|
JitFrameLayout::Size() +
|
||||||
|
BaselineStubFrameLayout::offsetOfReturnAddress());
|
||||||
|
masm.loadPtr(stubFrameReturnAddr, scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingCallSite);
|
||||||
|
|
||||||
|
Address stubFrameSavedFramePtr(scratch3,
|
||||||
|
JitFrameLayout::Size() - (2 * sizeof(void *)));
|
||||||
|
masm.loadPtr(stubFrameSavedFramePtr, scratch2);
|
||||||
|
masm.addPtr(Imm32(sizeof(void *)), scratch2); // Skip past BL-PrevFramePtr
|
||||||
|
masm.storePtr(scratch2, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_Rectifier
|
||||||
|
//
|
||||||
|
// The rectifier frame can be preceded by either an IonJS or a
|
||||||
|
// BaselineStub frame.
|
||||||
|
//
|
||||||
|
// Stack layout if caller of rectifier was Ion:
|
||||||
|
//
|
||||||
|
// Ion-Descriptor
|
||||||
|
// Ion-ReturnAddr
|
||||||
|
// ... ion frame data ... |- Rect-Descriptor.Size
|
||||||
|
// < COMMON LAYOUT >
|
||||||
|
//
|
||||||
|
// Stack layout if caller of rectifier was Baseline:
|
||||||
|
//
|
||||||
|
// BL-Descriptor
|
||||||
|
// Prev-FP ---> BL-ReturnAddr
|
||||||
|
// +-----> BL-SavedFramePointer
|
||||||
|
// | ... baseline frame data ...
|
||||||
|
// | BLStub-Descriptor
|
||||||
|
// | BLStub-ReturnAddr
|
||||||
|
// | BLStub-StubPointer |
|
||||||
|
// +------ BLStub-SavedFramePointer |- Rect-Descriptor.Size
|
||||||
|
// ... args to rectifier ... |
|
||||||
|
// < COMMON LAYOUT >
|
||||||
|
//
|
||||||
|
// Common stack layout:
|
||||||
|
//
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- IonRectitiferFrameLayout::Size()
|
||||||
|
// Rect-Descriptor |
|
||||||
|
// Rect-ReturnAddr |
|
||||||
|
// ... rectifier data & args ... |- Descriptor.Size
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- JitFrameLayout::Size()
|
||||||
|
// Descriptor |
|
||||||
|
// FP -----> ReturnAddr |
|
||||||
|
//
|
||||||
|
masm.bind(&handle_Rectifier);
|
||||||
|
{
|
||||||
|
// scratch2 := StackPointer + Descriptor.size*1 + JitFrameLayout::Size();
|
||||||
|
masm.ma_add(scratch2, StackPointer, scratch1);
|
||||||
|
masm.add32(Imm32(JitFrameLayout::Size()), scratch2);
|
||||||
|
masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfDescriptor()), scratch3);
|
||||||
|
masm.ma_lsr(scratch1, scratch3, Imm32(FRAMESIZE_SHIFT));
|
||||||
|
masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch3);
|
||||||
|
|
||||||
|
// Now |scratch1| contains Rect-Descriptor.Size
|
||||||
|
// and |scratch2| points to Rectifier frame
|
||||||
|
// and |scratch3| contains Rect-Descriptor.Type
|
||||||
|
|
||||||
|
// Check for either Ion or BaselineStub frame.
|
||||||
|
Label handle_Rectifier_BaselineStub;
|
||||||
|
masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS),
|
||||||
|
&handle_Rectifier_BaselineStub);
|
||||||
|
|
||||||
|
// Handle Rectifier <- IonJS
|
||||||
|
// scratch3 := RectFrame[ReturnAddr]
|
||||||
|
masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfReturnAddress()), scratch3);
|
||||||
|
masm.storePtr(scratch3, lastProfilingCallSite);
|
||||||
|
|
||||||
|
// scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size()
|
||||||
|
masm.ma_add(scratch3, scratch2, scratch1);
|
||||||
|
masm.add32(Imm32(RectifierFrameLayout::Size()), scratch3);
|
||||||
|
masm.storePtr(scratch3, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
|
||||||
|
// Handle Rectifier <- BaselineStub <- BaselineJS
|
||||||
|
masm.bind(&handle_Rectifier_BaselineStub);
|
||||||
|
#ifdef DEBUG
|
||||||
|
{
|
||||||
|
Label checkOk;
|
||||||
|
masm.branch32(Assembler::Equal, scratch3, Imm32(JitFrame_BaselineStub), &checkOk);
|
||||||
|
masm.assumeUnreachable("Unrecognized frame preceding baselineStub.");
|
||||||
|
masm.bind(&checkOk);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
masm.ma_add(scratch3, scratch2, scratch1);
|
||||||
|
Address stubFrameReturnAddr(scratch3, RectifierFrameLayout::Size() +
|
||||||
|
BaselineStubFrameLayout::offsetOfReturnAddress());
|
||||||
|
masm.loadPtr(stubFrameReturnAddr, scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingCallSite);
|
||||||
|
|
||||||
|
Address stubFrameSavedFramePtr(scratch3,
|
||||||
|
RectifierFrameLayout::Size() - (2 * sizeof(void *)));
|
||||||
|
masm.loadPtr(stubFrameSavedFramePtr, scratch2);
|
||||||
|
masm.addPtr(Imm32(sizeof(void *)), scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_Entry
|
||||||
|
//
|
||||||
|
// If at an entry frame, store null into both fields.
|
||||||
|
//
|
||||||
|
masm.bind(&handle_Entry);
|
||||||
|
{
|
||||||
|
masm.movePtr(ImmPtr(nullptr), scratch1);
|
||||||
|
masm.storePtr(scratch1, lastProfilingCallSite);
|
||||||
|
masm.storePtr(scratch1, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
Linker linker(masm);
|
||||||
|
AutoFlushICache afc("ProfilerExitFrameTailStub");
|
||||||
|
JitCode *code = linker.newCode<NoGC>(cx, OTHER_CODE);
|
||||||
|
|
||||||
|
#ifdef JS_ION_PERF
|
||||||
|
writePerfSpewerJitCodeProfile(code, "ProfilerExitFrameStub");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
|
@ -519,3 +519,18 @@ MacroAssemblerX64::branchValueIsNurseryObject(Condition cond, ValueOperand value
|
||||||
branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
|
branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
|
||||||
ScratchReg, Imm32(nursery.nurserySize()), label);
|
ScratchReg, Imm32(nursery.nurserySize()), label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroAssemblerX64::profilerEnterFrame(Register framePtr, Register scratch)
|
||||||
|
{
|
||||||
|
AbsoluteAddress activation(GetJitContext()->runtime->addressOfProfilingActivation());
|
||||||
|
loadPtr(activation, scratch);
|
||||||
|
storePtr(framePtr, Address(scratch, JitActivation::offsetOfLastProfilingFrame()));
|
||||||
|
storePtr(ImmPtr(nullptr), Address(scratch, JitActivation::offsetOfLastProfilingCallSite()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroAssemblerX64::profilerExitFrame()
|
||||||
|
{
|
||||||
|
jmp(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
|
||||||
|
}
|
||||||
|
|
|
@ -1445,6 +1445,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||||
|
|
||||||
void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label);
|
void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label);
|
||||||
void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label *label);
|
void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label *label);
|
||||||
|
|
||||||
|
// Instrumentation for entering and leaving the profiler.
|
||||||
|
void profilerEnterFrame(Register framePtr, Register scratch);
|
||||||
|
void profilerExitFrame();
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef MacroAssemblerX64 MacroAssemblerSpecific;
|
typedef MacroAssemblerX64 MacroAssemblerSpecific;
|
||||||
|
|
|
@ -820,3 +820,289 @@ JitRuntime::generateBailoutTailStub(JSContext *cx)
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JitCode *
|
||||||
|
JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
|
||||||
|
{
|
||||||
|
MacroAssembler masm;
|
||||||
|
|
||||||
|
Register scratch1 = r8;
|
||||||
|
Register scratch2 = r9;
|
||||||
|
Register scratch3 = r10;
|
||||||
|
Register scratch4 = r11;
|
||||||
|
|
||||||
|
//
|
||||||
|
// The code generated below expects that the current stack pointer points
|
||||||
|
// to an Ion or Baseline frame, at the state it would be immediately
|
||||||
|
// before a ret(). Thus, after this stub's business is done, it executes
|
||||||
|
// a ret() and returns directly to the caller script, on behalf of the
|
||||||
|
// callee script that jumped to this code.
|
||||||
|
//
|
||||||
|
// Thus the expected stack is:
|
||||||
|
//
|
||||||
|
// StackPointer ----+
|
||||||
|
// v
|
||||||
|
// ..., ActualArgc, CalleeToken, Descriptor, ReturnAddr
|
||||||
|
// MEM-HI MEM-LOW
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// The generated jitcode is responsible for overwriting the
|
||||||
|
// jitActivation->lastProfilingFrame field with a pointer to the previous
|
||||||
|
// Ion or Baseline jit-frame that was pushed before this one. It is also
|
||||||
|
// responsible for overwriting jitActivation->lastProfilingCallSite with
|
||||||
|
// the return address into that frame. The frame could either be an
|
||||||
|
// immediate "caller" frame, or it could be a frame in a previous
|
||||||
|
// JitActivation (if the current frame was entered from C++, and the C++
|
||||||
|
// was entered by some caller jit-frame further down the stack).
|
||||||
|
//
|
||||||
|
// So this jitcode is responsible for "walking up" the jit stack, finding
|
||||||
|
// the previous Ion or Baseline JS frame, and storing its address and the
|
||||||
|
// return address into the appropriate fields on the current jitActivation.
|
||||||
|
//
|
||||||
|
// There are a fixed number of different path types that can lead to the
|
||||||
|
// current frame, which is either a baseline or ion frame:
|
||||||
|
//
|
||||||
|
// <Baseline-Or-Ion>
|
||||||
|
// ^
|
||||||
|
// |
|
||||||
|
// ^--- Ion
|
||||||
|
// |
|
||||||
|
// ^--- Baseline Stub <---- Baseline
|
||||||
|
// |
|
||||||
|
// ^--- Argument Rectifier
|
||||||
|
// | ^
|
||||||
|
// | |
|
||||||
|
// | ^--- Ion
|
||||||
|
// | |
|
||||||
|
// | ^--- Baseline Stub <---- Baseline
|
||||||
|
// |
|
||||||
|
// ^--- Entry Frame (From C++)
|
||||||
|
//
|
||||||
|
Register actReg = scratch4;
|
||||||
|
AbsoluteAddress activationAddr(GetJitContext()->runtime->addressOfProfilingActivation());
|
||||||
|
masm.loadPtr(activationAddr, actReg);
|
||||||
|
|
||||||
|
Address lastProfilingFrame(actReg, JitActivation::offsetOfLastProfilingFrame());
|
||||||
|
Address lastProfilingCallSite(actReg, JitActivation::offsetOfLastProfilingCallSite());
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Ensure that frame we are exiting is current lastProfilingFrame
|
||||||
|
{
|
||||||
|
masm.loadPtr(lastProfilingFrame, scratch1);
|
||||||
|
Label checkOk;
|
||||||
|
masm.branchPtr(Assembler::Equal, scratch1, ImmWord(0), &checkOk);
|
||||||
|
masm.branchPtr(Assembler::Equal, StackPointer, scratch1, &checkOk);
|
||||||
|
masm.assumeUnreachable(
|
||||||
|
"Mismatch between stored lastProfilingFrame and current stack pointer.");
|
||||||
|
masm.bind(&checkOk);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Load the frame descriptor into |scratch1|, figure out what to do depending on its type.
|
||||||
|
masm.loadPtr(Address(StackPointer, JitFrameLayout::offsetOfDescriptor()), scratch1);
|
||||||
|
|
||||||
|
// Going into the conditionals, we will have:
|
||||||
|
// FrameDescriptor.size in scratch1
|
||||||
|
// FrameDescriptor.type in scratch2
|
||||||
|
masm.movePtr(scratch1, scratch2);
|
||||||
|
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch1);
|
||||||
|
masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch2);
|
||||||
|
|
||||||
|
// Handling of each case is dependent on FrameDescriptor.type
|
||||||
|
Label handle_IonJS;
|
||||||
|
Label handle_BaselineStub;
|
||||||
|
Label handle_Rectifier;
|
||||||
|
Label handle_Entry;
|
||||||
|
Label end;
|
||||||
|
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_IonJS), &handle_IonJS);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineJS), &handle_IonJS);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineStub), &handle_BaselineStub);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Rectifier), &handle_Rectifier);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Entry), &handle_Entry);
|
||||||
|
|
||||||
|
masm.assumeUnreachable("Invalid caller frame type when exiting from Ion frame.");
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_IonJS
|
||||||
|
//
|
||||||
|
// Stack layout:
|
||||||
|
// ...
|
||||||
|
// Ion-Descriptor
|
||||||
|
// Prev-FP ---> Ion-ReturnAddr
|
||||||
|
// ... previous frame data ... |- Descriptor.Size
|
||||||
|
// ... arguments ... |
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- JitFrameLayout::Size()
|
||||||
|
// Descriptor |
|
||||||
|
// FP -----> ReturnAddr |
|
||||||
|
//
|
||||||
|
masm.bind(&handle_IonJS);
|
||||||
|
{
|
||||||
|
// returning directly to an IonJS frame. Store return addr to frame
|
||||||
|
// in lastProfilingCallSite.
|
||||||
|
masm.loadPtr(Address(StackPointer, JitFrameLayout::offsetOfReturnAddress()), scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingCallSite);
|
||||||
|
|
||||||
|
// Store return frame in lastProfilingFrame.
|
||||||
|
// scratch2 := StackPointer + Descriptor.size*1 + JitFrameLayout::Size();
|
||||||
|
masm.lea(Operand(StackPointer, scratch1, TimesOne, JitFrameLayout::Size()), scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_BaselineStub
|
||||||
|
//
|
||||||
|
// Look past the stub and store the frame pointer to
|
||||||
|
// the baselineJS frame prior to it.
|
||||||
|
//
|
||||||
|
// Stack layout:
|
||||||
|
// ...
|
||||||
|
// BL-Descriptor
|
||||||
|
// Prev-FP ---> BL-ReturnAddr
|
||||||
|
// +-----> BL-PrevFramePointer
|
||||||
|
// | ... BL-FrameData ...
|
||||||
|
// | BLStub-Descriptor
|
||||||
|
// | BLStub-ReturnAddr
|
||||||
|
// | BLStub-StubPointer |
|
||||||
|
// +------ BLStub-SavedFramePointer |- Descriptor.Size
|
||||||
|
// ... arguments ... |
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- JitFrameLayout::Size()
|
||||||
|
// Descriptor |
|
||||||
|
// FP -----> ReturnAddr |
|
||||||
|
//
|
||||||
|
// We take advantage of the fact that the stub frame saves the frame
|
||||||
|
// pointer pointing to the baseline frame, so a bunch of calculation can
|
||||||
|
// be avoided.
|
||||||
|
//
|
||||||
|
masm.bind(&handle_BaselineStub);
|
||||||
|
{
|
||||||
|
BaseIndex stubFrameReturnAddr(StackPointer, scratch1, TimesOne,
|
||||||
|
JitFrameLayout::Size() +
|
||||||
|
BaselineStubFrameLayout::offsetOfReturnAddress());
|
||||||
|
masm.loadPtr(stubFrameReturnAddr, scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingCallSite);
|
||||||
|
|
||||||
|
BaseIndex stubFrameSavedFramePtr(StackPointer, scratch1, TimesOne,
|
||||||
|
JitFrameLayout::Size() - (2 * sizeof(void *)));
|
||||||
|
masm.loadPtr(stubFrameSavedFramePtr, scratch2);
|
||||||
|
masm.addPtr(Imm32(sizeof(void *)), scratch2); // Skip past BL-PrevFramePtr
|
||||||
|
masm.storePtr(scratch2, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_Rectifier
|
||||||
|
//
|
||||||
|
// The rectifier frame can be preceded by either an IonJS or a
|
||||||
|
// BaselineStub frame.
|
||||||
|
//
|
||||||
|
// Stack layout if caller of rectifier was Ion:
|
||||||
|
//
|
||||||
|
// Ion-Descriptor
|
||||||
|
// Ion-ReturnAddr
|
||||||
|
// ... ion frame data ... |- Rect-Descriptor.Size
|
||||||
|
// < COMMON LAYOUT >
|
||||||
|
//
|
||||||
|
// Stack layout if caller of rectifier was Baseline:
|
||||||
|
//
|
||||||
|
// BL-Descriptor
|
||||||
|
// Prev-FP ---> BL-ReturnAddr
|
||||||
|
// +-----> BL-SavedFramePointer
|
||||||
|
// | ... baseline frame data ...
|
||||||
|
// | BLStub-Descriptor
|
||||||
|
// | BLStub-ReturnAddr
|
||||||
|
// | BLStub-StubPointer |
|
||||||
|
// +------ BLStub-SavedFramePointer |- Rect-Descriptor.Size
|
||||||
|
// ... args to rectifier ... |
|
||||||
|
// < COMMON LAYOUT >
|
||||||
|
//
|
||||||
|
// Common stack layout:
|
||||||
|
//
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- IonRectitiferFrameLayout::Size()
|
||||||
|
// Rect-Descriptor |
|
||||||
|
// Rect-ReturnAddr |
|
||||||
|
// ... rectifier data & args ... |- Descriptor.Size
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- JitFrameLayout::Size()
|
||||||
|
// Descriptor |
|
||||||
|
// FP -----> ReturnAddr |
|
||||||
|
//
|
||||||
|
masm.bind(&handle_Rectifier);
|
||||||
|
{
|
||||||
|
// scratch2 := StackPointer + Descriptor.size + JitFrameLayout::Size()
|
||||||
|
masm.lea(Operand(StackPointer, scratch1, TimesOne, JitFrameLayout::Size()), scratch2);
|
||||||
|
masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfDescriptor()), scratch3);
|
||||||
|
masm.movePtr(scratch3, scratch1);
|
||||||
|
masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch3);
|
||||||
|
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch1);
|
||||||
|
|
||||||
|
// Now |scratch1| contains Rect-Descriptor.Size
|
||||||
|
// and |scratch2| points to Rectifier frame
|
||||||
|
// and |scratch3| contains Rect-Descriptor.Type
|
||||||
|
|
||||||
|
// Check for either Ion or BaselineStub frame.
|
||||||
|
Label handle_Rectifier_BaselineStub;
|
||||||
|
masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS),
|
||||||
|
&handle_Rectifier_BaselineStub);
|
||||||
|
|
||||||
|
// Handle Rectifier <- IonJS
|
||||||
|
// scratch3 := RectFrame[ReturnAddr]
|
||||||
|
masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfReturnAddress()), scratch3);
|
||||||
|
masm.storePtr(scratch3, lastProfilingCallSite);
|
||||||
|
|
||||||
|
// scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size()
|
||||||
|
masm.lea(Operand(scratch2, scratch1, TimesOne, RectifierFrameLayout::Size()), scratch3);
|
||||||
|
masm.storePtr(scratch3, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
|
||||||
|
// Handle Rectifier <- BaselineStub <- BaselineJS
|
||||||
|
masm.bind(&handle_Rectifier_BaselineStub);
|
||||||
|
#ifdef DEBUG
|
||||||
|
{
|
||||||
|
Label checkOk;
|
||||||
|
masm.branch32(Assembler::Equal, scratch3, Imm32(JitFrame_BaselineStub), &checkOk);
|
||||||
|
masm.assumeUnreachable("Unrecognized frame preceding baselineStub.");
|
||||||
|
masm.bind(&checkOk);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
BaseIndex stubFrameReturnAddr(scratch2, scratch1, TimesOne,
|
||||||
|
RectifierFrameLayout::Size() +
|
||||||
|
BaselineStubFrameLayout::offsetOfReturnAddress());
|
||||||
|
masm.loadPtr(stubFrameReturnAddr, scratch3);
|
||||||
|
masm.storePtr(scratch3, lastProfilingCallSite);
|
||||||
|
|
||||||
|
BaseIndex stubFrameSavedFramePtr(scratch2, scratch1, TimesOne,
|
||||||
|
RectifierFrameLayout::Size() - (2 * sizeof(void *)));
|
||||||
|
masm.loadPtr(stubFrameSavedFramePtr, scratch3);
|
||||||
|
masm.addPtr(Imm32(sizeof(void *)), scratch3);
|
||||||
|
masm.storePtr(scratch3, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_Entry
|
||||||
|
//
|
||||||
|
// If at an entry frame, store null into both fields.
|
||||||
|
//
|
||||||
|
masm.bind(&handle_Entry);
|
||||||
|
{
|
||||||
|
masm.movePtr(ImmPtr(nullptr), scratch1);
|
||||||
|
masm.storePtr(scratch1, lastProfilingCallSite);
|
||||||
|
masm.storePtr(scratch1, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
Linker linker(masm);
|
||||||
|
JitCode *code = linker.newCode<NoGC>(cx, OTHER_CODE);
|
||||||
|
|
||||||
|
#ifdef JS_ION_PERF
|
||||||
|
writePerfSpewerJitCodeProfile(code, "ProfilerExitFrameStub");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
|
@ -514,3 +514,18 @@ MacroAssemblerX86::branchValueIsNurseryObject(Condition cond, ValueOperand value
|
||||||
|
|
||||||
bind(&done);
|
bind(&done);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroAssemblerX86::profilerEnterFrame(Register framePtr, Register scratch)
|
||||||
|
{
|
||||||
|
AbsoluteAddress activation(GetJitContext()->runtime->addressOfProfilingActivation());
|
||||||
|
loadPtr(activation, scratch);
|
||||||
|
storePtr(framePtr, Address(scratch, JitActivation::offsetOfLastProfilingFrame()));
|
||||||
|
storePtr(ImmPtr(nullptr), Address(scratch, JitActivation::offsetOfLastProfilingCallSite()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MacroAssemblerX86::profilerExitFrame()
|
||||||
|
{
|
||||||
|
jmp(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
|
||||||
|
}
|
||||||
|
|
|
@ -1195,6 +1195,10 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||||
|
|
||||||
void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label);
|
void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label);
|
||||||
void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label *label);
|
void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label *label);
|
||||||
|
|
||||||
|
// Instrumentation for entering and leaving the profiler.
|
||||||
|
void profilerEnterFrame(Register framePtr, Register scratch);
|
||||||
|
void profilerExitFrame();
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef MacroAssemblerX86 MacroAssemblerSpecific;
|
typedef MacroAssemblerX86 MacroAssemblerSpecific;
|
||||||
|
|
|
@ -858,3 +858,292 @@ JitRuntime::generateBailoutTailStub(JSContext *cx)
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JitCode *
|
||||||
|
JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
|
||||||
|
{
|
||||||
|
MacroAssembler masm;
|
||||||
|
|
||||||
|
Register scratch1 = eax;
|
||||||
|
Register scratch2 = ebx;
|
||||||
|
Register scratch3 = esi;
|
||||||
|
Register scratch4 = edi;
|
||||||
|
|
||||||
|
//
|
||||||
|
// The code generated below expects that the current stack pointer points
|
||||||
|
// to an Ion or Baseline frame, at the state it would be immediately
|
||||||
|
// before a ret(). Thus, after this stub's business is done, it executes
|
||||||
|
// a ret() and returns directly to the caller script, on behalf of the
|
||||||
|
// callee script that jumped to this code.
|
||||||
|
//
|
||||||
|
// Thus the expected stack is:
|
||||||
|
//
|
||||||
|
// StackPointer ----+
|
||||||
|
// v
|
||||||
|
// ..., ActualArgc, CalleeToken, Descriptor, ReturnAddr
|
||||||
|
// MEM-HI MEM-LOW
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// The generated jitcode is responsible for overwriting the
|
||||||
|
// jitActivation->lastProfilingFrame field with a pointer to the previous
|
||||||
|
// Ion or Baseline jit-frame that was pushed before this one. It is also
|
||||||
|
// responsible for overwriting jitActivation->lastProfilingCallSite with
|
||||||
|
// the return address into that frame. The frame could either be an
|
||||||
|
// immediate "caller" frame, or it could be a frame in a previous
|
||||||
|
// JitActivation (if the current frame was entered from C++, and the C++
|
||||||
|
// was entered by some caller jit-frame further down the stack).
|
||||||
|
//
|
||||||
|
// So this jitcode is responsible for "walking up" the jit stack, finding
|
||||||
|
// the previous Ion or Baseline JS frame, and storing its address and the
|
||||||
|
// return address into the appropriate fields on the current jitActivation.
|
||||||
|
//
|
||||||
|
// There are a fixed number of different path types that can lead to the
|
||||||
|
// current frame, which is either a baseline or ion frame:
|
||||||
|
//
|
||||||
|
// <Baseline-Or-Ion>
|
||||||
|
// ^
|
||||||
|
// |
|
||||||
|
// ^--- Ion
|
||||||
|
// |
|
||||||
|
// ^--- Baseline Stub <---- Baseline
|
||||||
|
// |
|
||||||
|
// ^--- Argument Rectifier
|
||||||
|
// | ^
|
||||||
|
// | |
|
||||||
|
// | ^--- Ion
|
||||||
|
// | |
|
||||||
|
// | ^--- Baseline Stub <---- Baseline
|
||||||
|
// |
|
||||||
|
// ^--- Entry Frame (From C++)
|
||||||
|
//
|
||||||
|
Register actReg = scratch4;
|
||||||
|
AbsoluteAddress activationAddr(GetJitContext()->runtime->addressOfProfilingActivation());
|
||||||
|
masm.loadPtr(activationAddr, actReg);
|
||||||
|
|
||||||
|
Address lastProfilingFrame(actReg, JitActivation::offsetOfLastProfilingFrame());
|
||||||
|
Address lastProfilingCallSite(actReg, JitActivation::offsetOfLastProfilingCallSite());
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Ensure that frame we are exiting is current lastProfilingFrame
|
||||||
|
{
|
||||||
|
masm.loadPtr(lastProfilingFrame, scratch1);
|
||||||
|
Label checkOk;
|
||||||
|
masm.branchPtr(Assembler::Equal, scratch1, ImmWord(0), &checkOk);
|
||||||
|
masm.branchPtr(Assembler::Equal, StackPointer, scratch1, &checkOk);
|
||||||
|
masm.assumeUnreachable(
|
||||||
|
"Mismatch between stored lastProfilingFrame and current stack pointer.");
|
||||||
|
masm.bind(&checkOk);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Load the frame descriptor into |scratch1|, figure out what to do
|
||||||
|
// depending on its type.
|
||||||
|
masm.loadPtr(Address(StackPointer, JitFrameLayout::offsetOfDescriptor()), scratch1);
|
||||||
|
|
||||||
|
// Going into the conditionals, we will have:
|
||||||
|
// FrameDescriptor.size in scratch1
|
||||||
|
// FrameDescriptor.type in scratch2
|
||||||
|
masm.movePtr(scratch1, scratch2);
|
||||||
|
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch1);
|
||||||
|
masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch2);
|
||||||
|
|
||||||
|
// Handling of each case is dependent on FrameDescriptor.type
|
||||||
|
Label handle_IonJS;
|
||||||
|
Label handle_BaselineStub;
|
||||||
|
Label handle_Rectifier;
|
||||||
|
Label handle_Entry;
|
||||||
|
Label end;
|
||||||
|
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_IonJS), &handle_IonJS);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineJS), &handle_IonJS);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineStub), &handle_BaselineStub);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Rectifier), &handle_Rectifier);
|
||||||
|
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Entry), &handle_Entry);
|
||||||
|
|
||||||
|
masm.assumeUnreachable("Invalid caller frame type when exiting from Ion frame.");
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_IonJS
|
||||||
|
//
|
||||||
|
// Stack layout:
|
||||||
|
// ...
|
||||||
|
// Ion-Descriptor
|
||||||
|
// Prev-FP ---> Ion-ReturnAddr
|
||||||
|
// ... previous frame data ... |- Descriptor.Size
|
||||||
|
// ... arguments ... |
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- JitFrameLayout::Size()
|
||||||
|
// Descriptor |
|
||||||
|
// FP -----> ReturnAddr |
|
||||||
|
//
|
||||||
|
masm.bind(&handle_IonJS);
|
||||||
|
{
|
||||||
|
// |scratch1| contains Descriptor.size
|
||||||
|
|
||||||
|
// returning directly to an IonJS frame. Store return addr to frame
|
||||||
|
// in lastProfilingCallSite.
|
||||||
|
masm.loadPtr(Address(StackPointer, JitFrameLayout::offsetOfReturnAddress()), scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingCallSite);
|
||||||
|
|
||||||
|
// Store return frame in lastProfilingFrame.
|
||||||
|
// scratch2 := StackPointer + Descriptor.size*1 + JitFrameLayout::Size();
|
||||||
|
masm.lea(Operand(StackPointer, scratch1, TimesOne, JitFrameLayout::Size()), scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_BaselineStub
|
||||||
|
//
|
||||||
|
// Look past the stub and store the frame pointer to
|
||||||
|
// the baselineJS frame prior to it.
|
||||||
|
//
|
||||||
|
// Stack layout:
|
||||||
|
// ...
|
||||||
|
// BL-Descriptor
|
||||||
|
// Prev-FP ---> BL-ReturnAddr
|
||||||
|
// +-----> BL-PrevFramePointer
|
||||||
|
// | ... BL-FrameData ...
|
||||||
|
// | BLStub-Descriptor
|
||||||
|
// | BLStub-ReturnAddr
|
||||||
|
// | BLStub-StubPointer |
|
||||||
|
// +------ BLStub-SavedFramePointer |- Descriptor.Size
|
||||||
|
// ... arguments ... |
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- JitFrameLayout::Size()
|
||||||
|
// Descriptor |
|
||||||
|
// FP -----> ReturnAddr |
|
||||||
|
//
|
||||||
|
// We take advantage of the fact that the stub frame saves the frame
|
||||||
|
// pointer pointing to the baseline frame, so a bunch of calculation can
|
||||||
|
// be avoided.
|
||||||
|
//
|
||||||
|
masm.bind(&handle_BaselineStub);
|
||||||
|
{
|
||||||
|
BaseIndex stubFrameReturnAddr(StackPointer, scratch1, TimesOne,
|
||||||
|
JitFrameLayout::Size() +
|
||||||
|
BaselineStubFrameLayout::offsetOfReturnAddress());
|
||||||
|
masm.loadPtr(stubFrameReturnAddr, scratch2);
|
||||||
|
masm.storePtr(scratch2, lastProfilingCallSite);
|
||||||
|
|
||||||
|
BaseIndex stubFrameSavedFramePtr(StackPointer, scratch1, TimesOne,
|
||||||
|
JitFrameLayout::Size() - (2 * sizeof(void *)));
|
||||||
|
masm.loadPtr(stubFrameSavedFramePtr, scratch2);
|
||||||
|
masm.addPtr(Imm32(sizeof(void *)), scratch2); // Skip past BL-PrevFramePtr
|
||||||
|
masm.storePtr(scratch2, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_Rectifier
|
||||||
|
//
|
||||||
|
// The rectifier frame can be preceded by either an IonJS or a
|
||||||
|
// BaselineStub frame.
|
||||||
|
//
|
||||||
|
// Stack layout if caller of rectifier was Ion:
|
||||||
|
//
|
||||||
|
// Ion-Descriptor
|
||||||
|
// Ion-ReturnAddr
|
||||||
|
// ... ion frame data ... |- Rect-Descriptor.Size
|
||||||
|
// < COMMON LAYOUT >
|
||||||
|
//
|
||||||
|
// Stack layout if caller of rectifier was Baseline:
|
||||||
|
//
|
||||||
|
// BL-Descriptor
|
||||||
|
// Prev-FP ---> BL-ReturnAddr
|
||||||
|
// +-----> BL-SavedFramePointer
|
||||||
|
// | ... baseline frame data ...
|
||||||
|
// | BLStub-Descriptor
|
||||||
|
// | BLStub-ReturnAddr
|
||||||
|
// | BLStub-StubPointer |
|
||||||
|
// +------ BLStub-SavedFramePointer |- Rect-Descriptor.Size
|
||||||
|
// ... args to rectifier ... |
|
||||||
|
// < COMMON LAYOUT >
|
||||||
|
//
|
||||||
|
// Common stack layout:
|
||||||
|
//
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- IonRectitiferFrameLayout::Size()
|
||||||
|
// Rect-Descriptor |
|
||||||
|
// Rect-ReturnAddr |
|
||||||
|
// ... rectifier data & args ... |- Descriptor.Size
|
||||||
|
// ActualArgc |
|
||||||
|
// CalleeToken |- JitFrameLayout::Size()
|
||||||
|
// Descriptor |
|
||||||
|
// FP -----> ReturnAddr |
|
||||||
|
//
|
||||||
|
masm.bind(&handle_Rectifier);
|
||||||
|
{
|
||||||
|
// scratch2 := StackPointer + Descriptor.size + JitFrameLayout::Size()
|
||||||
|
masm.lea(Operand(StackPointer, scratch1, TimesOne, JitFrameLayout::Size()), scratch2);
|
||||||
|
masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfDescriptor()), scratch3);
|
||||||
|
masm.movePtr(scratch3, scratch1);
|
||||||
|
masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch3);
|
||||||
|
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch1);
|
||||||
|
|
||||||
|
// Now |scratch1| contains Rect-Descriptor.Size
|
||||||
|
// and |scratch2| points to Rectifier frame
|
||||||
|
// and |scratch3| contains Rect-Descriptor.Type
|
||||||
|
|
||||||
|
// Check for either Ion or BaselineStub frame.
|
||||||
|
Label handle_Rectifier_BaselineStub;
|
||||||
|
masm.branch32(Assembler::NotEqual, scratch3, Imm32(JitFrame_IonJS),
|
||||||
|
&handle_Rectifier_BaselineStub);
|
||||||
|
|
||||||
|
// Handle Rectifier <- IonJS
|
||||||
|
// scratch3 := RectFrame[ReturnAddr]
|
||||||
|
masm.loadPtr(Address(scratch2, RectifierFrameLayout::offsetOfReturnAddress()), scratch3);
|
||||||
|
masm.storePtr(scratch3, lastProfilingCallSite);
|
||||||
|
|
||||||
|
// scratch3 := RectFrame + Rect-Descriptor.Size + RectifierFrameLayout::Size()
|
||||||
|
masm.lea(Operand(scratch2, scratch1, TimesOne, RectifierFrameLayout::Size()), scratch3);
|
||||||
|
masm.storePtr(scratch3, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
|
||||||
|
// Handle Rectifier <- BaselineStub <- BaselineJS
|
||||||
|
masm.bind(&handle_Rectifier_BaselineStub);
|
||||||
|
#ifdef DEBUG
|
||||||
|
{
|
||||||
|
Label checkOk;
|
||||||
|
masm.branch32(Assembler::Equal, scratch3, Imm32(JitFrame_BaselineStub), &checkOk);
|
||||||
|
masm.assumeUnreachable("Unrecognized frame preceding baselineStub.");
|
||||||
|
masm.bind(&checkOk);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
BaseIndex stubFrameReturnAddr(scratch2, scratch1, TimesOne,
|
||||||
|
RectifierFrameLayout::Size() +
|
||||||
|
BaselineStubFrameLayout::offsetOfReturnAddress());
|
||||||
|
masm.loadPtr(stubFrameReturnAddr, scratch3);
|
||||||
|
masm.storePtr(scratch3, lastProfilingCallSite);
|
||||||
|
|
||||||
|
BaseIndex stubFrameSavedFramePtr(scratch2, scratch1, TimesOne,
|
||||||
|
RectifierFrameLayout::Size() - (2 * sizeof(void *)));
|
||||||
|
masm.loadPtr(stubFrameSavedFramePtr, scratch3);
|
||||||
|
masm.addPtr(Imm32(sizeof(void *)), scratch3);
|
||||||
|
masm.storePtr(scratch3, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// JitFrame_Entry
|
||||||
|
//
|
||||||
|
// If at an entry frame, store null into both fields.
|
||||||
|
//
|
||||||
|
masm.bind(&handle_Entry);
|
||||||
|
{
|
||||||
|
masm.movePtr(ImmPtr(nullptr), scratch1);
|
||||||
|
masm.storePtr(scratch1, lastProfilingCallSite);
|
||||||
|
masm.storePtr(scratch1, lastProfilingFrame);
|
||||||
|
masm.ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
Linker linker(masm);
|
||||||
|
JitCode *code = linker.newCode<NoGC>(cx, OTHER_CODE);
|
||||||
|
|
||||||
|
#ifdef JS_ION_PERF
|
||||||
|
writePerfSpewerJitCodeProfile(code, "ProfilerExitFrameStub");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
|
@ -87,6 +87,7 @@ struct PcScriptCache;
|
||||||
class Simulator;
|
class Simulator;
|
||||||
class SimulatorRuntime;
|
class SimulatorRuntime;
|
||||||
struct AutoFlushICache;
|
struct AutoFlushICache;
|
||||||
|
class CompileRuntime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -552,6 +553,7 @@ class PerThreadData : public PerThreadDataFriendFields
|
||||||
friend class js::ActivationIterator;
|
friend class js::ActivationIterator;
|
||||||
friend class js::jit::JitActivation;
|
friend class js::jit::JitActivation;
|
||||||
friend class js::AsmJSActivation;
|
friend class js::AsmJSActivation;
|
||||||
|
friend class js::jit::CompileRuntime;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
friend void js::AssertCurrentThreadCanLock(RuntimeLock which);
|
friend void js::AssertCurrentThreadCanLock(RuntimeLock which);
|
||||||
#endif
|
#endif
|
||||||
|
|
Загрузка…
Ссылка в новой задаче