Bug 1057082 - 2/7 - Add profiler exit and enter frame instrumentation code. r=jandem

This commit is contained in:
Kannan Vijayan 2015-01-14 16:19:13 -05:00
Родитель c3fed7ebbb
Коммит b6f5b5ee44
17 изменённых файлов: 1257 добавлений и 0 удалений

Просмотреть файл

@ -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