Reviewers: Jakob,
Message:
PTAL
Description:
Do not bailout from optimizing functions that use f(x, arguments)
if there is not enough type-feedback to detect that f is
Function.prototype.apply.
BUG=v8:3709
LOG=N
TEST=mjsunit/regress/regress-3709
Please review this at https://codereview.chromium.org/736043002/
Base URL: https://chromium.googlesource.com/v8/v8.git@master
Affected files (+85, -14 lines):
M src/hydrogen.h
M src/hydrogen.cc
A test/mjsunit/regress/regress-3709.js
Index: src/hydrogen.cc
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index
003f4aefeee384ae8847cb3ece5576d56adce4ec..942b3a80859de92e8db71c7e8c535951df2e1993
100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -4074,8 +4074,12 @@ void EffectContext::ReturnValue(HValue* value) {
void ValueContext::ReturnValue(HValue* value) {
// The value is tracked in the bailout environment, and communicated
// through the environment as the result of the expression.
- if (!arguments_allowed() && value->CheckFlag(HValue::kIsArguments)) {
- owner()->Bailout(kBadValueContextForArgumentsValue);
+ if (value->CheckFlag(HValue::kIsArguments)) {
+ if (flag_ == ARGUMENTS_FAKED) {
+ value = owner()->graph()->GetConstantUndefined();
+ } else if (!arguments_allowed()) {
+ owner()->Bailout(kBadValueContextForArgumentsValue);
+ }
}
owner()->Push(value);
}
@@ -4301,6 +4305,14 @@ void HOptimizedGraphBuilder::VisitExpressions(
}
+void HOptimizedGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs,
+ ArgumentsAllowedFlag flag) {
+ for (int i = 0; i < exprs->length(); ++i) {
+ CHECK_ALIVE(VisitForValue(exprs->at(i), flag));
+ }
+}
+
+
bool HOptimizedGraphBuilder::BuildGraph() {
if (current_info()->function()->is_generator()) {
Bailout(kFunctionIsAGenerator);
@@ -8885,13 +8897,8 @@ bool HOptimizedGraphBuilder::TryIndirectCall(Call*
expr) {
// is supported.
if (current_info()->scope()->arguments() == NULL) return false;
- ZoneList<Expression*>* args = expr->arguments();
- if (args->length() != 2) return false;
+ if (!CanBeFunctionApplyArguments(expr, true)) return false;
- VariableProxy* arg_two = args->at(1)->AsVariableProxy();
- if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return
false;
- HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
- if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
BuildFunctionApply(expr);
return true;
}
@@ -9178,6 +9185,20 @@ bool
HOptimizedGraphBuilder::TryHandleArrayCallNew(CallNew* expr,
}
+bool HOptimizedGraphBuilder::CanBeFunctionApplyArguments(
+ Call* expr, bool mark_arguments_as_live) {
+ ZoneList<Expression*>* args = expr->arguments();
+ if (args->length() != 2) return false;
+ VariableProxy* arg_two = args->at(1)->AsVariableProxy();
+ if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
+ HValue* arg_two_value = mark_arguments_as_live
+ ? LookupAndMakeLive(arg_two->var())
+ : Lookup(arg_two->var());
+ if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
+ return true;
+}
+
+
void HOptimizedGraphBuilder::VisitCall(Call* expr) {
DCHECK(!HasStackOverflow());
DCHECK(current_block() != NULL);
@@ -9214,13 +9235,14 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
- // Push the function under the receiver.
- environment()->SetExpressionStackAt(0, function);
- Push(receiver);
if (function->IsConstant() &&
HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
+ // Push the function under the receiver.
+ environment()->SetExpressionStackAt(0, function);
+ Push(receiver);
+
Handle<JSFunction> known_function = Handle<JSFunction>::cast(
HConstant::cast(function)->handle(isolate()));
expr->set_target(known_function);
@@ -9256,7 +9278,18 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
}
} else {
- CHECK_ALIVE(VisitExpressions(expr->arguments()));
+ ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED;
+ if (CanBeFunctionApplyArguments(expr, false)) {
+ Add<HDeoptimize>("Insufficient type feedback for call with
arguments",
+ Deoptimizer::EAGER);
+ arguments_flag = ARGUMENTS_FAKED;
+ }
+
+ // Push the function under the receiver.
+ environment()->SetExpressionStackAt(0, function);
+ Push(receiver);
+
+ CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag));
CallFunctionFlags flags = receiver->type().IsJSObject()
? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD;
call = New<HCallFunction>(function, argument_count, flags);
Index: src/hydrogen.h
diff --git a/src/hydrogen.h b/src/hydrogen.h
index
43388464cb0d9d03b588730213b99332ca4b1acc..164a06a5f3ee15114aee746fae3bc70a64a67ff5
100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -748,7 +748,8 @@ class HOptimizedGraphBuilder;
enum ArgumentsAllowedFlag {
ARGUMENTS_NOT_ALLOWED,
- ARGUMENTS_ALLOWED
+ ARGUMENTS_ALLOWED,
+ ARGUMENTS_FAKED
};
@@ -2261,7 +2262,11 @@ class HOptimizedGraphBuilder : public HGraphBuilder,
public AstVisitor {
#endif
}
}
-
+ HValue* Lookup(Variable* var) {
+ HEnvironment* env = environment();
+ int index = env->IndexFor(var);
+ return env->Lookup(index);
+ }
HValue* LookupAndMakeLive(Variable* var) {
HEnvironment* env = environment();
int index = env->IndexFor(var);
@@ -2290,6 +2295,8 @@ class HOptimizedGraphBuilder : public HGraphBuilder,
public AstVisitor {
// Visit a list of expressions from left to right, each in a value
context.
void VisitExpressions(ZoneList<Expression*>* exprs);
+ void VisitExpressions(ZoneList<Expression*>* exprs,
+ ArgumentsAllowedFlag flag);
// Remove the arguments from the bailout environment and emit
instructions
// to push them as outgoing parameters.
@@ -2723,6 +2730,8 @@ class HOptimizedGraphBuilder : public HGraphBuilder,
public AstVisitor {
HInstruction* BuildCallConstantFunction(Handle<JSFunction> target,
int argument_count);
+ bool CanBeFunctionApplyArguments(Call* expr, bool
mark_arguments_as_live);
+
// The translation state of the currently-being-translated function.
FunctionState* function_state_;
Index: test/mjsunit/regress/regress-3709.js
diff --git a/test/mjsunit/regress/regress-3709.js
b/test/mjsunit/regress/regress-3709.js
new file mode 100644
index
0000000000000000000000000000000000000000..f4e820e528807a098c4f6863c8baca4190710b47
--- /dev/null
+++ b/test/mjsunit/regress/regress-3709.js
@@ -0,0 +1,29 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function getobj() {
+ return { bar : function() { return 0}};
+}
+
+function foo() {
+ var obj = getobj();
+ var length = arguments.length;
+ if (length == 0) {
+ obj.bar();
+ } else {
+ obj.bar.apply(obj, arguments);
+ }
+}
+
+foo();
+foo();
+%OptimizeFunctionOnNextCall(foo);
+foo();
+if (%GetOptimizationStatus(foo) != 4) {
+ assertEquals(1, %GetOptimizationStatus(foo));
+ foo(10);
+ assertEquals(2, %GetOptimizationStatus(foo));
+}
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.