Bug 1214059: Baseline: Enable switch to debug mode at function entry, r=jandem

This commit is contained in:
Hannes Verschore 2016-01-22 08:07:52 -05:00
Родитель 9eb5f1349b
Коммит 63117a51eb
10 изменённых файлов: 253 добавлений и 189 удалений

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

@ -702,6 +702,10 @@ BaselineCompiler::emitInterruptCheck()
return true;
}
typedef bool (*IonCompileScriptForBaselineFn)(JSContext*, BaselineFrame*, jsbytecode*);
static const VMFunction IonCompileScriptForBaselineInfo =
FunctionInfo<IonCompileScriptForBaselineFn>(IonCompileScriptForBaseline);
bool
BaselineCompiler::emitWarmUpCounterIncrement(bool allowOsr)
{
@ -711,6 +715,8 @@ BaselineCompiler::emitWarmUpCounterIncrement(bool allowOsr)
if (!ionCompileable_ && !ionOSRCompileable_)
return true;
frame.assertSyncedStack();
Register scriptReg = R2.scratchReg();
Register countReg = R0.scratchReg();
Address warmUpCounterAddr(scriptReg, JSScript::offsetOfWarmUpCounter());
@ -743,11 +749,28 @@ BaselineCompiler::emitWarmUpCounterIncrement(bool allowOsr)
Address(scriptReg, JSScript::offsetOfIonScript()),
ImmPtr(ION_COMPILING_SCRIPT), &skipCall);
// Call IC.
ICWarmUpCounter_Fallback::Compiler stubCompiler(cx);
if (!emitNonOpIC(stubCompiler.getStub(&stubSpace_)))
return false;
// Try to compile and/or finish a compilation.
if (JSOp(*pc) == JSOP_LOOPENTRY) {
// During the loop entry we can try to OSR into ion.
// The ic has logic for this.
ICWarmUpCounter_Fallback::Compiler stubCompiler(cx);
if (!emitNonOpIC(stubCompiler.getStub(&stubSpace_)))
return false;
} else {
// To call stubs we need to have an opcode. This code handles the
// prologue and there is no dedicatd opcode present. Therefore use an
// annotated vm call.
prepareVMCall();
masm.Push(ImmPtr(pc));
masm.PushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
if (!callVM(IonCompileScriptForBaselineInfo))
return false;
// Annotate the ICEntry as warmup counter.
icEntries_.back().setFakeKind(ICEntry::Kind_WarmupCounter);
}
masm.bind(&skipCall);
return true;

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

