This commit is contained in:
Jan de Mooij 2013-03-25 10:29:04 +01:00
commit 7f0a88535b
15 changed files with 661 additions and 81 deletions

View File

@ -443,8 +443,10 @@ struct BaselineStackBuilder
// +===============+
//
static bool
InitFromBailout(JSContext *cx, HandleFunction fun, HandleScript script, SnapshotIterator &iter,
bool invalidate, BaselineStackBuilder &builder, MutableHandleFunction nextCallee)
InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
HandleFunction fun, HandleScript script, SnapshotIterator &iter,
bool invalidate, BaselineStackBuilder &builder,
MutableHandleFunction nextCallee, jsbytecode **callPC)
{
uint32_t exprStackSlots = iter.slots() - (script->nfixed + CountArgSlots(fun));
@ -499,9 +501,18 @@ InitFromBailout(JSContext *cx, HandleFunction fun, HandleScript script, Snapshot
uint32_t flags = 0;
// If SPS Profiler is enabled, mark the frame as having pushed an SPS entry.
// This may be wrong for the last frame of ArgumentCheck bailout, but
// that will be fixed later.
if (cx->runtime->spsProfiler.enabled()) {
IonSpew(IonSpew_BaselineBailouts, " Setting SPS flag on frame!");
flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
}
// Initialize BaselineFrame::scopeChain
JSObject *scopeChain = NULL;
if (iter.bailoutKind() == Bailout_ArgumentCheck) {
BailoutKind bailoutKind = iter.bailoutKind();
if (bailoutKind == Bailout_ArgumentCheck) {
// Temporary hack -- skip the (unused) scopeChain, because it could be
// bogus (we can fail before the scope chain slot is set). Strip the
// hasScopeChain flag and we'll check this later to run prologue().
@ -634,11 +645,13 @@ InitFromBailout(JSContext *cx, HandleFunction fun, HandleScript script, Snapshot
resumeAfter ? "after" : "at", (int) pcOff, js_CodeName[op],
PCToLineNumber(script, pc), script->filename(), (int) script->lineno);
IonSpew(IonSpew_BaselineBailouts, " Bailout kind: %s",
BailoutKindString(iter.bailoutKind()));
BailoutKindString(bailoutKind));
#endif
// If this was the last inline frame, then unpacking is almost done.
if (!iter.moreFrames()) {
// Last frame, so PC for call to next frame is set to NULL.
*callPC = NULL;
// If the bailout was a resumeAfter, and the opcode is monitored,
// then the bailed out state should be in a position to enter
@ -742,6 +755,35 @@ InitFromBailout(JSContext *cx, HandleFunction fun, HandleScript script, Snapshot
JS_ASSERT(numUnsynced == 0);
opReturnAddr = baselineScript->prologueEntryAddr();
IonSpew(IonSpew_BaselineBailouts, " Resuming into prologue.");
// If bailing into prologue, HAS_PUSHED_SPS_FRAME should not be set on frame.
blFrame->unsetPushedSPSFrame();
// Additionally, if SPS is enabled, there are two corner cases to handle:
// 1. If resuming into the prologue, and innermost frame is an inlined frame,
// and bailout is because of argument check failure, then:
// Top SPS profiler entry would be for caller frame.
// Ion would not have set the PC index field on that frame
// (since this bailout happens before MFunctionBoundary).
// Make sure that's done now.
// 2. If resuming into the prologue, and the bailout is NOT because of an
// argument check, then:
// Top SPS profiler entry would be for callee frame.
// Ion would already have pushed an SPS entry for this frame.
// The pc for this entry would be set to NULL.
// Make sure it's set to script->pc.
if (cx->runtime->spsProfiler.enabled()) {
if (caller && bailoutKind == Bailout_ArgumentCheck) {
IonSpew(IonSpew_BaselineBailouts, " Setting PCidx on innermost "
"inlined frame's parent's SPS entry (%s:%d) (pcIdx=%d)!",
caller->filename(), caller->lineno, callerPC - caller->code);
cx->runtime->spsProfiler.updatePC(caller, callerPC);
} else if (bailoutKind != Bailout_ArgumentCheck) {
IonSpew(IonSpew_BaselineBailouts,
" Popping SPS entry for innermost inlined frame's SPS entry");
cx->runtime->spsProfiler.exit(cx, script, fun);
}
}
} else {
opReturnAddr = nativeCodeForPC;
}
@ -752,6 +794,8 @@ InitFromBailout(JSContext *cx, HandleFunction fun, HandleScript script, Snapshot
return true;
}
*callPC = pc;
// Write out descriptor of BaselineJS frame.
size_t baselineFrameDescr = MakeFrameDescriptor((uint32_t) builder.framePushed(),
IonFrame_BaselineJS);
@ -1008,18 +1052,29 @@ ion::BailoutIonToBaseline(JSContext *cx, IonActivation *activation, IonBailoutIt
int frameNo = 0;
// Reconstruct baseline frames using the builder.
RootedScript caller(cx);
jsbytecode *callerPC = NULL;
RootedFunction fun(cx, callee);
RootedScript scr(cx, iter.script());
while (true) {
IonSpew(IonSpew_BaselineBailouts, " FrameNo %d", frameNo);
jsbytecode *callPC = NULL;
RootedFunction nextCallee(cx, NULL);
if (!InitFromBailout(cx, fun, scr, snapIter, invalidate, builder, &nextCallee))
if (!InitFromBailout(cx, caller, callerPC, fun, scr, snapIter, invalidate, builder,
&nextCallee, &callPC))
{
return BAILOUT_RETURN_FATAL_ERROR;
}
if (!snapIter.moreFrames())
break;
if (!snapIter.moreFrames()) {
JS_ASSERT(!callPC);
break;
}
JS_ASSERT(nextCallee);
JS_ASSERT(callPC);
caller = scr;
callerPC = callPC;
fun = nextCallee;
scr = fun->nonLazyScript();
snapIter.nextFrame();

View File

@ -114,9 +114,10 @@ BaselineCompiler::compile()
return Method_Error;
prologueOffset_.fixup(&masm);
uint32_t prologueOffset = uint32_t(prologueOffset_.offset());
spsPushToggleOffset_.fixup(&masm);
BaselineScript *baselineScript = BaselineScript::New(cx, prologueOffset,
BaselineScript *baselineScript = BaselineScript::New(cx, prologueOffset_.offset(),
spsPushToggleOffset_.offset(),
icEntries_.length(),
pcMappingIndexEntries.length(),
pcEntries.length());
@ -158,6 +159,10 @@ BaselineCompiler::compile()
if (cx->zone()->needsBarrier())
baselineScript->toggleBarriers(true);
// All SPS instrumentation is emitted toggled off. Toggle them on if needed.
if (cx->runtime->spsProfiler.enabled())
baselineScript->toggleSPS(true);
return Method_Compiled;
}
@ -228,6 +233,9 @@ BaselineCompiler::emitPrologue()
if (!emitArgumentTypeChecks())
return false;
if (!emitSPSPush())
return false;
return true;
}
@ -236,6 +244,9 @@ BaselineCompiler::emitEpilogue()
{
masm.bind(return_);
// Pop SPS frame if necessary
emitSPSPop();
masm.mov(BaselineFrameReg, BaselineStackReg);
masm.pop(BaselineFrameReg);
@ -466,6 +477,35 @@ BaselineCompiler::emitDebugTrap()
return true;
}
bool
BaselineCompiler::emitSPSPush()
{
// Enter the IC, guarded by a toggled jump (initially disabled).
Label noPush;
CodeOffsetLabel toggleOffset = masm.toggledJump(&noPush);
JS_ASSERT(frame.numUnsyncedSlots() == 0);
ICProfiler_Fallback::Compiler compiler(cx);
if (!emitNonOpIC(compiler.getStub(&stubSpace_)))
return false;
masm.bind(&noPush);
// Store the start offset in the appropriate location.
JS_ASSERT(spsPushToggleOffset_.offset() == 0);
spsPushToggleOffset_ = toggleOffset;
return true;
}
void
BaselineCompiler::emitSPSPop()
{
// If profiler entry was pushed on this frame, pop it.
Label noPop;
masm.branchTest32(Assembler::Zero, frame.addressOfFlags(),
Imm32(BaselineFrame::HAS_PUSHED_SPS_FRAME), &noPop);
masm.spsPopFrame(&cx->runtime->spsProfiler, R1.scratchReg());
masm.bind(&noPop);
}
MethodStatus
BaselineCompiler::emitBody()
{

View File

@ -193,12 +193,15 @@ class BaselineCompiler : public BaselineCompilerSpecific
bool emitNonOpIC(ICStub *stub) {
return emitIC(stub, false);
}
bool emitStackCheck();
bool emitInterruptCheck();
bool emitUseCountIncrement();
bool emitArgumentTypeChecks();
bool emitDebugPrologue();
bool emitDebugTrap();
bool emitSPSPush();
void emitSPSPop();
bool initScopeChain();

View File

@ -134,6 +134,9 @@ BaselineFrame::initForOsr(StackFrame *fp, uint32_t numStackValues)
hookData_ = fp->hookData();
}
if (fp->hasPushedSPSFrame())
flags_ |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
frameSize_ = BaselineFrame::FramePointerOffset +
BaselineFrame::Size() +
numStackValues * sizeof(Value);

View File

@ -56,7 +56,10 @@ class BaselineFrame
EVAL = 1 << 6,
// Frame has hookData_ set.
HAS_HOOK_DATA = 1 << 7
HAS_HOOK_DATA = 1 << 7,
// Frame has profiler entry pushed.
HAS_PUSHED_SPS_FRAME = 1 << 8
};
protected: // Silence Clang warning about unused private fields.
@ -296,6 +299,18 @@ class BaselineFrame
flags_ |= HAS_HOOK_DATA;
}
bool hasPushedSPSFrame() const {
return flags_ & HAS_PUSHED_SPS_FRAME;
}
void setPushedSPSFrame() {
flags_ |= HAS_PUSHED_SPS_FRAME;
}
void unsetPushedSPSFrame() {
flags_ &= ~HAS_PUSHED_SPS_FRAME;
}
void trace(JSTracer *trc);
bool isFunctionFrame() const {

View File

@ -77,6 +77,7 @@ TypeFallbackICSpew(JSContext *cx, ICTypeMonitor_Fallback *stub, const char *fmt,
#define TypeFallbackICSpew(...)
#endif
ICFallbackStub *
ICEntry::fallbackStub() const
{
@ -240,6 +241,11 @@ ICStub::trace(JSTracer *trc)
MarkTypeObject(trc, &updateStub->type(), "baseline-update-typeobject");
break;
}
case ICStub::Profiler_PushFunction: {
ICProfiler_PushFunction *pushFunStub = toProfiler_PushFunction();
MarkScript(trc, &pushFunStub->script(), "baseline-profilerpushfunction-stub-script");
break;
}
case ICStub::GetName_Global: {
ICGetName_Global *globalStub = toGetName_Global();
MarkShape(trc, &globalStub->shape(), "baseline-global-stub-shape");
@ -546,6 +552,29 @@ ICStubCompiler::leaveStubFrame(MacroAssembler &masm, bool calledIntoIon)
JS_ASSERT(entersStubFrame_);
EmitLeaveStubFrame(masm, calledIntoIon);
}
void
ICStubCompiler::guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip)
{
// This should only be called from the following stubs.
JS_ASSERT(kind == ICStub::Call_Scripted || kind == ICStub::Call_AnyScripted ||
kind == ICStub::Call_Native || kind == ICStub::GetProp_CallScripted ||
kind == ICStub::SetProp_CallScripted);
// Guard on bit in frame that indicates if the SPS frame was pushed in the first
// place. This code is expected to be called from within a stub that has already
// entered a stub frame.
JS_ASSERT(entersStubFrame_);
masm.loadPtr(Address(BaselineFrameReg, 0), scratch);
masm.branchTest32(Assembler::Zero,
Address(scratch, BaselineFrame::reverseOffsetOfFlags()),
Imm32(BaselineFrame::HAS_PUSHED_SPS_FRAME),
skip);
// Check if profiling is enabled
uint32_t *enabledAddr = cx->runtime->spsProfiler.addressOfEnabled();
masm.branch32(Assembler::Equal, AbsoluteAddress(enabledAddr), Imm32(0), skip);
}
//
// UseCount_Fallback
@ -858,6 +887,100 @@ ICUseCount_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
return true;
}
//
// ICProfile_Fallback
//
static bool
DoProfilerFallback(JSContext *cx, BaselineFrame *frame, ICProfiler_Fallback *stub)
{
RootedScript script(cx, frame->script());
RootedFunction func(cx, frame->maybeFun());
ICEntry *icEntry = stub->icEntry();
FallbackICSpew(cx, stub, "Profiler");
SPSProfiler *profiler = &cx->runtime->spsProfiler;
// Manually enter SPS this time.
JS_ASSERT(profiler->enabled());
if (!cx->runtime->spsProfiler.enter(cx, script, func))
return false;
frame->setPushedSPSFrame();
// Unlink any existing PushFunction stub (which may hold stale 'const char *' to
// the profile string.
JS_ASSERT_IF(icEntry->firstStub() != stub,
icEntry->firstStub()->isProfiler_PushFunction() &&
icEntry->firstStub()->next() == stub);
stub->unlinkStubsWithKind(cx, ICStub::Profiler_PushFunction);
JS_ASSERT(icEntry->firstStub() == stub);
// Generate the string to use to identify this stack frame.
const char *string = profiler->profileString(cx, script, func);
if (string == NULL)
return false;
IonSpew(IonSpew_BaselineIC, " Generating Profiler_PushFunction stub for %s:%d",
script->filename(), script->lineno);
// Create a new optimized stub.
ICProfiler_PushFunction::Compiler compiler(cx, string, script);
ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
if (!optStub)
return false;
stub->addNewStub(optStub);
return true;
}
typedef bool (*DoProfilerFallbackFn)(JSContext *, BaselineFrame *frame, ICProfiler_Fallback *);
static const VMFunction DoProfilerFallbackInfo =
FunctionInfo<DoProfilerFallbackFn>(DoProfilerFallback);
bool
ICProfiler_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
{
EmitRestoreTailCallReg(masm);
masm.push(BaselineStubReg); // Push stub.
masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg()); // Push frame.
return tailCallVM(DoProfilerFallbackInfo, masm);
}
bool
ICProfiler_PushFunction::Compiler::generateStubCode(MacroAssembler &masm)
{
Register scratch = R0.scratchReg();
Register scratch2 = R1.scratchReg();
// Profiling should be enabled if we ever reach here.
#ifdef DEBUG
Label spsEnabled;
uint32_t *enabledAddr = cx->runtime->spsProfiler.addressOfEnabled();
masm.branch32(Assembler::NotEqual, AbsoluteAddress(enabledAddr), Imm32(0), &spsEnabled);
masm.breakpoint();
masm.bind(&spsEnabled);
#endif
// Push SPS entry.
masm.spsPushFrame(&cx->runtime->spsProfiler,
Address(BaselineStubReg, ICProfiler_PushFunction::offsetOfStr()),
Address(BaselineStubReg, ICProfiler_PushFunction::offsetOfScript()),
scratch,
scratch2);
// Mark frame as having profiler entry pushed.
Address flagsOffset(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags());
masm.or32(Imm32(BaselineFrame::HAS_PUSHED_SPS_FRAME), flagsOffset);
EmitReturnFromIC(masm);
return true;
}
//
// TypeMonitor_Fallback
//
@ -4477,9 +4600,9 @@ TryAttachLengthStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub
}
static bool
TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, ICGetProp_Fallback *stub,
HandlePropertyName name, HandleValue val, HandleValue res,
bool *attached)
TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
ICGetProp_Fallback *stub, HandlePropertyName name,
HandleValue val, HandleValue res, bool *attached)
{
JS_ASSERT(!*attached);
@ -4526,7 +4649,8 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, ICGetProp_Fallbac
(obj == holder) ? "direct" : "prototype",
callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno);
ICGetProp_CallScripted::Compiler compiler(cx, monitorStub, obj, holder, callee);
ICGetProp_CallScripted::Compiler compiler(cx, monitorStub, obj, holder, callee,
pc - script->code);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
@ -4638,7 +4762,7 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub,
return true;
}
if (!TryAttachNativeGetPropStub(cx, script, stub, name, val, res, &attached))
if (!TryAttachNativeGetPropStub(cx, script, pc, stub, name, val, res, &attached))
return false;
if (attached)
return true;
@ -4901,6 +5025,28 @@ ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
}
masm.bind(&noUnderflow);
// If needed, update SPS Profiler frame entry. At this point, callee and scratch can
// be clobbered.
{
Label skipProfilerUpdate;
// Need to avoid using ArgumentsRectifierReg and code register.
GeneralRegisterSet availRegs = availableGeneralRegs(0);
availRegs.take(ArgumentsRectifierReg);
availRegs.take(code);
Register scratch = availRegs.takeAny();
Register pcIdx = availRegs.takeAny();
// Check if profiling is enabled.
guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
// Update profiling entry before leaving function.
masm.load32(Address(BaselineStubReg, ICGetProp_CallScripted::offsetOfPCOffset()), pcIdx);
masm.spsUpdatePCIdx(&cx->runtime->spsProfiler, pcIdx, scratch);
masm.bind(&skipProfilerUpdate);
}
masm.callIon(code);
leaveStubFrame(masm, true);
@ -4924,7 +5070,7 @@ ICGetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
// Attach an optimized stub for a SETPROP/SETGNAME/SETNAME op.
static bool
TryAttachSetPropStub(JSContext *cx, HandleScript script, ICSetProp_Fallback *stub,
TryAttachSetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc, ICSetProp_Fallback *stub,
HandleObject obj, HandleShape oldShape, uint32_t oldSlots,
HandlePropertyName name, HandleId id, HandleValue rhs, bool *attached)
{
@ -4988,7 +5134,7 @@ TryAttachSetPropStub(JSContext *cx, HandleScript script, ICSetProp_Fallback *stu
(obj == holder) ? "direct" : "prototype",
callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno);
ICSetProp_CallScripted::Compiler compiler(cx, obj, holder, callee);
ICSetProp_CallScripted::Compiler compiler(cx, obj, holder, callee, pc - script->code);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
@ -5045,8 +5191,11 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub,
}
bool attached = false;
if (!TryAttachSetPropStub(cx, script, stub, obj, oldShape, oldSlots, name, id, rhs, &attached))
if (!TryAttachSetPropStub(cx, script, pc, stub, obj, oldShape, oldSlots, name, id, rhs,
&attached))
{
return false;
}
if (attached)
return true;
@ -5295,6 +5444,28 @@ ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
}
masm.bind(&noUnderflow);
// If needed, update SPS Profiler frame entry. At this point, callee and scratch can
// be clobbered.
{
Label skipProfilerUpdate;
// Need to avoid using ArgumentsRectifierReg and code register.
GeneralRegisterSet availRegs = availableGeneralRegs(0);
availRegs.take(ArgumentsRectifierReg);
availRegs.take(code);
Register scratch = availRegs.takeAny();
Register pcIdx = availRegs.takeAny();
// Check if profiling is enabled.
guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
// Update profiling entry before leaving function.
masm.load32(Address(BaselineStubReg, ICSetProp_CallScripted::offsetOfPCOffset()), pcIdx);
masm.spsUpdatePCIdx(&cx->runtime->spsProfiler, pcIdx, scratch);
masm.bind(&skipProfilerUpdate);
}
masm.callIon(code);
leaveStubFrame(masm, true);
@ -5323,8 +5494,8 @@ ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
//
static bool
TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, JSOp op,
uint32_t argc, Value *vp, bool constructing, bool useNewType)
TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsbytecode *pc,
JSOp op, uint32_t argc, Value *vp, bool constructing, bool useNewType)
{
if (useNewType || op == JSOP_EVAL)
return true;
@ -5366,7 +5537,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, JSO
constructing ? "yes" : "no");
ICCallScriptedCompiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
constructing);
constructing, pc - script->code);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
@ -5384,7 +5555,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, JSO
fun.get(), fun->nonLazyScript()->filename(), fun->nonLazyScript()->lineno,
constructing ? "yes" : "no");
ICCallScriptedCompiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
calleeScript, constructing);
calleeScript, constructing, pc - script->code);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
@ -5406,7 +5577,7 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, JSO
IonSpew(IonSpew_BaselineIC, " Generating Call_Native stub (fun=%p, cons=%s)", fun.get(),
constructing ? "yes" : "no");
ICCall_Native::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
fun, constructing);
fun, constructing, pc - script->code);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
@ -5472,9 +5643,13 @@ DoCallFallback(JSContext *cx, BaselineFrame *frame, ICCall_Fallback *stub, uint3
newType = types::UseNewType(cx, script, pc);
// Try attaching a call stub.
if (!TryAttachCallStub(cx, stub, script, op, argc, vp, constructing, newType))
if (!TryAttachCallStub(cx, stub, script, pc, op, argc, vp, constructing, newType))
return false;
// Maybe update PC in profiler entry before leaving this script by call.
if (cx->runtime->spsProfiler.enabled() && frame->hasPushedSPSFrame())
cx->runtime->spsProfiler.updatePC(script, pc);
if (!MaybeCloneFunctionAtCallsite(cx, &callee, script, pc))
return false;
@ -5792,6 +5967,32 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler &masm)
}
masm.bind(&noUnderflow);
// If needed, update SPS Profiler frame entry before and after call.
{
Label skipProfilerUpdate;
// Need to avoid using ArgumentsRectifierReg and code register.
GeneralRegisterSet availRegs = availableGeneralRegs(0);
availRegs.take(ArgumentsRectifierReg);
availRegs.take(code);
Register scratch = availRegs.takeAny();
Register pcIdx = availRegs.takeAny();
// Check if profiling is enabled.
guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
// Update profiling entry before leaving function.
JS_ASSERT(kind == ICStub::Call_Scripted || kind == ICStub::Call_AnyScripted);
if (kind == ICStub::Call_Scripted)
masm.load32(Address(BaselineStubReg, ICCall_Scripted::offsetOfPCOffset()), pcIdx);
else
masm.load32(Address(BaselineStubReg, ICCall_AnyScripted::offsetOfPCOffset()), pcIdx);
masm.spsUpdatePCIdx(&cx->runtime->spsProfiler, pcIdx, scratch);
masm.bind(&skipProfilerUpdate);
}
// Do call
masm.callIon(code);
// If this is a constructing call, and the callee returns a non-object, replace it with
@ -5887,6 +6088,18 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler &masm)
masm.push(BaselineTailCallReg);
masm.enterFakeExitFrame();
// If needed, update SPS Profiler frame entry. At this point, BaselineTailCallReg
// and scratch can be clobbered.
{
Label skipProfilerUpdate;
Register pcIdx = BaselineTailCallReg;
guardProfilingEnabled(masm, scratch, &skipProfilerUpdate);
masm.load32(Address(BaselineStubReg, ICCall_Native::offsetOfPCOffset()), pcIdx);
masm.spsUpdatePCIdx(&cx->runtime->spsProfiler, pcIdx, scratch);
masm.bind(&skipProfilerUpdate);
}
// Execute call.
masm.setupUnalignedABICall(3, scratch);
masm.loadJSContext(scratch);

