mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge.
This commit is contained in:
commit
7f0a88535b
@ -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();
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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_;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user