@ -101,6 +101,7 @@ struct DebugModeOSREntry
bool needsRecompileInfo() const {
return frameKind == ICEntry::Kind_CallVM ||
frameKind == ICEntry::Kind_WarmupCounter ||
frameKind == ICEntry::Kind_StackCheck ||
frameKind == ICEntry::Kind_EarlyStackCheck ||
frameKind == ICEntry::Kind_DebugTrap ||
@ -298,6 +299,8 @@ ICEntryKindToString(ICEntry::Kind kind)
return "non-op IC";
case ICEntry::Kind_CallVM:
return "callVM";
case ICEntry::Kind_WarmupCounter:
return "warmup counter";
case ICEntry::Kind_StackCheck:
return "stack check";
case ICEntry::Kind_EarlyStackCheck:
@ -359,6 +362,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const Debugger::ExecutionObservab
// B. From a VM call.
// H. From inside HandleExceptionBaseline.
// I. From inside the interrupt handler via the prologue stack check.
// J. From the warmup counter in the prologue.
//
// On to Off:
// - All the ways above.
@ -367,10 +371,10 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const Debugger::ExecutionObservab
// E. From the debug epilogue.
//
// Off to On to Off:
// F. Undo case B or I above on previously patched yet unpopped frames.
// F. Undo case B, I or J above on previously patched yet unpopped frames.
//
// On to Off to On:
// G. Undo cases B, C, D, E, or I above on previously patched yet unpopped
// G. Undo cases B, C, D, E, I or J above on previously patched yet unpopped
// frames.
//
// In general, we patch the return address from the VM call to return to a
@ -456,7 +460,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const Debugger::ExecutionObservab
// Cases F and G above.
//
// We undo a previous recompile by handling cases B, C, D, E, or I
// We undo a previous recompile by handling cases B, C, D, E, I or J
// like normal, except that we retrieve the pc information via
// the previous OSR debug info stashed on the frame.
BaselineDebugModeOSRInfo* info = iter.baselineFrame()->getDebugModeOSRInfo();
@ -464,17 +468,19 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const Debugger::ExecutionObservab
MOZ_ASSERT(info->pc == pc);
MOZ_ASSERT(info->frameKind == kind);
// Case G, might need to undo B, C, D, E, or I.
// Case G, might need to undo B, C, D, E, I or J.
MOZ_ASSERT_IF(script->baselineScript()->hasDebugInstrumentation(),
kind == ICEntry::Kind_CallVM ||
kind == ICEntry::Kind_WarmupCounter ||
kind == ICEntry::Kind_StackCheck ||
kind == ICEntry::Kind_EarlyStackCheck ||
kind == ICEntry::Kind_DebugTrap ||
kind == ICEntry::Kind_DebugPrologue ||
kind == ICEntry::Kind_DebugEpilogue);
// Case F, should only need to undo case B or I.
// Case F, should only need to undo case B, I or J.
MOZ_ASSERT_IF(!script->baselineScript()->hasDebugInstrumentation(),
kind == ICEntry::Kind_CallVM ||
kind == ICEntry::Kind_WarmupCounter||
kind == ICEntry::Kind_StackCheck ||
kind == ICEntry::Kind_EarlyStackCheck);
@ -505,6 +511,18 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const Debugger::ExecutionObservab
break;
}
case ICEntry::Kind_WarmupCounter: {
// Case J above.
//
// Patching mechanism is identical to a CallVM. This is
// handled especially only because the warmup counter VM call is
// part of the prologue, and not tied an opcode.
ICEntry& warmupCountEntry = bl->warmupCountICEntry();
recompInfo->resumeAddr = bl->returnAddressForIC(warmupCountEntry);
popFrameReg = false;
break;
}
case ICEntry::Kind_StackCheck:
case ICEntry::Kind_EarlyStackCheck: {
// Case I above.
@ -956,6 +974,7 @@ IsReturningFromCallVM(BaselineDebugModeOSRInfo* info)
// The stack check entries are returns from a callVM, but have a special
// kind because they do not exist in a 1-1 relationship with a pc offset.
return info->frameKind == ICEntry::Kind_CallVM ||
info->frameKind == ICEntry::Kind_WarmupCounter ||
info->frameKind == ICEntry::Kind_StackCheck ||
info->frameKind == ICEntry::Kind_EarlyStackCheck;
}
@ -973,6 +992,7 @@ EmitBranchIsReturningFromCallVM(MacroAssembler& masm, Register entry, Label* lab
{
// Keep this in sync with IsReturningFromCallVM.
EmitBranchICEntryKind(masm, entry, ICEntry::Kind_CallVM, label);
EmitBranchICEntryKind(masm, entry, ICEntry::Kind_WarmupCounter, label);
EmitBranchICEntryKind(masm, entry, ICEntry::Kind_StackCheck, label);
EmitBranchICEntryKind(masm, entry, ICEntry::Kind_EarlyStackCheck, label);
}

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

@ -50,66 +50,6 @@ namespace jit {
// WarmUpCounter_Fallback
//
static bool
EnsureCanEnterIon(JSContext* cx, ICWarmUpCounter_Fallback* stub, BaselineFrame* frame,
HandleScript script, jsbytecode* pc, void** jitcodePtr)
{
MOZ_ASSERT(jitcodePtr);
MOZ_ASSERT(!*jitcodePtr);
bool isLoopEntry = (JSOp(*pc) == JSOP_LOOPENTRY);
MethodStatus stat;
if (isLoopEntry) {
MOZ_ASSERT(LoopEntryCanIonOsr(pc));
JitSpew(JitSpew_BaselineOSR, " Compile at loop entry!");
stat = CanEnterAtBranch(cx, script, frame, pc);
} else if (frame->isFunctionFrame()) {
JitSpew(JitSpew_BaselineOSR, " Compile function from top for later entry!");
stat = CompileFunctionForBaseline(cx, script, frame);
} else {
return true;
}
if (stat == Method_Error) {
JitSpew(JitSpew_BaselineOSR, " Compile with Ion errored!");
return false;
}
if (stat == Method_CantCompile)
JitSpew(JitSpew_BaselineOSR, " Can't compile with Ion!");
else if (stat == Method_Skipped)
JitSpew(JitSpew_BaselineOSR, " Skipped compile with Ion!");
else if (stat == Method_Compiled)
JitSpew(JitSpew_BaselineOSR, " Compiled with Ion!");
else
MOZ_CRASH("Invalid MethodStatus!");
// Failed to compile. Reset warm-up counter and return.
if (stat != Method_Compiled) {
// TODO: If stat == Method_CantCompile, insert stub that just skips the
// warm-up counter entirely, instead of resetting it.
bool bailoutExpected = script->hasIonScript() && script->ionScript()->bailoutExpected();
if (stat == Method_CantCompile || bailoutExpected) {
JitSpew(JitSpew_BaselineOSR, " Reset WarmUpCounter cantCompile=%s bailoutExpected=%s!",
stat == Method_CantCompile ? "yes" : "no",
bailoutExpected ? "yes" : "no");
script->resetWarmUpCounter();
}
return true;
}
if (isLoopEntry) {
IonScript* ion = script->ionScript();
MOZ_ASSERT(cx->runtime()->spsProfiler.enabled() == ion->hasProfilingInstrumentation());
MOZ_ASSERT(ion->osrPc() == pc);
JitSpew(JitSpew_BaselineOSR, " OSR possible!");
*jitcodePtr = ion->method()->raw() + ion->osrEntryOffset();
}
return true;
}
//
// The following data is kept in a temporary heap-allocated buffer, stored in
@ -184,56 +124,33 @@ PrepareOsrTempData(JSContext* cx, ICWarmUpCounter_Fallback* stub, BaselineFrame*
}
static bool
DoWarmUpCounterFallback(JSContext* cx, BaselineFrame* frame, ICWarmUpCounter_Fallback* stub,
IonOsrTempData** infoPtr)
DoWarmUpCounterFallbackOSR(JSContext* cx, BaselineFrame* frame, ICWarmUpCounter_Fallback* stub,
IonOsrTempData** infoPtr)
{
MOZ_ASSERT(infoPtr);
*infoPtr = nullptr;
// A TI OOM will disable TI and Ion.
if (!jit::IsIonEnabled(cx))
return true;
RootedScript script(cx, frame->script());
jsbytecode* pc = stub->icEntry()->pc(script);
bool isLoopEntry = JSOp(*pc) == JSOP_LOOPENTRY;
MOZ_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY);
MOZ_ASSERT(!isLoopEntry || LoopEntryCanIonOsr(pc));
FallbackICSpew(cx, stub, "WarmUpCounter(%d)", int(script->pcToOffset(pc)));
FallbackICSpew(cx, stub, "WarmUpCounter(%d)", isLoopEntry ? int(script->pcToOffset(pc)) : int(-1));
if (!script->canIonCompile()) {
// TODO: ASSERT that ion-compilation-disabled checker stub doesn't exist.
// TODO: Clear all optimized stubs.
// TODO: Add a ion-compilation-disabled checker IC stub
script->resetWarmUpCounter();
return true;
}
MOZ_ASSERT(!script->isIonCompilingOffThread());
// If Ion script exists, but PC is not at a loop entry, then Ion will be entered for
// this script at an appropriate LOOPENTRY or the next time this function is called.
if (script->hasIonScript() && !isLoopEntry) {
JitSpew(JitSpew_BaselineOSR, "IonScript exists, but not at loop entry!");
// TODO: ASSERT that a ion-script-already-exists checker stub doesn't exist.
// TODO: Clear all optimized stubs.
// TODO: Add a ion-script-already-exists checker stub.
return true;
}
// Ensure that Ion-compiled code is available.
JitSpew(JitSpew_BaselineOSR,
"WarmUpCounter for %s:%" PRIuSIZE " reached %d at pc %p, trying to switch to Ion!",
script->filename(), script->lineno(), (int) script->getWarmUpCount(), (void*) pc);
void* jitcode = nullptr;
if (!EnsureCanEnterIon(cx, stub, frame, script, pc, &jitcode))
if (!IonCompileScriptForBaseline(cx, frame, pc))
return false;
// Jitcode should only be set here if not at loop entry.
MOZ_ASSERT_IF(!isLoopEntry, !jitcode);
if (!jitcode)
if (!script->hasIonScript() || script->ionScript()->osrPc() != pc ||
script->ionScript()->bailoutExpected())
{
return true;
}
IonScript* ion = script->ionScript();
MOZ_ASSERT(cx->runtime()->spsProfiler.enabled() == ion->hasProfilingInstrumentation());
MOZ_ASSERT(ion->osrPc() == pc);
JitSpew(JitSpew_BaselineOSR, " OSR possible!");
void* jitcode = ion->method()->raw() + ion->osrEntryOffset();
// Prepare the temporary heap copy of the fake InterpreterFrame and actual args list.
JitSpew(JitSpew_BaselineOSR, "Got jitcode. Preparing for OSR into ion.");
@ -245,10 +162,10 @@ DoWarmUpCounterFallback(JSContext* cx, BaselineFrame* frame, ICWarmUpCounter_Fal
return true;
}
typedef bool (*DoWarmUpCounterFallbackFn)(JSContext*, BaselineFrame*,
ICWarmUpCounter_Fallback*, IonOsrTempData** infoPtr);
static const VMFunction DoWarmUpCounterFallbackInfo =
FunctionInfo<DoWarmUpCounterFallbackFn>(DoWarmUpCounterFallback);
typedef bool (*DoWarmUpCounterFallbackOSRFn)(JSContext*, BaselineFrame*,
ICWarmUpCounter_Fallback*, IonOsrTempData** infoPtr);
static const VMFunction DoWarmUpCounterFallbackOSRInfo =
FunctionInfo<DoWarmUpCounterFallbackOSRFn>(DoWarmUpCounterFallbackOSR);
bool
ICWarmUpCounter_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
@ -259,7 +176,7 @@ ICWarmUpCounter_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
enterStubFrame(masm, R1.scratchReg());
Label noCompiledCode;
// Call DoWarmUpCounterFallback to compile/check-for Ion-compiled function
// Call DoWarmUpCounterFallbackOSR to compile/check-for Ion-compiled function
{
// Push IonOsrTempData pointer storage
masm.subFromStackPtr(Imm32(sizeof(void*)));
@ -270,7 +187,7 @@ ICWarmUpCounter_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
pushStubPayload(masm, R0.scratchReg());
if (!callVM(DoWarmUpCounterFallbackInfo, masm))
if (!callVM(DoWarmUpCounterFallbackOSRInfo, masm))
return false;
// Pop IonOsrTempData pointer.

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

@ -3467,6 +3467,8 @@ IsCacheableDOMProxy(JSObject* obj)
return handler->family() == GetDOMProxyHandlerFamily();
}
struct IonOsrTempData;
} // namespace jit
} // namespace js

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

