[turbofan] Use FastNewClosureStub if possible.
authormstarzinger <mstarzinger@chromium.org>
Mon, 27 Apr 2015 09:08:20 +0000 (02:08 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 27 Apr 2015 09:07:57 +0000 (09:07 +0000)
This introduces a JSCreateClosure operator which can be lowered by the
typed pipeline to the aforementioned stub. It also allows for further
optimizations of closure creation.

R=titzer@chromium.org

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

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

12 files changed:
src/code-factory.cc
src/code-factory.h
src/compiler/ast-graph-builder.cc
src/compiler/js-generic-lowering.cc
src/compiler/js-operator.cc
src/compiler/js-operator.h
src/compiler/js-typed-lowering.cc
src/compiler/js-typed-lowering.h
src/compiler/opcodes.h
src/compiler/typer.cc
src/compiler/verifier.cc
test/unittests/compiler/js-typed-lowering-unittest.cc

index c4063b9..7277448 100644 (file)
@@ -159,6 +159,15 @@ Callable CodeFactory::FastCloneShallowObject(Isolate* isolate, int length) {
 
 
 // static
+Callable CodeFactory::FastNewClosure(Isolate* isolate,
+                                     LanguageMode language_mode,
+                                     FunctionKind kind) {
+  FastNewClosureStub stub(isolate, language_mode, kind);
+  return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
+}
+
+
+// static
 Callable CodeFactory::AllocateHeapNumber(Isolate* isolate) {
   AllocateHeapNumberStub stub(isolate);
   return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
index 858cfba..16ef6d5 100644 (file)
@@ -69,6 +69,9 @@ class CodeFactory final {
   static Callable FastCloneShallowArray(Isolate* isolate);
   static Callable FastCloneShallowObject(Isolate* isolate, int length);
 
+  static Callable FastNewClosure(Isolate* isolate, LanguageMode language_mode,
+                                 FunctionKind kind);
+
   static Callable AllocateHeapNumber(Isolate* isolate);
 
   static Callable CallFunction(Isolate* isolate, int argc,
index 4e480d6..03fee58 100644 (file)
@@ -1476,10 +1476,9 @@ void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
   }
 
   // Create node to instantiate a new closure.
-  Node* info = jsgraph()->Constant(shared_info);
-  Node* pretenure = jsgraph()->BooleanConstant(expr->pretenure());
-  const Operator* op = javascript()->CallRuntime(Runtime::kNewClosure, 3);
-  Node* value = NewNode(op, context, info, pretenure);
+  PretenureFlag pretenure = expr->pretenure() ? TENURED : NOT_TENURED;
+  const Operator* op = javascript()->CreateClosure(shared_info, pretenure);
+  Node* value = NewNode(op, context);
   ast_context()->ProduceValue(value);
 }
 
index e8eab0f..611b5c9 100644 (file)
@@ -414,6 +414,14 @@ void JSGenericLowering::LowerJSStoreContext(Node* node) {
 }
 
 
+void JSGenericLowering::LowerJSCreateClosure(Node* node) {
+  CreateClosureParameters p = CreateClosureParametersOf(node->op());
+  node->InsertInput(zone(), 1, jsgraph()->HeapConstant(p.shared_info()));
+  node->InsertInput(zone(), 2, jsgraph()->BooleanConstant(p.pretenure()));
+  ReplaceWithRuntimeCall(node, Runtime::kNewClosure);
+}
+
+
 void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
   Unique<String> name = OpParameter<Unique<String>>(node);
   node->InsertInput(zone(), 0, jsgraph()->HeapConstant(name));
index 716592b..8812b6e 100644 (file)
@@ -208,6 +208,37 @@ const StoreNamedParameters& StoreNamedParametersOf(const Operator* op) {
 }
 
 
+bool operator==(CreateClosureParameters const& lhs,
+                CreateClosureParameters const& rhs) {
+  return lhs.pretenure() == rhs.pretenure() &&
+         lhs.shared_info().is_identical_to(rhs.shared_info());
+}
+
+
+bool operator!=(CreateClosureParameters const& lhs,
+                CreateClosureParameters const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+size_t hash_value(CreateClosureParameters const& p) {
+  // TODO(mstarzinger): Include hash of the SharedFunctionInfo here.
+  base::hash<PretenureFlag> h;
+  return h(p.pretenure());
+}
+
+
+std::ostream& operator<<(std::ostream& os, CreateClosureParameters const& p) {
+  return os << p.pretenure() << ", " << Brief(*p.shared_info());
+}
+
+
+const CreateClosureParameters& CreateClosureParametersOf(const Operator* op) {
+  DCHECK_EQ(IrOpcode::kJSCreateClosure, op->opcode());
+  return OpParameter<CreateClosureParameters>(op);
+}
+
+
 #define CACHED_OP_LIST(V)                                 \
   V(Equal, Operator::kNoProperties, 2, 1)                 \
   V(NotEqual, Operator::kNoProperties, 2, 1)              \
@@ -437,6 +468,17 @@ const Operator* JSOperatorBuilder::StoreContext(size_t depth, size_t index) {
 }
 
 
+const Operator* JSOperatorBuilder::CreateClosure(
+    Handle<SharedFunctionInfo> shared_info, PretenureFlag pretenure) {
+  CreateClosureParameters parameters(shared_info, pretenure);
+  return new (zone()) Operator1<CreateClosureParameters>(  // --
+      IrOpcode::kJSCreateClosure, Operator::kNoThrow,      // opcode
+      "JSCreateClosure",                                   // name
+      1, 1, 1, 1, 1, 0,                                    // counts
+      parameters);                                         // parameter
+}
+
+
 const Operator* JSOperatorBuilder::CreateCatchContext(
     const Unique<String>& name) {
   return new (zone()) Operator1<Unique<String>>(                 // --
index 0b6ec9c..bdb0c9c 100644 (file)
@@ -206,6 +206,32 @@ std::ostream& operator<<(std::ostream&, StoreNamedParameters const&);
 const StoreNamedParameters& StoreNamedParametersOf(const Operator* op);
 
 
+// Defines shared information for the closure that should be created. This is
+// used as a parameter by JSCreateClosure operators.
+class CreateClosureParameters final {
+ public:
+  CreateClosureParameters(Handle<SharedFunctionInfo> shared_info,
+                          PretenureFlag pretenure)
+      : shared_info_(shared_info), pretenure_(pretenure) {}
+
+  Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
+  PretenureFlag pretenure() const { return pretenure_; }
+
+ private:
+  const Handle<SharedFunctionInfo> shared_info_;
+  const PretenureFlag pretenure_;
+};
+
+bool operator==(CreateClosureParameters const&, CreateClosureParameters const&);
+bool operator!=(CreateClosureParameters const&, CreateClosureParameters const&);
+
+size_t hash_value(CreateClosureParameters const&);
+
+std::ostream& operator<<(std::ostream&, CreateClosureParameters const&);
+
+const CreateClosureParameters& CreateClosureParametersOf(const Operator* op);
+
+
 // Interface for building JavaScript-level operators, e.g. directly from the
 // AST. Most operators have no parameters, thus can be globally shared for all
 // graphs.
@@ -242,6 +268,8 @@ class JSOperatorBuilder final : public ZoneObject {
   const Operator* Yield();
 
   const Operator* Create();
+  const Operator* CreateClosure(Handle<SharedFunctionInfo> shared_info,
+                                PretenureFlag pretenure);
 
   const Operator* CallFunction(size_t arity, CallFunctionFlags flags);
   const Operator* CallRuntime(Runtime::FunctionId id, size_t arity);
index a3fbb66..554ef75 100644 (file)
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "src/code-factory.h"
 #include "src/compiler/access-builder.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/js-typed-lowering.h"
+#include "src/compiler/linkage.h"
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties.h"
 #include "src/compiler/operator-properties.h"
@@ -923,6 +925,32 @@ Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
 }
 
 
+Reduction JSTypedLowering::ReduceJSCreateClosure(Node* node) {
+  DCHECK_EQ(IrOpcode::kJSCreateClosure, node->opcode());
+  CreateClosureParameters const& p = CreateClosureParametersOf(node->op());
+  Handle<SharedFunctionInfo> shared = p.shared_info();
+
+  // Use the FastNewClosureStub that allocates in new space only for nested
+  // functions that don't need literals cloning.
+  if (p.pretenure() == NOT_TENURED && shared->num_literals() == 0) {
+    Isolate* isolate = jsgraph()->isolate();
+    Callable callable = CodeFactory::FastNewClosure(
+        isolate, shared->language_mode(), shared->kind());
+    CallDescriptor* desc = Linkage::GetStubCallDescriptor(
+        isolate, graph()->zone(), callable.descriptor(), 0,
+        CallDescriptor::kNoFlags);
+    const Operator* new_op = common()->Call(desc);
+    Node* stub_code = jsgraph()->HeapConstant(callable.code());
+    node->ReplaceInput(0, jsgraph()->HeapConstant(shared));
+    node->InsertInput(graph()->zone(), 0, stub_code);
+    node->set_op(new_op);
+    return Changed(node);
+  }
+
+  return NoChange();
+}
+
+
 Reduction JSTypedLowering::Reduce(Node* node) {
   // Check if the output type is a singleton.  In that case we already know the
   // result value and can simply replace the node if it's eliminable.
@@ -1009,6 +1037,8 @@ Reduction JSTypedLowering::Reduce(Node* node) {
       return ReduceJSLoadContext(node);
     case IrOpcode::kJSStoreContext:
       return ReduceJSStoreContext(node);
+    case IrOpcode::kJSCreateClosure:
+      return ReduceJSCreateClosure(node);
     default:
       break;
   }
index d9f2552..7f4b49e 100644 (file)
@@ -54,6 +54,7 @@ class JSTypedLowering final : public Reducer {
   Reduction ReduceJSToNumber(Node* node);
   Reduction ReduceJSToStringInput(Node* input);
   Reduction ReduceJSToString(Node* node);
+  Reduction ReduceJSCreateClosure(Node* node);
   Reduction ReduceNumberBinop(Node* node, const Operator* numberOp);
   Reduction ReduceInt32Binop(Node* node, const Operator* intOp);
   Reduction ReduceUI32Shift(Node* node, Signedness left_signedness,
index e79e911..39f7cdb 100644 (file)
 
 #define JS_OBJECT_OP_LIST(V) \
   V(JSCreate)                \
+  V(JSCreateClosure)         \
   V(JSLoadProperty)          \
   V(JSLoadNamed)             \
   V(JSStoreProperty)         \
index bcf315d..0e7d31c 100644 (file)
@@ -1311,6 +1311,11 @@ Bounds Typer::Visitor::TypeJSCreate(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeJSCreateClosure(Node* node) {
+  return Bounds(Type::None(), Type::OtherObject());
+}
+
+
 Type* Typer::Visitor::JSLoadPropertyTyper(Type* object, Type* name, Typer* t) {
   // TODO(rossberg): Use range types and sized array types to filter undefined.
   if (object->IsArray() && name->Is(Type::Integral32())) {
index e216428..733f8d7 100644 (file)
@@ -492,6 +492,10 @@ void Verifier::Visitor::Check(Node* node) {
       // Type is Object.
       CheckUpperIs(node, Type::Object());
       break;
+    case IrOpcode::kJSCreateClosure:
+      // Type is Function.
+      CheckUpperIs(node, Type::OtherObject());
+      break;
     case IrOpcode::kJSLoadProperty:
     case IrOpcode::kJSLoadNamed:
       // Type can be anything.
index 8652ed8..e269db0 100644 (file)
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "src/code-factory.h"
 #include "src/compiler/access-builder.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/js-operator.h"
@@ -14,6 +15,7 @@
 #include "test/unittests/compiler/node-test-utils.h"
 #include "testing/gmock-support.h"
 
+using testing::_;
 using testing::BitEq;
 using testing::IsNaN;
 
@@ -880,6 +882,30 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedGlobalConstants) {
   }
 }
 
+
+// -----------------------------------------------------------------------------
+// JSCreateClosure
+
+
+TEST_F(JSTypedLoweringTest, JSCreateClosure) {
+  Node* const context = UndefinedConstant();
+  Node* const effect = graph()->start();
+  Node* const control = graph()->start();
+  Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
+  Reduction r =
+      Reduce(graph()->NewNode(javascript()->CreateClosure(shared, NOT_TENURED),
+                              context, context, effect, control));
+  ASSERT_TRUE(r.Changed());
+  EXPECT_THAT(
+      r.replacement(),
+      IsCall(_,
+             IsHeapConstant(Unique<HeapObject>::CreateImmovable(
+                 CodeFactory::FastNewClosure(isolate(), shared->language_mode(),
+                                             shared->kind()).code())),
+             IsHeapConstant(Unique<HeapObject>::CreateImmovable(shared)),
+             effect, control));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8