Allow inlining of functions containing %_Arguments.
authormstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 27 Jun 2014 11:04:35 +0000 (11:04 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 27 Jun 2014 11:04:35 +0000 (11:04 +0000)
R=svenpanne@chromium.org
TEST=mjsunit/compiler/inline-arguments

Review URL: https://codereview.chromium.org/356773002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22060 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/ast.cc
src/hydrogen.cc
test/mjsunit/compiler/inline-arguments.js

index 5939eb1..edea0f5 100644 (file)
@@ -1114,11 +1114,6 @@ void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
     // Don't try to inline JS runtime calls because we don't (currently) even
     // optimize them.
     add_flag(kDontInline);
-  } else if (node->function()->intrinsic_type == Runtime::INLINE &&
-             node->raw_name()->IsOneByteEqualTo("_Arguments")) {
-    // Don't inline the %_Arguments because it's implementation will not work.
-    // There is no stack frame to get them from.
-    add_flag(kDontInline);
   }
 }
 
index d447bbc..89f61de 100644 (file)
@@ -7738,19 +7738,19 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target,
   HConstant* context = Add<HConstant>(Handle<Context>(target->context()));
   inner_env->BindContext(context);
 
-  HArgumentsObject* arguments_object = NULL;
-
-  // If the function uses arguments object create and bind one, also copy
+  // Create a dematerialized arguments object for the function, also copy the
   // current arguments values to use them for materialization.
+  HEnvironment* arguments_env = inner_env->arguments_environment();
+  int parameter_count = arguments_env->parameter_count();
+  HArgumentsObject* arguments_object = Add<HArgumentsObject>(parameter_count);
+  for (int i = 0; i < parameter_count; i++) {
+    arguments_object->AddArgument(arguments_env->Lookup(i), zone());
+  }
+
+  // If the function uses arguments object then bind bind one.
   if (function->scope()->arguments() != NULL) {
     ASSERT(function->scope()->arguments()->IsStackAllocated());
-    HEnvironment* arguments_env = inner_env->arguments_environment();
-    int arguments_count = arguments_env->parameter_count();
-    arguments_object = Add<HArgumentsObject>(arguments_count);
     inner_env->Bind(function->scope()->arguments(), arguments_object);
-    for (int i = 0; i < arguments_count; i++) {
-      arguments_object->AddArgument(arguments_env->Lookup(i), zone());
-    }
   }
 
   // Capture the state before invoking the inlined function for deopt in the
@@ -11326,18 +11326,26 @@ void HOptimizedGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
 
 
 void HOptimizedGraphBuilder::GenerateArguments(CallRuntime* call) {
-  // Our implementation of arguments (based on this stack frame or an
-  // adapter below it) does not work for inlined functions.  This runtime
-  // function is blacklisted by AstNode::IsInlineable.
-  ASSERT(function_state()->outer() == NULL);
   ASSERT(call->arguments()->length() == 1);
   CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
   HValue* index = Pop();
-  HInstruction* elements = Add<HArgumentsElements>(false);
-  HInstruction* length = Add<HArgumentsLength>(elements);
-  HInstruction* checked_index = Add<HBoundsCheck>(index, length);
-  HAccessArgumentsAt* result = New<HAccessArgumentsAt>(
-      elements, length, checked_index);
+  HInstruction* result = NULL;
+  if (function_state()->outer() == NULL) {
+    HInstruction* elements = Add<HArgumentsElements>(false);
+    HInstruction* length = Add<HArgumentsLength>(elements);
+    HInstruction* checked_index = Add<HBoundsCheck>(index, length);
+    result = New<HAccessArgumentsAt>(elements, length, checked_index);
+  } else {
+    EnsureArgumentsArePushedForAccess();
+
+    // Number of arguments without receiver.
+    HInstruction* elements = function_state()->arguments_elements();
+    int argument_count = environment()->
+        arguments_environment()->parameter_count() - 1;
+    HInstruction* length = Add<HConstant>(argument_count);
+    HInstruction* checked_key = Add<HBoundsCheck>(index, length);
+    result = New<HAccessArgumentsAt>(elements, length, checked_key);
+  }
   return ast_context()->ReturnInstruction(result, call->id());
 }
 
index 1337ab2..d52f31b 100644 (file)
@@ -309,3 +309,29 @@ test_toarr(toarr2);
   delete forceDeopt.deopt;
   outer();
 })();
+
+
+// Test inlining of functions with %_Arguments and %_ArgumentsLength intrinsic.
+(function () {
+  function inner(len,a,b,c) {
+    assertSame(len, %_ArgumentsLength());
+    for (var i = 1; i < len; ++i) {
+      var c = String.fromCharCode(96 + i);
+      assertSame(c, %_Arguments(i));
+    }
+  }
+
+  function outer() {
+    inner(1);
+    inner(2, 'a');
+    inner(3, 'a', 'b');
+    inner(4, 'a', 'b', 'c');
+    inner(5, 'a', 'b', 'c', 'd');
+    inner(6, 'a', 'b', 'c', 'd', 'e');
+  }
+
+  outer();
+  outer();
+  %OptimizeFunctionOnNextCall(outer);
+  outer();
+})();