Force pretenuring of closures that are immediately assigned to
authorager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 22 Nov 2010 09:57:21 +0000 (09:57 +0000)
committerager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 22 Nov 2010 09:57:21 +0000 (09:57 +0000)
properties. For these closures we would like to be able to use
constant functions and for that we need the closures allocated in old
space.
Review URL: http://codereview.chromium.org/5220007

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

18 files changed:
src/arm/code-stubs-arm.cc
src/arm/codegen-arm.cc
src/arm/codegen-arm.h
src/arm/full-codegen-arm.cc
src/ast.h
src/full-codegen.cc
src/full-codegen.h
src/ia32/code-stubs-ia32.cc
src/ia32/codegen-ia32.cc
src/ia32/codegen-ia32.h
src/ia32/full-codegen-ia32.cc
src/parser.cc
src/runtime.cc
src/runtime.h
src/x64/code-stubs-x64.cc
src/x64/codegen-x64.cc
src/x64/codegen-x64.h
src/x64/full-codegen-x64.cc

index b3b0766a8f347bba34994cd1aa301ae5aff6797b..76a610b7be21dcbbfca1e995eaa2c11f286d7e34 100644 (file)
@@ -100,8 +100,9 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
 
   // Create a new closure through the slower runtime call.
   __ bind(&gc);
-  __ Push(cp, r3);
-  __ TailCallRuntime(Runtime::kNewClosure, 2, 1);
+  __ LoadRoot(r4, Heap::kFalseValueRootIndex);
+  __ Push(cp, r3, r4);
+  __ TailCallRuntime(Runtime::kNewClosure, 3, 1);
 }
 
 
index fe7ea8bd80ff4de08ccf0e50c8a426a97a183a97..3e6743afafa08abe5bf0f5529b357ed08a92e6b5 100644 (file)
@@ -3103,10 +3103,13 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
 
 
 void CodeGenerator::InstantiateFunction(
-    Handle<SharedFunctionInfo> function_info) {
+    Handle<SharedFunctionInfo> function_info,
+    bool pretenure) {
   // Use the fast case closure allocation code that allocates in new
   // space for nested functions that don't need literals cloning.
-  if (scope()->is_function_scope() && function_info->num_literals() == 0) {
+  if (scope()->is_function_scope() &&
+      function_info->num_literals() == 0 &&
+      !pretenure) {
     FastNewClosureStub stub;
     frame_->EmitPush(Operand(function_info));
     frame_->SpillAll();
@@ -3116,7 +3119,10 @@ void CodeGenerator::InstantiateFunction(
     // Create a new closure.
     frame_->EmitPush(cp);
     frame_->EmitPush(Operand(function_info));
-    frame_->CallRuntime(Runtime::kNewClosure, 2);
+    frame_->EmitPush(Operand(pretenure
+                             ? Factory::true_value()
+                             : Factory::false_value()));
+    frame_->CallRuntime(Runtime::kNewClosure, 3);
     frame_->EmitPush(r0);
   }
 }
@@ -3136,7 +3142,7 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
     ASSERT(frame_->height() == original_height);
     return;
   }
-  InstantiateFunction(function_info);
+  InstantiateFunction(function_info, node->pretenure());
   ASSERT_EQ(original_height + 1, frame_->height());
 }
 
@@ -3147,7 +3153,7 @@ void CodeGenerator::VisitSharedFunctionInfoLiteral(
   int original_height = frame_->height();
 #endif
   Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
-  InstantiateFunction(node->shared_function_info());
+  InstantiateFunction(node->shared_function_info(), false);
   ASSERT_EQ(original_height + 1, frame_->height());
 }
 
index 9495f1b6088bb97e8cf491172d4f78e02626e32e..6905d2331e935762a188caa83662df56a1a39c7d 100644 (file)
@@ -449,7 +449,8 @@ class CodeGenerator: public AstVisitor {
   void DeclareGlobals(Handle<FixedArray> pairs);
 
   // Instantiate the function based on the shared function info.
-  void InstantiateFunction(Handle<SharedFunctionInfo> function_info);
+  void InstantiateFunction(Handle<SharedFunctionInfo> function_info,
+                           bool pretenure);
 
   // Support for type checks.
   void GenerateIsSmi(ZoneList<Expression*>* args);
index f0fa5a77494b226402ba723e4031b5aee3983238..f04015bd787b1473ab114accc318c2efa55064d0 100644 (file)
@@ -860,18 +860,23 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
 }
 
 
