Force pretenuring of closures that are immediately assigned to
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
This commit is contained in:
parent
75ae84f9ca
commit
1e8413e188
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user