View File

@ -271,6 +271,9 @@ class ICEntry
#define IC_STUB_KIND_LIST(_) \
_(UseCount_Fallback) \
\
_(Profiler_Fallback) \
_(Profiler_PushFunction) \
\
_(TypeMonitor_Fallback) \
_(TypeMonitor_SingleObject) \
_(TypeMonitor_TypeObject) \
@ -991,6 +994,11 @@ class ICStubCompiler
void enterStubFrame(MacroAssembler &masm, Register scratch);
void leaveStubFrame(MacroAssembler &masm, bool calledIntoIon = false);
// Some stubs need to emit SPS profiler updates. This emits the guarding
// jitcode for those stubs. If profiling is not enabled, jumps to the
// given label.
void guardProfilingEnabled(MacroAssembler &masm, Register scratch, Label *skip);
inline GeneralRegisterSet availableGeneralRegs(size_t numInputs) const {
GeneralRegisterSet regs(GeneralRegisterSet::All());
JS_ASSERT(!regs.has(BaselineStackReg));
@ -1082,6 +1090,95 @@ class ICUseCount_Fallback : public ICFallbackStub
};
};
// Profiler_Fallback
class ICProfiler_Fallback : public ICFallbackStub
{
friend class ICStubSpace;
ICProfiler_Fallback(IonCode *stubCode)
: ICFallbackStub(ICStub::Profiler_Fallback, stubCode)
{ }
public:
static inline ICProfiler_Fallback *New(ICStubSpace *space, IonCode *code) {
if (!code)
return NULL;
return space->allocate<ICProfiler_Fallback>(code);
}
// Compiler for this stub kind.
class Compiler : public ICStubCompiler {
protected:
bool generateStubCode(MacroAssembler &masm);
public:
Compiler(JSContext *cx)
: ICStubCompiler(cx, ICStub::Profiler_Fallback)
{ }
ICProfiler_Fallback *getStub(ICStubSpace *space) {
return ICProfiler_Fallback::New(space, getStubCode());
}
};
};
// Profiler_PushFunction
class ICProfiler_PushFunction : public ICStub
{
friend class ICStubSpace;
const char *str_;
HeapPtrScript script_;
ICProfiler_PushFunction(IonCode *stubCode, const char *str, HandleScript script)
: ICStub(ICStub::Profiler_PushFunction, stubCode),
str_(str),
script_(script)
{ }
public:
static inline ICProfiler_PushFunction *New(ICStubSpace *space, IonCode *code,
const char *str, HandleScript script)
{
if (!code)
return NULL;
return space->allocate<ICProfiler_PushFunction>(code, str, script);
}
HeapPtrScript &script() {
return script_;
}
static size_t offsetOfStr() {
return offsetof(ICProfiler_PushFunction, str_);
}
static size_t offsetOfScript() {
return offsetof(ICProfiler_PushFunction, script_);
}
// Compiler for this stub kind.
class Compiler : public ICStubCompiler {
protected:
const char *str_;
RootedScript script_;
bool generateStubCode(MacroAssembler &masm);
public:
Compiler(JSContext *cx, const char *str, HandleScript script)
: ICStubCompiler(cx, ICStub::Profiler_PushFunction),
str_(str),
script_(cx, script)
{ }
ICProfiler_PushFunction *getStub(ICStubSpace *space) {
return ICProfiler_PushFunction::New(space, getStubCode(), str_, script_);
}
};
};
// TypeCheckPrimitiveSetStub
// Base class for IC stubs (TypeUpdate or TypeMonitor) that check that a given
// value's type falls within a set of primitive types.
@ -3893,26 +3990,31 @@ class ICGetProp_CallScripted : public ICMonitoredStub
// Function to call.
HeapPtrFunction getter_;
// PC offset of call
uint32_t pcOffset_;
ICGetProp_CallScripted(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape shape, HandleObject holder, HandleShape holderShape,
HandleFunction getter)
HandleFunction getter, uint32_t pcOffset)
: ICMonitoredStub(GetProp_CallScripted, stubCode, firstMonitorStub),
shape_(shape),
holder_(holder),
holderShape_(holderShape),
getter_(getter)
getter_(getter),
pcOffset_(pcOffset)
{}
public:
static inline ICGetProp_CallScripted *New(
ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub,
HandleShape shape, HandleObject holder, HandleShape holderShape,
HandleFunction getter)
HandleFunction getter, uint32_t pcOffset)
{
if (!code)
return NULL;
return space->allocate<ICGetProp_CallScripted>(code, firstMonitorStub,
shape, holder, holderShape, getter);
shape, holder, holderShape, getter,
pcOffset);
}
HeapPtrShape &shape() {
@ -3927,6 +4029,7 @@ class ICGetProp_CallScripted : public ICMonitoredStub
HeapPtrFunction &getter() {
return getter_;
}
static size_t offsetOfShape() {
return offsetof(ICGetProp_CallScripted, shape_);
}
@ -3939,31 +4042,35 @@ class ICGetProp_CallScripted : public ICMonitoredStub
static size_t offsetOfGetter() {
return offsetof(ICGetProp_CallScripted, getter_);
}
static size_t offsetOfPCOffset() {
return offsetof(ICGetProp_CallScripted, pcOffset_);
}
class Compiler : public ICStubCompiler {
ICStub *firstMonitorStub_;
RootedObject obj_;
RootedObject holder_;
RootedFunction getter_;
uint32_t pcOffset_;
bool generateStubCode(MacroAssembler &masm);
public:
Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject obj,
HandleObject holder, HandleFunction getter)
HandleObject holder, HandleFunction getter, uint32_t pcOffset)
: ICStubCompiler(cx, ICStub::GetProp_CallScripted),
firstMonitorStub_(firstMonitorStub),
obj_(cx, obj),
holder_(cx, holder),
getter_(cx, getter)
getter_(cx, getter),
pcOffset_(pcOffset)
{}
ICStub *getStub(ICStubSpace *space) {
RootedShape shape(cx, obj_->lastProperty());
RootedShape holderShape(cx, holder_->lastProperty());
return ICGetProp_CallScripted::New(space, getStubCode(), firstMonitorStub_,
shape, holder_, holderShape, getter_);
return ICGetProp_CallScripted::New(space, getStubCode(), firstMonitorStub_, shape,
holder_, holderShape, getter_, pcOffset_);
}
};
};
@ -4260,23 +4367,29 @@ class ICSetProp_CallScripted : public ICStub
// Function to call.
HeapPtrFunction setter_;
// PC of call, for profiler
uint32_t pcOffset_;
ICSetProp_CallScripted(IonCode *stubCode, HandleShape shape, HandleObject holder,
HandleShape holderShape, HandleFunction setter)
HandleShape holderShape, HandleFunction setter, uint32_t pcOffset)
: ICStub(SetProp_CallScripted, stubCode),
shape_(shape),
holder_(holder),
holderShape_(holderShape),
setter_(setter)
setter_(setter),
pcOffset_(pcOffset)
{}
public:
static inline ICSetProp_CallScripted *New(ICStubSpace *space, IonCode *code,
HandleShape shape, HandleObject holder,
HandleShape holderShape, HandleFunction setter)
HandleShape holderShape, HandleFunction setter,
uint32_t pcOffset)
{
if (!code)
return NULL;
return space->allocate<ICSetProp_CallScripted>(code, shape, holder, holderShape, setter);
return space->allocate<ICSetProp_CallScripted>(code, shape, holder, holderShape, setter,
pcOffset);
}
HeapPtrShape &shape() {
@ -4291,6 +4404,7 @@ class ICSetProp_CallScripted : public ICStub
HeapPtrFunction &setter() {
return setter_;
}
static size_t offsetOfShape() {
return offsetof(ICSetProp_CallScripted, shape_);
}
@ -4303,28 +4417,33 @@ class ICSetProp_CallScripted : public ICStub
static size_t offsetOfSetter() {
return offsetof(ICSetProp_CallScripted, setter_);
}
static size_t offsetOfPCOffset() {
return offsetof(ICSetProp_CallScripted, pcOffset_);
}
class Compiler : public ICStubCompiler {
RootedObject obj_;
RootedObject holder_;
RootedFunction setter_;
uint32_t pcOffset_;
bool generateStubCode(MacroAssembler &masm);
public:
Compiler(JSContext *cx, HandleObject obj, HandleObject holder, HandleFunction setter)
Compiler(JSContext *cx, HandleObject obj, HandleObject holder, HandleFunction setter,
uint32_t pcOffset)
: ICStubCompiler(cx, ICStub::SetProp_CallScripted),
obj_(cx, obj),
holder_(cx, holder),
setter_(cx, setter)
setter_(cx, setter),
pcOffset_(pcOffset)
{}
ICStub *getStub(ICStubSpace *space) {
RootedShape shape(cx, obj_->lastProperty());
RootedShape holderShape(cx, holder_->lastProperty());
return ICSetProp_CallScripted::New(space, getStubCode(), shape, holder_,
holderShape, setter_);
return ICSetProp_CallScripted::New(space, getStubCode(), shape, holder_, holderShape,
setter_, pcOffset_);
}
};
};
@ -4420,26 +4539,34 @@ class ICCall_Scripted : public ICMonitoredStub
friend class ICStubSpace;
HeapPtrScript calleeScript_;
uint32_t pcOffset_;
ICCall_Scripted(IonCode *stubCode, ICStub *firstMonitorStub, HandleScript calleeScript)
ICCall_Scripted(IonCode *stubCode, ICStub *firstMonitorStub, HandleScript calleeScript,
uint32_t pcOffset)
: ICMonitoredStub(ICStub::Call_Scripted, stubCode, firstMonitorStub),
calleeScript_(calleeScript)
calleeScript_(calleeScript),
pcOffset_(pcOffset)
{ }
public:
static inline ICCall_Scripted *New(
ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub, HandleScript calleeScript)
ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub, HandleScript calleeScript,
uint32_t pcOffset)
{
if (!code)
return NULL;
return space->allocate<ICCall_Scripted>(code, firstMonitorStub, calleeScript);
return space->allocate<ICCall_Scripted>(code, firstMonitorStub, calleeScript, pcOffset);
}
HeapPtrScript &calleeScript() {
return calleeScript_;
}
static size_t offsetOfCalleeScript() {
return offsetof(ICCall_Scripted, calleeScript_);
}
HeapPtrScript &calleeScript() {
return calleeScript_;
static size_t offsetOfPCOffset() {
return offsetof(ICCall_Scripted, pcOffset_);
}
};
@ -4447,17 +4574,24 @@ class ICCall_AnyScripted : public ICMonitoredStub
{
friend class ICStubSpace;
ICCall_AnyScripted(IonCode *stubCode, ICStub *firstMonitorStub)
: ICMonitoredStub(ICStub::Call_AnyScripted, stubCode, firstMonitorStub)
uint32_t pcOffset_;
ICCall_AnyScripted(IonCode *stubCode, ICStub *firstMonitorStub, uint32_t pcOffset)
: ICMonitoredStub(ICStub::Call_AnyScripted, stubCode, firstMonitorStub),
pcOffset_(pcOffset)
{ }
public:
static inline ICCall_AnyScripted *New(ICStubSpace *space, IonCode *code,
ICStub *firstMonitorStub)
ICStub *firstMonitorStub, uint32_t pcOffset)
{
if (!code)
return NULL;
return space->allocate<ICCall_AnyScripted>(code, firstMonitorStub);
return space->allocate<ICCall_AnyScripted>(code, firstMonitorStub, pcOffset);
}
static size_t offsetOfPCOffset() {
return offsetof(ICCall_AnyScripted, pcOffset_);
}
};
@ -4467,6 +4601,7 @@ class ICCallScriptedCompiler : public ICCallStubCompiler {
ICStub *firstMonitorStub_;
bool isConstructing_;
RootedScript calleeScript_;
uint32_t pcOffset_;
bool generateStubCode(MacroAssembler &masm);
virtual int32_t getKey() const {
@ -4475,24 +4610,30 @@ class ICCallScriptedCompiler : public ICCallStubCompiler {
public:
ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub, HandleScript calleeScript,
bool isConstructing)
bool isConstructing, uint32_t pcOffset)
: ICCallStubCompiler(cx, ICStub::Call_Scripted),
firstMonitorStub_(firstMonitorStub),
isConstructing_(isConstructing),
calleeScript_(cx, calleeScript)
calleeScript_(cx, calleeScript),
pcOffset_(pcOffset)
{ }
ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub, bool isConstructing)
ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub, bool isConstructing,
uint32_t pcOffset)
: ICCallStubCompiler(cx, ICStub::Call_AnyScripted),
firstMonitorStub_(firstMonitorStub),
isConstructing_(isConstructing),
calleeScript_(cx, NULL)
calleeScript_(cx, NULL),
pcOffset_(pcOffset)
{ }
ICStub *getStub(ICStubSpace *space) {
if (calleeScript_)
return ICCall_Scripted::New(space, getStubCode(), firstMonitorStub_, calleeScript_);
return ICCall_AnyScripted::New(space, getStubCode(), firstMonitorStub_);
ICStub *stub = NULL;
if (calleeScript_) {
return ICCall_Scripted::New(space, getStubCode(), firstMonitorStub_, calleeScript_,
pcOffset_);
}
return ICCall_AnyScripted::New(space, getStubCode(), firstMonitorStub_, pcOffset_);
}
};
@ -4501,26 +4642,33 @@ class ICCall_Native : public ICMonitoredStub
friend class ICStubSpace;
HeapPtrFunction callee_;
uint32_t pcOffset_;
ICCall_Native(IonCode *stubCode, ICStub *firstMonitorStub, HandleFunction callee)
ICCall_Native(IonCode *stubCode, ICStub *firstMonitorStub, HandleFunction callee,
uint32_t pcOffset)
: ICMonitoredStub(ICStub::Call_Native, stubCode, firstMonitorStub),
callee_(callee)
callee_(callee),
pcOffset_(pcOffset)
{ }
public:
static inline ICCall_Native *New(ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub,
HandleFunction callee)
HandleFunction callee, uint32_t pcOffset)
{
if (!code)
return NULL;
return space->allocate<ICCall_Native>(code, firstMonitorStub, callee);
return space->allocate<ICCall_Native>(code, firstMonitorStub, callee, pcOffset);
}
HeapPtrFunction &callee() {
return callee_;
}
static size_t offsetOfCallee() {
return offsetof(ICCall_Native, callee_);
}
HeapPtrFunction &callee() {
return callee_;
static size_t offsetOfPCOffset() {
return offsetof(ICCall_Native, pcOffset_);
}
// Compiler for this stub kind.
@ -4529,6 +4677,7 @@ class ICCall_Native : public ICMonitoredStub
ICStub *firstMonitorStub_;
bool isConstructing_;
RootedFunction callee_;
uint32_t pcOffset_;
bool generateStubCode(MacroAssembler &masm);
virtual int32_t getKey() const {
@ -4537,15 +4686,16 @@ class ICCall_Native : public ICMonitoredStub
public:
Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleFunction callee,
bool isConstructing)
bool isConstructing, uint32_t pcOffset)
: ICCallStubCompiler(cx, ICStub::Call_Native),
firstMonitorStub_(firstMonitorStub),
isConstructing_(isConstructing),
callee_(cx, callee)
callee_(cx, callee),
pcOffset_(pcOffset)
{ }
ICStub *getStub(ICStubSpace *space) {
return ICCall_Native::New(space, getStubCode(), firstMonitorStub_, callee_);
return ICCall_Native::New(space, getStubCode(), firstMonitorStub_, callee_, pcOffset_);
}
};
};

