mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1030095 - Remove restriction on inlining recursive calls. r=hv1989
This commit is contained in:
parent
e25f29c619
commit
92c1f56d86
@ -150,7 +150,6 @@ namespace JS {
|
||||
_(CantInlineClassConstructor) \
|
||||
_(CantInlineDisabledIon) \
|
||||
_(CantInlineTooManyArgs) \
|
||||
_(CantInlineRecursive) \
|
||||
_(CantInlineHeavyweight) \
|
||||
_(CantInlineNeedsArgsObj) \
|
||||
_(CantInlineDebuggee) \
|
||||
@ -168,6 +167,7 @@ namespace JS {
|
||||
_(CantInlineNativeNoTemplateObj) \
|
||||
_(CantInlineBound) \
|
||||
_(CantInlineNativeNoSpecialization) \
|
||||
_(HasCommonInliningPath) \
|
||||
\
|
||||
_(GenericSuccess) \
|
||||
_(Inlined) \
|
||||
|
@ -372,6 +372,59 @@ IonBuilder::DontInline(JSScript* targetScript, const char* reason)
|
||||
return InliningDecision_DontInline;
|
||||
}
|
||||
|
||||
/*
|
||||
* |hasCommonInliningPath| determines whether the current inlining path has been
|
||||
* seen before based on the sequence of scripts in the chain of |IonBuilder|s.
|
||||
*
|
||||
* An inlining path for a function |f| is the sequence of functions whose
|
||||
* inlinings precede |f| up to any previous occurrences of |f|.
|
||||
* So, if we have the chain of inlinings
|
||||
*
|
||||
* f1 -> f2 -> f -> f3 -> f4 -> f5 -> f
|
||||
* -------- --------------
|
||||
*
|
||||
* the inlining paths for |f| are [f2, f1] and [f5, f4, f3].
|
||||
* When attempting to inline |f|, we find all existing inlining paths for |f|
|
||||
* and check whether they share a common prefix with the path created were |f|
|
||||
* inlined.
|
||||
*
|
||||
* For example, given mutually recursive functions |f| and |g|, a possible
|
||||
* inlining is
|
||||
*
|
||||
* +---- Inlining stopped here...
|
||||
* |
|
||||
* v
|
||||
* a -> f -> g -> f \ -> g -> f -> g -> ...
|
||||
*
|
||||
* where the vertical bar denotes the termination of inlining.
|
||||
* Inlining is terminated because we have already observed the inlining path
|
||||
* [f] when inlining function |g|. Note that this will inline recursive
|
||||
* functions such as |fib| only one level, as |fib| has a zero length inlining
|
||||
* path which trivially prefixes all inlining paths.
|
||||
*
|
||||
*/
|
||||
bool
|
||||
IonBuilder::hasCommonInliningPath(const JSScript* scriptToInline)
|
||||
{
|
||||
if (this->script() == scriptToInline)
|
||||
return true;
|
||||
|
||||
// Find all previous inlinings of the |scriptToInline| and check for common
|
||||
// inlining paths with the top of the inlining stack.
|
||||
for (IonBuilder* it = this; it; it = it->callerBuilder_) {
|
||||
if (it->script() != scriptToInline)
|
||||
continue;
|
||||
|
||||
// This only needs to check the top of each stack for a match,
|
||||
// as a match of length one ensures a common prefix.
|
||||
IonBuilder* path = it->callerBuilder_;
|
||||
if (!path || this->script() == path->script())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IonBuilder::InliningDecision
|
||||
IonBuilder::canInlineTarget(JSFunction* target, CallInfo& callInfo)
|
||||
{
|
||||
@ -468,14 +521,9 @@ IonBuilder::canInlineTarget(JSFunction* target, CallInfo& callInfo)
|
||||
return DontInline(inlineScript, "Too many actual args");
|
||||
}
|
||||
|
||||
// Allow inlining of recursive calls, but only one level deep.
|
||||
IonBuilder* builder = callerBuilder_;
|
||||
while (builder) {
|
||||
if (builder->script() == inlineScript) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineRecursive);
|
||||
return DontInline(inlineScript, "Recursive call");
|
||||
}
|
||||
builder = builder->callerBuilder_;
|
||||
if (hasCommonInliningPath(inlineScript)) {
|
||||
trackOptimizationOutcome(TrackedOutcome::HasCommonInliningPath);
|
||||
return DontInline(inlineScript, "Common inlining path");
|
||||
}
|
||||
|
||||
if (target->isHeavyweight()) {
|
||||
|
@ -720,6 +720,9 @@ class IonBuilder
|
||||
|
||||
static InliningDecision DontInline(JSScript* targetScript, const char* reason);
|
||||
|
||||
// Helper function for canInlineTarget
|
||||
bool hasCommonInliningPath(const JSScript* scriptToInline);
|
||||
|
||||
// Oracles.
|
||||
InliningDecision canInlineTarget(JSFunction* target, CallInfo& callInfo);
|
||||
InliningDecision makeInliningDecision(JSObject* target, CallInfo& callInfo);
|
||||
|
Loading…
Reference in New Issue
Block a user