@ -697,6 +697,18 @@ BaselineScript::stackCheckICEntry(bool earlyCheck)
MOZ_CRASH("No stack check ICEntry found.");
}
ICEntry&
BaselineScript::warmupCountICEntry()
{
// The stack check will be at a very low offset, so just do a linear search
// from the beginning.
for (size_t i = 0; i < numICEntries() && icEntry(i).pcOffset() == 0; i++) {
if (icEntry(i).kind() == ICEntry::Kind_WarmupCounter)
return icEntry(i);
}
MOZ_CRASH("No warmup count ICEntry found.");
}
ICEntry&
BaselineScript::icEntryFromReturnAddress(uint8_t* returnAddr)
{

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

@ -370,6 +370,7 @@ struct BaselineScript
ICEntry& icEntryFromPCOffset(uint32_t pcOffset, ICEntry* prevLookedUpEntry);
ICEntry& callVMEntryFromPCOffset(uint32_t pcOffset);
ICEntry& stackCheckICEntry(bool earlyCheck);
ICEntry& warmupCountICEntry();
ICEntry& icEntryFromReturnAddress(uint8_t* returnAddr);
uint8_t* returnAddressForIC(const ICEntry& ent);

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

@ -2483,76 +2483,6 @@ jit::OffThreadCompilationAvailable(JSContext* cx)
&& CanUseExtraThreads();
}
// Decide if a transition from interpreter execution to Ion code should occur.
// May compile or recompile the target JSScript.
MethodStatus
jit::CanEnterAtBranch(JSContext* cx, HandleScript script, BaselineFrame* osrFrame, jsbytecode* pc)
{
MOZ_ASSERT(jit::IsIonEnabled(cx));
MOZ_ASSERT((JSOp)*pc == JSOP_LOOPENTRY);
MOZ_ASSERT(LoopEntryCanIonOsr(pc));
// Skip if the script has been disabled.
if (!script->canIonCompile())
return Method_Skipped;
// Skip if the script is being compiled off thread.
if (script->isIonCompilingOffThread())
return Method_Skipped;
// Skip if the code is expected to result in a bailout.
if (script->hasIonScript() && script->ionScript()->bailoutExpected())
return Method_Skipped;
// Optionally ignore on user request.
if (!JitOptions.osr)
return Method_Skipped;
// Mark as forbidden if frame can't be handled.
if (!CheckFrame(cx, osrFrame)) {
ForbidCompilation(cx, script);
return Method_CantCompile;
}
// Check if the jitcode still needs to get linked and do this
// to have a valid IonScript.
if (script->baselineScript()->hasPendingIonBuilder())
LazyLink(cx, script);
// By default a recompilation doesn't happen on osr mismatch.
// Decide if we want to force a recompilation if this happens too much.
bool force = false;
if (script->hasIonScript() && pc != script->ionScript()->osrPc()) {
uint32_t count = script->ionScript()->incrOsrPcMismatchCounter();
if (count <= JitOptions.osrPcMismatchesBeforeRecompile)
return Method_Skipped;
force = true;
}
// Attempt compilation.
// - Returns Method_Compiled if the right ionscript is present
// (Meaning it was present or a sequantial compile finished)
// - Returns Method_Skipped if pc doesn't match
// (This means a background thread compilation with that pc could have started or not.)
RootedScript rscript(cx, script);
MethodStatus status = Compile(cx, rscript, osrFrame, pc, osrFrame->isConstructing(),
force);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);
return status;
}
// Return the compilation was skipped when the osr pc wasn't adjusted.
// This can happen when there was still an IonScript available and a
// background compilation started, but hasn't finished yet.
// Or when we didn't force a recompile.
if (script->hasIonScript() && pc != script->ionScript()->osrPc())
return Method_Skipped;
return Method_Compiled;
}
MethodStatus
jit::CanEnter(JSContext* cx, RunState& state)
{
@ -2627,8 +2557,8 @@ jit::CanEnter(JSContext* cx, RunState& state)
return Method_Compiled;
}
MethodStatus
jit::CompileFunctionForBaseline(JSContext* cx, HandleScript script, BaselineFrame* frame)
static MethodStatus
BaselineCanEnterAtEntry(JSContext* cx, HandleScript script, BaselineFrame* frame)
{
MOZ_ASSERT(jit::IsIonEnabled(cx));
MOZ_ASSERT(frame->callee()->nonLazyScript()->canIonCompile());
@ -2653,6 +2583,157 @@ jit::CompileFunctionForBaseline(JSContext* cx, HandleScript script, BaselineFram
return Method_Compiled;
}
// Decide if a transition from baseline execution to Ion code should occur.
// May compile or recompile the target JSScript.
static MethodStatus
BaselineCanEnterAtBranch(JSContext* cx, HandleScript script, BaselineFrame* osrFrame, jsbytecode* pc)
{
MOZ_ASSERT(jit::IsIonEnabled(cx));
MOZ_ASSERT((JSOp)*pc == JSOP_LOOPENTRY);
MOZ_ASSERT(LoopEntryCanIonOsr(pc));
// Skip if the script has been disabled.
if (!script->canIonCompile())
return Method_Skipped;
// Skip if the script is being compiled off thread.
if (script->isIonCompilingOffThread())
return Method_Skipped;
// Skip if the code is expected to result in a bailout.
if (script->hasIonScript() && script->ionScript()->bailoutExpected())
return Method_Skipped;
// Optionally ignore on user request.
if (!JitOptions.osr)
return Method_Skipped;
// Mark as forbidden if frame can't be handled.
if (!CheckFrame(cx, osrFrame)) {
ForbidCompilation(cx, script);
return Method_CantCompile;
}
// Check if the jitcode still needs to get linked and do this
// to have a valid IonScript.
if (script->baselineScript()->hasPendingIonBuilder())
LazyLink(cx, script);
// By default a recompilation doesn't happen on osr mismatch.
// Decide if we want to force a recompilation if this happens too much.
bool force = false;
if (script->hasIonScript() && pc != script->ionScript()->osrPc()) {
uint32_t count = script->ionScript()->incrOsrPcMismatchCounter();
if (count <= JitOptions.osrPcMismatchesBeforeRecompile)
return Method_Skipped;
force = true;
}
// Attempt compilation.
// - Returns Method_Compiled if the right ionscript is present
// (Meaning it was present or a sequantial compile finished)
// - Returns Method_Skipped if pc doesn't match
// (This means a background thread compilation with that pc could have started or not.)
RootedScript rscript(cx, script);
MethodStatus status = Compile(cx, rscript, osrFrame, pc, osrFrame->isConstructing(),
force);
if (status != Method_Compiled) {
if (status == Method_CantCompile)
ForbidCompilation(cx, script);
return status;
}
// Return the compilation was skipped when the osr pc wasn't adjusted.
// This can happen when there was still an IonScript available and a
// background compilation started, but hasn't finished yet.
// Or when we didn't force a recompile.
if (script->hasIonScript() && pc != script->ionScript()->osrPc())
return Method_Skipped;
return Method_Compiled;
}
bool
jit::IonCompileScriptForBaseline(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
{
// A TI OOM will disable TI and Ion.
if (!jit::IsIonEnabled(cx))
return true;
RootedScript script(cx, frame->script());
bool isLoopEntry = JSOp(*pc) == JSOP_LOOPENTRY;
MOZ_ASSERT(!isLoopEntry || LoopEntryCanIonOsr(pc));
if (!script->canIonCompile()) {
// TODO: ASSERT that ion-compilation-disabled checker stub doesn't exist.
// TODO: Clear all optimized stubs.
// TODO: Add a ion-compilation-disabled checker IC stub
script->resetWarmUpCounter();
return true;
}
MOZ_ASSERT(!script->isIonCompilingOffThread());
// If Ion script exists, but PC is not at a loop entry, then Ion will be entered for
// this script at an appropriate LOOPENTRY or the next time this function is called.
if (script->hasIonScript() && !isLoopEntry) {
JitSpew(JitSpew_BaselineOSR, "IonScript exists, but not at loop entry!");
// TODO: ASSERT that a ion-script-already-exists checker stub doesn't exist.
// TODO: Clear all optimized stubs.
// TODO: Add a ion-script-already-exists checker stub.
return true;
}
// Ensure that Ion-compiled code is available.
JitSpew(JitSpew_BaselineOSR,
"WarmUpCounter for %s:%" PRIuSIZE " reached %d at pc %p, trying to switch to Ion!",
script->filename(), script->lineno(), (int) script->getWarmUpCount(), (void*) pc);
MethodStatus stat;
if (isLoopEntry) {
MOZ_ASSERT(LoopEntryCanIonOsr(pc));
JitSpew(JitSpew_BaselineOSR, " Compile at loop entry!");
stat = BaselineCanEnterAtBranch(cx, script, frame, pc);
} else if (frame->isFunctionFrame()) {
JitSpew(JitSpew_BaselineOSR, " Compile function from top for later entry!");
stat = BaselineCanEnterAtEntry(cx, script, frame);
} else {
return true;
}
if (stat == Method_Error) {
JitSpew(JitSpew_BaselineOSR, " Compile with Ion errored!");
return false;
}
if (stat == Method_CantCompile)
JitSpew(JitSpew_BaselineOSR, " Can't compile with Ion!");
else if (stat == Method_Skipped)
JitSpew(JitSpew_BaselineOSR, " Skipped compile with Ion!");
else if (stat == Method_Compiled)
JitSpew(JitSpew_BaselineOSR, " Compiled with Ion!");
else
MOZ_CRASH("Invalid MethodStatus!");
// Failed to compile. Reset warm-up counter and return.
if (stat != Method_Compiled) {
// TODO: If stat == Method_CantCompile, insert stub that just skips the
// warm-up counter entirely, instead of resetting it.
bool bailoutExpected = script->hasIonScript() && script->ionScript()->bailoutExpected();
if (stat == Method_CantCompile || bailoutExpected) {
JitSpew(JitSpew_BaselineOSR, " Reset WarmUpCounter cantCompile=%s bailoutExpected=%s!",
stat == Method_CantCompile ? "yes" : "no",
bailoutExpected ? "yes" : "no");
script->resetWarmUpCounter();
}
return true;
}
return true;
}
MethodStatus
jit::Recompile(JSContext* cx, HandleScript script, BaselineFrame* osrFrame, jsbytecode* osrPc,
bool constructing, bool force)

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

@ -83,10 +83,9 @@ void SetJitContext(JitContext* ctx);
bool CanIonCompileScript(JSContext* cx, JSScript* script, bool osr);
MethodStatus CanEnterAtBranch(JSContext* cx, HandleScript script,
BaselineFrame* frame, jsbytecode* pc);
bool IonCompileScriptForBaseline(JSContext* cx, BaselineFrame* frame, jsbytecode* pc);
MethodStatus CanEnter(JSContext* cx, RunState& state);
MethodStatus CompileFunctionForBaseline(JSContext* cx, HandleScript script, BaselineFrame* frame);
MethodStatus CanEnterUsingFastInvoke(JSContext* cx, HandleScript script, uint32_t numActualArgs);
MethodStatus

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

@ -1398,6 +1398,11 @@ class MacroAssembler : public MacroAssemblerSpecific
push(scratch);
}
void PushBaselineFramePtr(Register framePtr, Register scratch) {
loadBaselineFramePtr(framePtr, scratch);
Push(scratch);
}
private:
void handleFailure();

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

@ -240,6 +240,10 @@ class ICEntry
// the prologue).
Kind_NonOpCallVM,
// A fake IC entry for returning from a callVM to after the
// warmup counter.
Kind_WarmupCounter,
// A fake IC entry for returning from a callVM to the interrupt
// handler via the over-recursion check on function entry.
Kind_StackCheck,