[turbofan] Model arguments object materialization in graph.
authormstarzinger <mstarzinger@chromium.org>
Tue, 15 Sep 2015 09:07:21 +0000 (02:07 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 15 Sep 2015 09:07:34 +0000 (09:07 +0000)
This models the materialization of arguments objects in the prologue
within the IR graph. It will in turn allow us to optimize access to
these objects and also correctly handle them with inlining.

R=bmeurer@chromium.org,mvstanton@chromium.org
TEST=cctest/test-run-jsobjects/Arguments*

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

Cr-Commit-Position: refs/heads/master@{#30735}

src/compiler/ast-graph-builder.cc
src/compiler/js-generic-lowering.cc
src/compiler/js-operator.cc
src/compiler/js-operator.h
src/compiler/opcodes.h
src/compiler/typer.cc
src/compiler/verifier.cc
test/cctest/cctest.gyp
test/cctest/compiler/test-run-jsobjects.cc [new file with mode: 0644]

index 52d4a47..6718535 100644 (file)
@@ -3152,7 +3152,11 @@ Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
 
   // Allocate and initialize a new arguments object.
   Node* callee = GetFunctionClosure();
-  const Operator* op = javascript()->CallRuntime(Runtime::kNewArguments, 1);
+  CreateArgumentsParameters::Type type =
+      is_strict(language_mode()) || !info()->has_simple_parameters()
+          ? CreateArgumentsParameters::kUnmappedArguments
+          : CreateArgumentsParameters::kMappedArguments;
+  const Operator* op = javascript()->CreateArguments(type, 0);
   Node* object = NewNode(op, callee);
 
   // Assign the object to the arguments variable.
index 60b0c2e..c7c6b1f 100644 (file)
@@ -115,6 +115,7 @@ REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSGreaterThanOrEqual, Token::GTE)
     ReplaceWithRuntimeCall(node, fun);            \
   }
 REPLACE_RUNTIME_CALL(JSCreate, Runtime::kAbort)
+REPLACE_RUNTIME_CALL(JSCreateArguments, Runtime::kNewArguments)
 REPLACE_RUNTIME_CALL(JSCreateFunctionContext, Runtime::kNewFunctionContext)
 REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext)
 REPLACE_RUNTIME_CALL(JSCreateBlockContext, Runtime::kPushBlockContext)
index c486e02..975ca0c 100644 (file)
@@ -391,6 +391,28 @@ const StorePropertyParameters& StorePropertyParametersOf(const Operator* op) {
 }
 
 
