Bug 823884: Make call uninlineable when aborting during inlining, r=nbp

This commit is contained in:
Hannes Verschore 2012-12-28 21:33:07 +01:00
Родитель e4b89b0500
Коммит b3a11b3d2a
6 изменённых файлов: 54 добавлений и 17 удалений

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

@ -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();
} }