View File

@ -32,10 +32,14 @@ PCMappingSlotInfo::ToSlotLocation(const StackValue *stackVal)
return SlotIgnore;
}
BaselineScript::BaselineScript(uint32_t prologueOffset)
BaselineScript::BaselineScript(uint32_t prologueOffset, uint32_t spsPushToggleOffset)
: method_(NULL),
fallbackStubSpace_(),
prologueOffset_(prologueOffset),
#ifdef DEBUG
spsOn_(false),
#endif
spsPushToggleOffset_(spsPushToggleOffset),
flags_(0)
{ }
@ -284,7 +288,8 @@ ion::CanEnterBaselineJIT(JSContext *cx, JSScript *scriptArg, StackFrame *fp, boo
static const unsigned DataAlignment = sizeof(uintptr_t);
BaselineScript *
BaselineScript::New(JSContext *cx, uint32_t prologueOffset, size_t icEntries,
BaselineScript::New(JSContext *cx, uint32_t prologueOffset,
uint32_t spsPushToggleOffset, size_t icEntries,
size_t pcMappingIndexEntries, size_t pcMappingSize)
{
size_t paddedBaselineScriptSize = AlignBytes(sizeof(BaselineScript), DataAlignment);
@ -306,7 +311,7 @@ BaselineScript::New(JSContext *cx, uint32_t prologueOffset, size_t icEntries,
return NULL;
BaselineScript *script = reinterpret_cast<BaselineScript *>(buffer);
new (script) BaselineScript(prologueOffset);
new (script) BaselineScript(prologueOffset, spsPushToggleOffset);
size_t offsetCursor = paddedBaselineScriptSize;
@ -613,6 +618,25 @@ BaselineScript::toggleDebugTraps(RawScript script, jsbytecode *pc)
}
}
void
BaselineScript::toggleSPS(bool enable)
{
JS_ASSERT(enable == !(bool)spsOn_);
IonSpew(IonSpew_BaselineIC, " toggling SPS %s for BaselineScript %p",
enable ? "on" : "off", this);
// Toggle the jump
CodeLocationLabel pushToggleLocation(method_, CodeOffsetLabel(spsPushToggleOffset_));
if (enable)
Assembler::ToggleToCmp(pushToggleLocation);
else
Assembler::ToggleToJmp(pushToggleLocation);
#ifdef DEBUG
spsOn_ = enable;
#endif
}
void
BaselineScript::purgeOptimizedStubs(Zone *zone)
{
@ -714,6 +738,19 @@ ion::SizeOfBaselineData(JSScript *script, JSMallocSizeOfFun mallocSizeOf, size_t
script->baseline->sizeOfIncludingThis(mallocSizeOf, data, fallbackStubs);
}
void
ion::ToggleBaselineSPS(JSRuntime *runtime, bool enable)
{
for (ZonesIter zone(runtime); !zone.done(); zone.next()) {
for (gc::CellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
if (!script->hasBaselineScript())
continue;
script->baselineScript()->toggleSPS(enable);
}
}
}
static void
MarkActiveBaselineScripts(JSContext *cx, const IonActivationIterator &activation)
{

View File

@ -108,6 +108,12 @@ struct BaselineScript
// Native code offset right before the scope chain is initialized.
uint32_t prologueOffset_;
// The offsets for the toggledJump instructions for SPS update ICs.
#ifdef DEBUG
mozilla::DebugOnly<bool> spsOn_;
#endif
uint32_t spsPushToggleOffset_;
public:
enum Flag {
// Flag set by JSScript::argumentsOptimizationFailed. Similar to
@ -136,9 +142,10 @@ struct BaselineScript
public:
// Do not call directly, use BaselineScript::New. This is public for cx->new_.
BaselineScript(uint32_t prologueOffset);
BaselineScript(uint32_t prologueOffset, uint32_t spsPushToggleOffset);
static BaselineScript *New(JSContext *cx, uint32_t prologueOffset, size_t icEntries,
static BaselineScript *New(JSContext *cx, uint32_t prologueOffset,
uint32_t spsPushToggleOffset, size_t icEntries,
size_t pcMappingIndexEntries, size_t pcMappingSize);
static void Trace(JSTracer *trc, BaselineScript *script);
static void Destroy(FreeOp *fop, BaselineScript *script);
@ -235,6 +242,8 @@ struct BaselineScript
// toggle traps at |pc|.
void toggleDebugTraps(RawScript script, jsbytecode *pc);
void toggleSPS(bool enable);
static size_t offsetOfFlags() {
return offsetof(BaselineScript, flags_);
}
@ -261,6 +270,9 @@ void
SizeOfBaselineData(JSScript *script, JSMallocSizeOfFun mallocSizeOf, size_t *data,
size_t *fallbackStubs);
void
ToggleBaselineSPS(JSRuntime *runtime, bool enable);
struct BaselineBailoutInfo
{
// Pointer into the current C stack, where overwriting will start.

View File

@ -466,6 +466,10 @@ HandleException(ResumeFromException *rfe)
if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME)
return;
// Unwind profiler pseudo-stack
RawScript script = iter.script();
Probes::exitScript(cx, script, script->function(), NULL);
if (cx->compartment->debugMode() && !calledDebugEpilogue) {
// If DebugEpilogue returns |true|, we have to perform a forced
// return, e.g. return frame->returnValue() to the caller.

View File

@ -751,16 +751,46 @@ class MacroAssembler : public MacroAssemblerSpecific
bind(&stackFull);
}
void spsUpdatePCIdx(SPSProfiler *p, Register idx, Register temp) {
Label stackFull;
spsProfileEntryAddress(p, -1, temp, &stackFull);
store32(idx, Address(temp, ProfileEntry::offsetOfPCIdx()));
bind(&stackFull);
}
void spsPushFrame(SPSProfiler *p, const char *str, RawScript s, Register temp) {
Label stackFull;
spsProfileEntryAddress(p, 0, temp, &stackFull);
storePtr(ImmWord(str), Address(temp, ProfileEntry::offsetOfString()));
storePtr(ImmGCPtr(s), Address(temp, ProfileEntry::offsetOfScript()));
storePtr(ImmWord((void*) NULL),
Address(temp, ProfileEntry::offsetOfStackAddress()));
store32(Imm32(ProfileEntry::NullPCIndex),
Address(temp, ProfileEntry::offsetOfPCIdx()));
storePtr(ImmWord((void*) NULL), Address(temp, ProfileEntry::offsetOfStackAddress()));
store32(Imm32(ProfileEntry::NullPCIndex), Address(temp, ProfileEntry::offsetOfPCIdx()));
/* Always increment the stack size, whether or not we actually pushed. */
bind(&stackFull);
movePtr(ImmWord(p->sizePointer()), temp);
add32(Imm32(1), Address(temp, 0));
}
void spsPushFrame(SPSProfiler *p, const Address &str, const Address &script,
Register temp, Register temp2)
{
Label stackFull;
spsProfileEntryAddress(p, 0, temp, &stackFull);
loadPtr(str, temp2);
storePtr(temp2, Address(temp, ProfileEntry::offsetOfString()));
loadPtr(script, temp2);
storePtr(temp2, Address(temp, ProfileEntry::offsetOfScript()));
storePtr(ImmWord((void*) 0), Address(temp, ProfileEntry::offsetOfStackAddress()));
// Store 0 for PCIdx because that's what interpreter does.
// (See Probes::enterScript, which calls spsProfiler.enter, which pushes an entry
// with 0 pcIdx).
store32(Imm32(0), Address(temp, ProfileEntry::offsetOfPCIdx()));
/* Always increment the stack size, whether or not we actually pushed. */
bind(&stackFull);

View File

@ -24,9 +24,9 @@ BaselineCompilerShared::BaselineCompilerShared(JSContext *cx, HandleScript scrip
pcMappingEntries_(),
icLoadLabels_(),
pushedBeforeCall_(0),
inCall_(false)
{
}
inCall_(false),
spsPushToggleOffset_()
{ }
bool
BaselineCompilerShared::callVM(const VMFunction &fun)

View File

@ -12,6 +12,7 @@
#include "ion/BaselineFrameInfo.h"
#include "ion/IonSpewer.h"
#include "ion/BaselineIC.h"
#include "ion/IonInstrumentation.h"
#include "ion/IonMacroAssembler.h"
namespace js {
@ -66,6 +67,8 @@ class BaselineCompilerShared
uint32_t pushedBeforeCall_;
mozilla::DebugOnly<bool> inCall_;
CodeOffsetLabel spsPushToggleOffset_;
BaselineCompilerShared(JSContext *cx, HandleScript script);
ICEntry *allocateICEntry(ICStub *stub, bool isForOp) {

View File

@ -16,6 +16,8 @@
#include "vm/SPSProfiler.h"
#include "vm/StringBuffer.h"
#include "ion/BaselineJIT.h"
using namespace js;
using mozilla::DebugOnly;
@ -66,6 +68,15 @@ SPSProfiler::enable(bool enabled)
* currently instrumented code is discarded
*/
ReleaseAllJITCode(rt->defaultFreeOp());
#ifdef JS_ION
/* Toggle SPS-related jumps on baseline jitcode.
* The call to |ReleaseAllJITCode| above will release most baseline jitcode, but not
* jitcode for scripts with active frames on the stack. These scripts need to have
* their profiler state toggled so they behave properly.
*/
ion::ToggleBaselineSPS(rt, enabled);
#endif
}
/* Lookup the string for the function/script, creating one if necessary */

View File

@ -134,7 +134,7 @@ class SPSProfiler
uint32_t *size_;
uint32_t max_;
bool slowAssertions;
bool enabled_;
uint32_t enabled_;
const char *allocProfileString(JSContext *cx, RawScript script,
RawFunction function);
@ -254,6 +254,10 @@ class SPSProfiler
/* meant to be used for testing, not recommended to call in normal code */
size_t stringsCount() { return strings.count(); }
void stringsReset() { strings.clear(); }
uint32_t *addressOfEnabled() {
return &enabled_;
}
};
/*