+bool operator==(CreateArgumentsParameters const& lhs,
+                CreateArgumentsParameters const& rhs) {
+  return lhs.type() == rhs.type() && lhs.start_index() == rhs.start_index();
+}
+
+
+bool operator!=(CreateArgumentsParameters const& lhs,
+                CreateArgumentsParameters const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(CreateArgumentsParameters const& p) {
+  return base::hash_combine(p.type(), p.start_index());
+}
+
+
+std::ostream& operator<<(std::ostream& os, CreateArgumentsParameters const& p) {
+  return os << p.type() << ", " << p.start_index();
+}
+
+
 bool operator==(CreateClosureParameters const& lhs,
                 CreateClosureParameters const& rhs) {
   return lhs.pretenure() == rhs.pretenure() &&
@@ -705,6 +727,18 @@ const Operator* JSOperatorBuilder::LoadDynamicContext(
 }
 
 
+const Operator* JSOperatorBuilder::CreateArguments(
+    CreateArgumentsParameters::Type type, int start_index) {
+  DCHECK_IMPLIES(start_index, type == CreateArgumentsParameters::kRestArray);
+  CreateArgumentsParameters parameters(type, start_index);
+  return new (zone()) Operator1<CreateArgumentsParameters>(  // --
+      IrOpcode::kJSCreateArguments, Operator::kNoThrow,      // opcode
+      "JSCreateArguments",                                   // name
+      1, 1, 1, 1, 1, 0,                                      // counts
+      parameters);                                           // parameter
+}
+
+
 const Operator* JSOperatorBuilder::CreateClosure(
     Handle<SharedFunctionInfo> shared_info, PretenureFlag pretenure) {
   CreateClosureParameters parameters(shared_info, pretenure);
index 4776a8f..2c281e7 100644 (file)
@@ -407,6 +407,32 @@ std::ostream& operator<<(std::ostream&, StorePropertyParameters const&);
 const StorePropertyParameters& StorePropertyParametersOf(const Operator* op);
 
 
+// Defines specifics about arguments object or rest parameter creation. This is
+// used as a parameter by JSCreateArguments operators.
+class CreateArgumentsParameters final {
+ public:
+  enum Type { kMappedArguments, kUnmappedArguments, kRestArray };
+  CreateArgumentsParameters(Type type, int start_index)
+      : type_(type), start_index_(start_index) {}
+
+  Type type() const { return type_; }
+  int start_index() const { return start_index_; }
+
+ private:
+  const Type type_;
+  const int start_index_;
+};
+
+bool operator==(CreateArgumentsParameters const&,
+                CreateArgumentsParameters const&);
+bool operator!=(CreateArgumentsParameters const&,
+                CreateArgumentsParameters const&);
+
+size_t hash_value(CreateArgumentsParameters const&);
+
+std::ostream& operator<<(std::ostream&, CreateArgumentsParameters const&);
+
+
 // Defines shared information for the closure that should be created. This is
 // used as a parameter by JSCreateClosure operators.
 class CreateClosureParameters final {
@@ -469,6 +495,8 @@ class JSOperatorBuilder final : public ZoneObject {
   const Operator* Yield();
 
   const Operator* Create();
+  const Operator* CreateArguments(CreateArgumentsParameters::Type type,
+                                  int start_index);
   const Operator* CreateClosure(Handle<SharedFunctionInfo> shared_info,
                                 PretenureFlag pretenure);
   const Operator* CreateLiteralArray(int literal_flags);
index c5b6c81..2b49b63 100644 (file)
 
 #define JS_OBJECT_OP_LIST(V) \
   V(JSCreate)                \
+  V(JSCreateArguments)       \
   V(JSCreateClosure)         \
   V(JSCreateLiteralArray)    \
   V(JSCreateLiteralObject)   \
index 6724668..e1b7108 100644 (file)
@@ -1179,6 +1179,11 @@ Bounds Typer::Visitor::TypeJSCreate(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeJSCreateArguments(Node* node) {
+  return Bounds(Type::None(), Type::OtherObject());
+}
+
+
 Bounds Typer::Visitor::TypeJSCreateClosure(Node* node) {
   return Bounds(Type::None(), Type::OtherObject());
 }
index 595d9be..3d4fefd 100644 (file)
@@ -511,6 +511,10 @@ void Verifier::Visitor::Check(Node* node) {
       // Type is Object.
       CheckUpperIs(node, Type::Object());
       break;
+    case IrOpcode::kJSCreateArguments:
+      // Type is OtherObject.
+      CheckUpperIs(node, Type::OtherObject());
+      break;
     case IrOpcode::kJSCreateClosure:
       // Type is Function.
       CheckUpperIs(node, Type::OtherObject());
index 0a9d535..94a1473 100644 (file)
@@ -75,6 +75,7 @@
         'compiler/test-run-jsbranches.cc',
         'compiler/test-run-jscalls.cc',
         'compiler/test-run-jsexceptions.cc',
+        'compiler/test-run-jsobjects.cc',
         'compiler/test-run-jsops.cc',
         'compiler/test-run-machops.cc',
         'compiler/test-run-native-calls.cc',
diff --git a/test/cctest/compiler/test-run-jsobjects.cc b/test/cctest/compiler/test-run-jsobjects.cc
new file mode 100644 (file)
index 0000000..242de4d
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2015 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.
+
+#include "test/cctest/compiler/function-tester.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+TEST(ArgumentsMapped) {
+  FunctionTester T("(function(a) { return arguments; })");
+
+  Handle<Object> arguments;
+  T.Call(T.Val(19), T.Val(23), T.Val(42), T.Val(65)).ToHandle(&arguments);
+  CHECK(arguments->IsJSObject() && !arguments->IsJSArray());
+  CHECK(JSObject::cast(*arguments)->HasSloppyArgumentsElements());
+  Handle<String> l = T.isolate->factory()->length_string();
+  Handle<Object> length = JSObject::GetProperty(arguments, l).ToHandleChecked();
+  CHECK_EQ(4, length->Number());
+}
+
+
+TEST(ArgumentsUnmapped) {
+  FunctionTester T("(function(a) { 'use strict'; return arguments; })");
+
+  Handle<Object> arguments;
+  T.Call(T.Val(19), T.Val(23), T.Val(42), T.Val(65)).ToHandle(&arguments);
+  CHECK(arguments->IsJSObject() && !arguments->IsJSArray());
+  CHECK(!JSObject::cast(*arguments)->HasSloppyArgumentsElements());
+  Handle<String> l = T.isolate->factory()->length_string();
+  Handle<Object> length = JSObject::GetProperty(arguments, l).ToHandleChecked();
+  CHECK_EQ(4, length->Number());
+}
+
+
+TEST(ArgumentsRest) {
+  FLAG_harmony_rest_parameters = true;
+  FunctionTester T("(function(a, ...args) { return args; })");
+
+  Handle<Object> arguments;
+  T.Call(T.Val(19), T.Val(23), T.Val(42), T.Val(65)).ToHandle(&arguments);
+  CHECK(arguments->IsJSObject() && arguments->IsJSArray());
+  CHECK(!JSObject::cast(*arguments)->HasSloppyArgumentsElements());
+  Handle<String> l = T.isolate->factory()->length_string();
+  Handle<Object> length = JSObject::GetProperty(arguments, l).ToHandleChecked();
+  CHECK_EQ(3, length->Number());
+}