-void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
+void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
+                                       bool pretenure) {
   // Use the fast case closure allocation code that allocates in new
   // space for nested functions that don't need literals cloning.
-  if (scope()->is_function_scope() && info->num_literals() == 0) {
+  if (scope()->is_function_scope() &&
+      info->num_literals() == 0 &&
+      !pretenure) {
     FastNewClosureStub stub;
     __ mov(r0, Operand(info));
     __ push(r0);
     __ CallStub(&stub);
   } else {
     __ mov(r0, Operand(info));
-    __ Push(cp, r0);
-    __ CallRuntime(Runtime::kNewClosure, 2);
+    __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex
+                              : Heap::kFalseValueRootIndex);
+    __ Push(cp, r0, r1);
+    __ CallRuntime(Runtime::kNewClosure, 3);
   }
   context()->Plug(r0);
 }
index 04c297757014f941a6f1fcab8bf18ea624c6e470..0846dbc537fb1280b66c8c95e80287c1296a7aec 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -1416,7 +1416,8 @@ class FunctionLiteral: public Expression {
         contains_loops_(contains_loops),
         function_token_position_(RelocInfo::kNoPosition),
         inferred_name_(Heap::empty_string()),
-        try_full_codegen_(false) {
+        try_full_codegen_(false),
+        pretenure_(false) {
 #ifdef DEBUG
     already_compiled_ = false;
 #endif
@@ -1459,6 +1460,9 @@ class FunctionLiteral: public Expression {
   bool try_full_codegen() { return try_full_codegen_; }
   void set_try_full_codegen(bool flag) { try_full_codegen_ = flag; }
 
+  bool pretenure() { return pretenure_; }
+  void set_pretenure(bool value) { pretenure_ = value; }
+
 #ifdef DEBUG
   void mark_as_compiled() {
     ASSERT(!already_compiled_);
@@ -1482,6 +1486,7 @@ class FunctionLiteral: public Expression {
   int function_token_position_;
   Handle<String> inferred_name_;
   bool try_full_codegen_;
+  bool pretenure_;
 #ifdef DEBUG
   bool already_compiled_;
 #endif
index 19971a2c48ddb27eb3d7aed09bbc68fc4aabdf3e..a890f15974a23c46b9e58440f55f83d14c268802 100644 (file)
@@ -1168,14 +1168,14 @@ void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
     SetStackOverflow();
     return;
   }
-  EmitNewClosure(function_info);
+  EmitNewClosure(function_info, expr->pretenure());
 }
 
 
 void FullCodeGenerator::VisitSharedFunctionInfoLiteral(
     SharedFunctionInfoLiteral* expr) {
   Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
-  EmitNewClosure(expr->shared_function_info());
+  EmitNewClosure(expr->shared_function_info(), false);
 }
 
 
index 6a1def6ee1983833a92633489fe4b4d25ce01c1a..97a56bd90805a3246b8d8e8fdaecaa12f99c3430 100644 (file)
@@ -348,7 +348,7 @@ class FullCodeGenerator: public AstVisitor {
 
   // Platform-specific support for allocating a new closure based on
   // the given function info.
-  void EmitNewClosure(Handle<SharedFunctionInfo> info);
+  void EmitNewClosure(Handle<SharedFunctionInfo> info, bool pretenure);
 
   // Platform-specific support for compiling assignments.
 
index 6ac89bfbac0da3500266828c1c8187203b7333c3..5975ad27dbc9b77ec2f481651d0e5e594a7e8dcc 100644 (file)
@@ -80,8 +80,9 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
   __ pop(edx);
   __ push(esi);
   __ push(edx);
+  __ push(Immediate(Factory::false_value()));
   __ push(ecx);  // Restore return address.
-  __ TailCallRuntime(Runtime::kNewClosure, 2, 1);
+  __ TailCallRuntime(Runtime::kNewClosure, 3, 1);
 }
 
 
index 060ccce845149fcc94561abb78f21af3002f9a31..f5ab357ff1ef9fbb93b7a5edcec7e8d1d7892c7b 100644 (file)
@@ -4897,7 +4897,8 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
 
 
 Result CodeGenerator::InstantiateFunction(
-    Handle<SharedFunctionInfo> function_info) {
+    Handle<SharedFunctionInfo> function_info,
+    bool pretenure) {
   // The inevitable call will sync frame elements to memory anyway, so
   // we do it eagerly to allow us to push the arguments directly into
   // place.
@@ -4905,7 +4906,9 @@ Result CodeGenerator::InstantiateFunction(
 
   // Use the fast case closure allocation code that allocates in new
   // space for nested functions that don't need literals cloning.
-  if (scope()->is_function_scope() && function_info->num_literals() == 0) {
+  if (scope()->is_function_scope() &&
+      function_info->num_literals() == 0 &&
+      !pretenure) {
     FastNewClosureStub stub;
     frame()->EmitPush(Immediate(function_info));
     return frame()->CallStub(&stub, 1);
@@ -4914,7 +4917,10 @@ Result CodeGenerator::InstantiateFunction(
     // shared function info.
     frame()->EmitPush(esi);
     frame()->EmitPush(Immediate(function_info));
-    return frame()->CallRuntime(Runtime::kNewClosure, 2);
+    frame()->EmitPush(Immediate(pretenure
+                                ? Factory::true_value()
+                                : Factory::false_value()));
+    return frame()->CallRuntime(Runtime::kNewClosure, 3);
   }
 }
 
@@ -4930,7 +4936,7 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
     SetStackOverflow();
     return;
   }
-  Result result = InstantiateFunction(function_info);
+  Result result = InstantiateFunction(function_info, node->pretenure());
   frame()->Push(&result);
 }
 
@@ -4939,7 +4945,7 @@ void CodeGenerator::VisitSharedFunctionInfoLiteral(
     SharedFunctionInfoLiteral* node) {
   ASSERT(!in_safe_int32_mode());
   Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
-  Result result = InstantiateFunction(node->shared_function_info());
+  Result result = InstantiateFunction(node->shared_function_info(), false);
   frame()->Push(&result);
 }
 
index f15e08c540e57510c5d65e866d0d71b3b52eb8ee..d1a2036cb7fff804439848a715d11ebf85b5bfa7 100644 (file)
@@ -625,7 +625,8 @@ class CodeGenerator: public AstVisitor {
   void DeclareGlobals(Handle<FixedArray> pairs);
 
   // Instantiate the function based on the shared function info.
-  Result InstantiateFunction(Handle<SharedFunctionInfo> function_info);
+  Result InstantiateFunction(Handle<SharedFunctionInfo> function_info,
+                             bool pretenure);
 
   // Support for types.
   void GenerateIsSmi(ZoneList<Expression*>* args);
index b742d352c41068d5dee0e69abcf9570122a8084e..3adc48a739dade5bde0dbddd9bc5d4656a1df378 100644 (file)
@@ -880,17 +880,23 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
 }
 
 
-void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
+void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
+                                       bool pretenure) {
   // Use the fast case closure allocation code that allocates in new
   // space for nested functions that don't need literals cloning.
-  if (scope()->is_function_scope() && info->num_literals() == 0) {
+  if (scope()->is_function_scope() &&
+      info->num_literals() == 0 &&
+      !pretenure) {
     FastNewClosureStub stub;
     __ push(Immediate(info));
     __ CallStub(&stub);
   } else {
     __ push(esi);
     __ push(Immediate(info));
-    __ CallRuntime(Runtime::kNewClosure, 2);
+    __ push(Immediate(pretenure
+                      ? Factory::true_value()
+                      : Factory::false_value()));
+    __ CallRuntime(Runtime::kNewClosure, 3);
   }
   context()->Plug(eax);
 }
index 8b5e8270b359dd583453c8b85e633d6b49330135..7e4a51e2fa3add4fdf73b1a0bb9801a2387e6f9f 100644 (file)
@@ -2276,6 +2276,12 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
     temp_scope_->AddProperty();
   }
 
+  // If we assign a function literal to a property we pretenure the
+  // literal so it can be added as a constant function property.
+  if (property != NULL && right->AsFunctionLiteral() != NULL) {
+    right->AsFunctionLiteral()->set_pretenure(true);
+  }
+
   if (fni_ != NULL) {
     // Check if the right hand side is a call to avoid inferring a
     // name if we're dealing with "a = function(){...}();"-like
index 327114898078769f44d057252b850acc799ac182..08f1865e71846ca6bdf0884e0e74d295ef73135a 100644 (file)
@@ -6341,15 +6341,20 @@ static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
 
 static MaybeObject* Runtime_NewClosure(Arguments args) {
   HandleScope scope;
-  ASSERT(args.length() == 2);
+  ASSERT(args.length() == 3);
   CONVERT_ARG_CHECKED(Context, context, 0);
   CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
+  CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
 
-  PretenureFlag pretenure = (context->global_context() == *context)
-      ? TENURED       // Allocate global closures in old space.
-      : NOT_TENURED;  // Allocate local closures in new space.
+  // Allocate global closures in old space and allocate local closures
+  // in new space. Additionally pretenure closures that are assigned
+  // directly to properties.
+  pretenure = pretenure || (context->global_context() == *context);
+  PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
   Handle<JSFunction> result =
-      Factory::NewFunctionFromSharedFunctionInfo(shared, context, pretenure);
+      Factory::NewFunctionFromSharedFunctionInfo(shared,
+                                                 context,
+                                                 pretenure_flag);
   return *result;
 }
 
index 3436f124bac7d82c06ac10087da409326df6f2d7..f9ebbc42ef8f62f6cbd63685b641cf413fee82d1 100644 (file)
@@ -262,7 +262,7 @@ namespace internal {
   F(CreateCatchExtensionObject, 2, 1) \
   \
   /* Statements */ \
-  F(NewClosure, 2, 1) \
+  F(NewClosure, 3, 1) \
   F(NewObject, 1, 1) \
   F(NewObjectFromBound, 2, 1) \
   F(FinalizeInstanceSize, 1, 1) \
index 04173e1afb34a39a9ee275a4d7668e380b3ee745..14e352731fed0e2ec08266d8d6b5bf6a76190bb9 100644 (file)
@@ -80,8 +80,9 @@ void FastNewClosureStub::Generate(MacroAssembler* masm) {
   __ pop(rdx);
   __ push(rsi);
   __ push(rdx);
+  __ Push(Factory::false_value());
   __ push(rcx);  // Restore return address.
-  __ TailCallRuntime(Runtime::kNewClosure, 2, 1);
+  __ TailCallRuntime(Runtime::kNewClosure, 3, 1);
 }
 
 
index 395f7c39caa046b35facb415068bccb2432abac9..5abf3c838c4e39a363fa77f035058e6d22a3fb6b 100644 (file)
@@ -4244,7 +4244,8 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
 
 
 void CodeGenerator::InstantiateFunction(
-    Handle<SharedFunctionInfo> function_info) {
+    Handle<SharedFunctionInfo> function_info,
+    bool pretenure) {
   // The inevitable call will sync frame elements to memory anyway, so
   // we do it eagerly to allow us to push the arguments directly into
   // place.
@@ -4252,7 +4253,9 @@ void CodeGenerator::InstantiateFunction(
 
   // Use the fast case closure allocation code that allocates in new
   // space for nested functions that don't need literals cloning.
-  if (scope()->is_function_scope() && function_info->num_literals() == 0) {
+  if (scope()->is_function_scope() &&
+      function_info->num_literals() == 0 &&
+      !pretenure) {
     FastNewClosureStub stub;
     frame_->Push(function_info);
     Result answer = frame_->CallStub(&stub, 1);
@@ -4262,7 +4265,10 @@ void CodeGenerator::InstantiateFunction(
     // shared function info.
     frame_->EmitPush(rsi);
     frame_->EmitPush(function_info);
-    Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
+    frame_->EmitPush(pretenure
+                     ? Factory::true_value()
+                     : Factory::false_value());
+    Result result = frame_->CallRuntime(Runtime::kNewClosure, 3);
     frame_->Push(&result);
   }
 }
@@ -4279,14 +4285,14 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
     SetStackOverflow();
     return;
   }
-  InstantiateFunction(function_info);
+  InstantiateFunction(function_info, node->pretenure());
 }
 
 
 void CodeGenerator::VisitSharedFunctionInfoLiteral(
     SharedFunctionInfoLiteral* node) {
   Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
-  InstantiateFunction(node->shared_function_info());
+  InstantiateFunction(node->shared_function_info(), false);
 }
 
 
index 2bc82a46f5d3a392bc0245638ab16b8ea3458a2d..1a5e7df31cc2f9e0be3272434c4a325138c57fc8 100644 (file)
@@ -585,7 +585,8 @@ class CodeGenerator: public AstVisitor {
   void DeclareGlobals(Handle<FixedArray> pairs);
 
   // Instantiate the function based on the shared function info.
-  void InstantiateFunction(Handle<SharedFunctionInfo> function_info);
+  void InstantiateFunction(Handle<SharedFunctionInfo> function_info,
+                           bool pretenure);
 
   // Support for type checks.
   void GenerateIsSmi(ZoneList<Expression*>* args);
index 4dbc655d3f34ce0980c8d4e1d028daba8d203315..ee80169bb988edfbb5440ba5129c3b4d134cdfc0 100644 (file)
@@ -837,17 +837,21 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
 }
 
 
-void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
+void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
+                                       bool pretenure) {
   // Use the fast case closure allocation code that allocates in new
   // space for nested functions that don't need literals cloning.
-  if (scope()->is_function_scope() && info->num_literals() == 0) {
+  if (scope()->is_function_scope() &&
+      info->num_literals() == 0 &&
+      !pretenure) {
     FastNewClosureStub stub;
     __ Push(info);
     __ CallStub(&stub);
   } else {
     __ push(rsi);
     __ Push(info);
-    __ CallRuntime(Runtime::kNewClosure, 2);
+    __ Push(pretenure ? Factory::true_value() : Factory::false_value());
+    __ CallRuntime(Runtime::kNewClosure, 3);
   }
   context()->Plug(rax);
 }