зеркало из https://github.com/mozilla/gecko-dev.git
Bug 823884: Make call uninlineable when aborting during inlining, r=nbp
This commit is contained in:
Родитель
e4b89b0500
Коммит
b3a11b3d2a
|
@ -1135,7 +1135,7 @@ AttachFinishedCompilations(JSContext *cx)
|
||||||
static const size_t BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12;
|
static const size_t BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12;
|
||||||
|
|
||||||
template <typename CompileContext>
|
template <typename CompileContext>
|
||||||
static bool
|
static AbortReason
|
||||||
IonCompile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrPc, bool constructing,
|
IonCompile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrPc, bool constructing,
|
||||||
CompileContext &compileContext)
|
CompileContext &compileContext)
|
||||||
{
|
{
|
||||||
|
@ -1149,31 +1149,31 @@ IonCompile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *o
|
||||||
|
|
||||||
LifoAlloc *alloc = cx->new_<LifoAlloc>(BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
|
LifoAlloc *alloc = cx->new_<LifoAlloc>(BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
|
||||||
if (!alloc)
|
if (!alloc)
|
||||||
return false;
|
return AbortReason_Alloc;
|
||||||
|
|
||||||
AutoDestroyAllocator autoDestroy(alloc);
|
AutoDestroyAllocator autoDestroy(alloc);
|
||||||
|
|
||||||
TempAllocator *temp = alloc->new_<TempAllocator>(alloc);
|
TempAllocator *temp = alloc->new_<TempAllocator>(alloc);
|
||||||
if (!temp)
|
if (!temp)
|
||||||
return false;
|
return AbortReason_Alloc;
|
||||||
|
|
||||||
IonContext ictx(cx, cx->compartment, temp);
|
IonContext ictx(cx, cx->compartment, temp);
|
||||||
|
|
||||||
if (!cx->compartment->ensureIonCompartmentExists(cx))
|
if (!cx->compartment->ensureIonCompartmentExists(cx))
|
||||||
return false;
|
return AbortReason_Alloc;
|
||||||
|
|
||||||
MIRGraph *graph = alloc->new_<MIRGraph>(temp);
|
MIRGraph *graph = alloc->new_<MIRGraph>(temp);
|
||||||
ExecutionMode executionMode = compileContext.executionMode();
|
ExecutionMode executionMode = compileContext.executionMode();
|
||||||
CompileInfo *info = alloc->new_<CompileInfo>(script, fun, osrPc, constructing,
|
CompileInfo *info = alloc->new_<CompileInfo>(script, fun, osrPc, constructing,
|
||||||
executionMode);
|
executionMode);
|
||||||
if (!info)
|
if (!info)
|
||||||
return false;
|
return AbortReason_Alloc;
|
||||||
|
|
||||||
types::AutoEnterTypeInference enter(cx, true);
|
types::AutoEnterTypeInference enter(cx, true);
|
||||||
TypeInferenceOracle oracle;
|
TypeInferenceOracle oracle;
|
||||||
|
|
||||||
if (!oracle.init(cx, script))
|
if (!oracle.init(cx, script))
|
||||||
return false;
|
return AbortReason_Disable;
|
||||||
|
|
||||||
AutoFlushCache afc("IonCompile");
|
AutoFlushCache afc("IonCompile");
|
||||||
|
|
||||||
|
@ -1185,10 +1185,10 @@ IonCompile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *o
|
||||||
IonBuilder *builder = alloc->new_<IonBuilder>(cx, temp, graph, &oracle, info);
|
IonBuilder *builder = alloc->new_<IonBuilder>(cx, temp, graph, &oracle, info);
|
||||||
if (!compileContext.compile(builder, graph, autoDestroy)) {
|
if (!compileContext.compile(builder, graph, autoDestroy)) {
|
||||||
IonSpew(IonSpew_Abort, "IM Compilation failed.");
|
IonSpew(IonSpew_Abort, "IM Compilation failed.");
|
||||||
return false;
|
return builder->abortReason();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return AbortReason_NoAbort;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1245,16 +1245,27 @@ SequentialCompileContext::compile(IonBuilder *builder, MIRGraph *graph,
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
MethodStatus
|
||||||
TestIonCompile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrPc, bool constructing)
|
TestIonCompile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrPc, bool constructing)
|
||||||
{
|
{
|
||||||
SequentialCompileContext compileContext;
|
SequentialCompileContext compileContext;
|
||||||
if (!IonCompile(cx, script, fun, osrPc, constructing, compileContext)) {
|
|
||||||
|
AbortReason reason = IonCompile(cx, script, fun, osrPc, constructing, compileContext);
|
||||||
|
|
||||||
|
if (reason == AbortReason_Alloc)
|
||||||
|
return Method_Skipped;
|
||||||
|
|
||||||
|
if (reason == AbortReason_Inlining)
|
||||||
|
return Method_Skipped;
|
||||||
|
|
||||||
|
if (reason == AbortReason_Disable) {
|
||||||
if (!cx->isExceptionPending())
|
if (!cx->isExceptionPending())
|
||||||
ForbidCompilation(cx, script);
|
ForbidCompilation(cx, script);
|
||||||
return false;
|
return Method_CantCompile;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
JS_ASSERT(reason == AbortReason_NoAbort);
|
||||||
|
return Method_Compiled;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -1370,10 +1381,12 @@ Compile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrP
|
||||||
}
|
}
|
||||||
|
|
||||||
SequentialCompileContext compileContext;
|
SequentialCompileContext compileContext;
|
||||||
if (!IonCompile(cx, script, fun, osrPc, constructing, compileContext))
|
|
||||||
|
AbortReason reason = IonCompile(cx, script, fun, osrPc, constructing, compileContext);
|
||||||
|
if (reason == AbortReason_Disable)
|
||||||
return Method_CantCompile;
|
return Method_CantCompile;
|
||||||
|
|
||||||
// Compilation succeeded, but we invalidated right away.
|
// Compilation succeeded or we invalidated right away or an inlining/alloc abort
|
||||||
return script->hasIonScript() ? Method_Compiled : Method_Skipped;
|
return script->hasIonScript() ? Method_Compiled : Method_Skipped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -211,6 +211,13 @@ enum MethodStatus
|
||||||
Method_Compiled
|
Method_Compiled
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum AbortReason {
|
||||||
|
AbortReason_Alloc,
|
||||||
|
AbortReason_Inlining,
|
||||||
|
AbortReason_Disable,
|
||||||
|
AbortReason_NoAbort
|
||||||
|
};
|
||||||
|
|
||||||
// An Ion context is needed to enter into either an Ion method or an instance
|
// An Ion context is needed to enter into either an Ion method or an instance
|
||||||
// of the Ion compiler. It points to a temporary allocator and the active
|
// of the Ion compiler. It points to a temporary allocator and the active
|
||||||
// JSContext, either of which may be NULL, and the active compartment, which
|
// JSContext, either of which may be NULL, and the active compartment, which
|
||||||
|
@ -296,7 +303,7 @@ class CodeGenerator;
|
||||||
CodeGenerator *CompileBackEnd(MIRGenerator *mir);
|
CodeGenerator *CompileBackEnd(MIRGenerator *mir);
|
||||||
void AttachFinishedCompilations(JSContext *cx);
|
void AttachFinishedCompilations(JSContext *cx);
|
||||||
void FinishOffThreadBuilder(IonBuilder *builder);
|
void FinishOffThreadBuilder(IonBuilder *builder);
|
||||||
bool TestIonCompile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrPc, bool constructing);
|
MethodStatus TestIonCompile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrPc, bool constructing);
|
||||||
|
|
||||||
static inline bool IsEnabled(JSContext *cx)
|
static inline bool IsEnabled(JSContext *cx)
|
||||||
{
|
{
|
||||||
|
|
|
@ -35,6 +35,7 @@ IonBuilder::IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph,
|
||||||
backgroundCodegen_(NULL),
|
backgroundCodegen_(NULL),
|
||||||
recompileInfo(cx->compartment->types.compiledInfo),
|
recompileInfo(cx->compartment->types.compiledInfo),
|
||||||
cx(cx),
|
cx(cx),
|
||||||
|
abortReason_(AbortReason_Disable),
|
||||||
loopDepth_(loopDepth),
|
loopDepth_(loopDepth),
|
||||||
callerResumePoint_(NULL),
|
callerResumePoint_(NULL),
|
||||||
callerBuilder_(NULL),
|
callerBuilder_(NULL),
|
||||||
|
@ -360,6 +361,7 @@ IonBuilder::build()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JS_ASSERT(loopDepth_ == 0);
|
JS_ASSERT(loopDepth_ == 0);
|
||||||
|
abortReason_ = AbortReason_NoAbort;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3172,8 +3174,16 @@ IonBuilder::jsop_call_inline(HandleFunction callee, uint32_t argc, bool construc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the graph.
|
// Build the graph.
|
||||||
if (!inlineBuilder.buildInline(this, inlineResumePoint, thisDefn, argv))
|
if (!inlineBuilder.buildInline(this, inlineResumePoint, thisDefn, argv)) {
|
||||||
|
JS_ASSERT(calleeScript->hasAnalysis());
|
||||||
|
|
||||||
|
// Inlining the callee failed. Disable inlining the function
|
||||||
|
if (inlineBuilder.abortReason_ == AbortReason_Disable)
|
||||||
|
calleeScript->analysis()->setIonUninlineable();
|
||||||
|
|
||||||
|
abortReason_ = AbortReason_Inlining;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
MIRGraphExits &exits = *inlineBuilder.graph().exitAccumulator();
|
MIRGraphExits &exits = *inlineBuilder.graph().exitAccumulator();
|
||||||
|
|
||||||
|
|
|
@ -492,8 +492,11 @@ class IonBuilder : public MIRGenerator
|
||||||
CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; }
|
CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; }
|
||||||
void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; }
|
void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; }
|
||||||
|
|
||||||
|
AbortReason abortReason() { return abortReason_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSContext *cx;
|
JSContext *cx;
|
||||||
|
AbortReason abortReason_;
|
||||||
|
|
||||||
jsbytecode *pc;
|
jsbytecode *pc;
|
||||||
MBasicBlock *current;
|
MBasicBlock *current;
|
||||||
|
|
|
@ -888,6 +888,7 @@ class ScriptAnalysis
|
||||||
bool failed() const { return hadFailure; }
|
bool failed() const { return hadFailure; }
|
||||||
bool ionInlineable() const { return isIonInlineable; }
|
bool ionInlineable() const { return isIonInlineable; }
|
||||||
bool ionInlineable(uint32_t argc) const { return isIonInlineable && argc == script_->function()->nargs; }
|
bool ionInlineable(uint32_t argc) const { return isIonInlineable && argc == script_->function()->nargs; }
|
||||||
|
void setIonUninlineable() { isIonInlineable = false; }
|
||||||
bool jaegerInlineable() const { return isJaegerInlineable; }
|
bool jaegerInlineable() const { return isJaegerInlineable; }
|
||||||
bool jaegerInlineable(uint32_t argc) const { return isJaegerInlineable && argc == script_->function()->nargs; }
|
bool jaegerInlineable(uint32_t argc) const { return isJaegerInlineable && argc == script_->function()->nargs; }
|
||||||
bool jaegerCompileable() { return isJaegerCompileable; }
|
bool jaegerCompileable() { return isJaegerCompileable; }
|
||||||
|
|
|
@ -839,7 +839,10 @@ stubs::TriggerIonCompile(VMFrame &f)
|
||||||
osrPC = NULL;
|
osrPC = NULL;
|
||||||
|
|
||||||
RootedFunction scriptFunction(f.cx, script->function());
|
RootedFunction scriptFunction(f.cx, script->function());
|
||||||
if (!ion::TestIonCompile(f.cx, script, scriptFunction, osrPC, f.fp()->isConstructing())) {
|
ion::MethodStatus compileStatus =
|
||||||
|
ion::TestIonCompile(f.cx, script, scriptFunction, osrPC, f.fp()->isConstructing());
|
||||||
|
|
||||||
|
if (compileStatus != ion::Method_Compiled) {
|
||||||
if (f.cx->isExceptionPending())
|
if (f.cx->isExceptionPending())
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче