Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 1a63f1e7aaa7fe9c12b6033a4149659375c43de9..862afe5d3a644bdccc9f918236653baa31e5b03b 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -167,8 +167,7 @@ void HBasicBlock::Finish(HControlInstruction* end) { |
void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) { |
if (block->IsInlineReturnTarget()) { |
AddInstruction(new(zone()) HLeaveInlined); |
- last_environment_ = last_environment()->outer(); |
- if (drop_extra) last_environment_->Drop(1); |
+ last_environment_ = last_environment()->DiscardInlined(drop_extra); |
} |
AddSimulate(AstNode::kNoNumber); |
HGoto* instr = new(zone()) HGoto(block); |
@@ -182,8 +181,7 @@ void HBasicBlock::AddLeaveInlined(HValue* return_value, |
ASSERT(target->IsInlineReturnTarget()); |
ASSERT(return_value != NULL); |
AddInstruction(new(zone()) HLeaveInlined); |
- last_environment_ = last_environment()->outer(); |
- if (drop_extra) last_environment_->Drop(1); |
+ last_environment_ = last_environment()->DiscardInlined(drop_extra); |
last_environment()->Push(return_value); |
AddSimulate(AstNode::kNoNumber); |
HGoto* instr = new(zone()) HGoto(target); |
@@ -2076,6 +2074,7 @@ AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) |
for_typeof_(false) { |
owner->set_ast_context(this); // Push. |
#ifdef DEBUG |
+ ASSERT(!owner->environment()->is_arguments_adaptor()); |
original_length_ = owner->environment()->length(); |
#endif |
} |
@@ -2089,14 +2088,16 @@ AstContext::~AstContext() { |
EffectContext::~EffectContext() { |
ASSERT(owner()->HasStackOverflow() || |
owner()->current_block() == NULL || |
- owner()->environment()->length() == original_length_); |
+ (owner()->environment()->length() == original_length_ && |
+ !owner()->environment()->is_arguments_adaptor())); |
} |
ValueContext::~ValueContext() { |
ASSERT(owner()->HasStackOverflow() || |
owner()->current_block() == NULL || |
- owner()->environment()->length() == original_length_ + 1); |
+ (owner()->environment()->length() == original_length_ + 1 && |
+ !owner()->environment()->is_arguments_adaptor())); |
} |
@@ -4828,7 +4829,9 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { |
TraceInline(target, caller, "inline depth limit reached"); |
return false; |
} |
- current_level++; |
+ if (!env->outer()->is_arguments_adaptor()) { |
+ current_level++; |
+ } |
env = env->outer(); |
} |
@@ -4876,11 +4879,8 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { |
return false; |
} |
- // Don't inline functions that uses the arguments object or that |
- // have a mismatching number of parameters. |
- int arity = expr->arguments()->length(); |
- if (function->scope()->arguments() != NULL || |
- arity != target_shared->formal_parameter_count()) { |
+ // Don't inline functions that uses the arguments object. |
+ if (function->scope()->arguments() != NULL) { |
TraceInline(target, caller, "target requires special argument handling"); |
return false; |
} |
@@ -4944,6 +4944,7 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { |
HConstant* undefined = graph()->GetConstantUndefined(); |
HEnvironment* inner_env = |
environment()->CopyForInlining(target, |
+ expr->arguments()->length(), |
function, |
undefined, |
call_kind); |
@@ -4963,6 +4964,7 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { |
body_entry->SetJoinId(expr->ReturnId()); |
set_current_block(body_entry); |
AddInstruction(new(zone()) HEnterInlined(target, |
+ expr->arguments()->length(), |
function, |
call_kind)); |
VisitDeclarations(target_info.scope()->declarations()); |
@@ -6902,7 +6904,8 @@ HEnvironment::HEnvironment(HEnvironment* outer, |
outer_(outer), |
pop_count_(0), |
push_count_(0), |
- ast_id_(AstNode::kNoNumber) { |
+ ast_id_(AstNode::kNoNumber), |
+ arguments_adaptor_(false) { |
Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0); |
} |
@@ -6916,11 +6919,28 @@ HEnvironment::HEnvironment(const HEnvironment* other) |
outer_(NULL), |
pop_count_(0), |
push_count_(0), |
- ast_id_(other->ast_id()) { |
+ ast_id_(other->ast_id()), |
+ arguments_adaptor_(false) { |
Initialize(other); |
} |
+HEnvironment::HEnvironment(HEnvironment* outer, |
+ Handle<JSFunction> closure, |
+ int arguments) |
+ : closure_(closure), |
+ values_(arguments), |
+ assigned_variables_(0), |
+ parameter_count_(arguments), |
+ local_count_(0), |
+ outer_(outer), |
+ pop_count_(0), |
+ push_count_(0), |
+ ast_id_(AstNode::kNoNumber), |
+ arguments_adaptor_(true) { |
+} |
+ |
+ |
void HEnvironment::Initialize(int parameter_count, |
int local_count, |
int stack_height) { |
@@ -6944,6 +6964,7 @@ void HEnvironment::Initialize(const HEnvironment* other) { |
pop_count_ = other->pop_count_; |
push_count_ = other->push_count_; |
ast_id_ = other->ast_id_; |
+ arguments_adaptor_ = other->arguments_adaptor_; |
} |
@@ -7047,20 +7068,36 @@ HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const { |
HEnvironment* HEnvironment::CopyForInlining( |
Handle<JSFunction> target, |
+ int arguments, |
FunctionLiteral* function, |
HConstant* undefined, |
CallKind call_kind) const { |
+ ASSERT(!is_arguments_adaptor()); |
+ |
+ Zone* zone = closure()->GetIsolate()->zone(); |
+ |
// Outer environment is a copy of this one without the arguments. |
int arity = function->scope()->num_parameters(); |
+ |
HEnvironment* outer = Copy(); |
- outer->Drop(arity + 1); // Including receiver. |
+ outer->Drop(arguments + 1); // Including receiver. |
outer->ClearHistory(); |
- Zone* zone = closure()->GetIsolate()->zone(); |
+ |
+ if (arity != arguments) { |
+ // Create artificial arguments adaptation environment. |
+ outer = new(zone) HEnvironment(outer, target, arguments + 1); |
+ for (int i = 0; i <= arguments; ++i) { // Include receiver. |
+ outer->Push(ExpressionStackAt(arguments - i)); |
+ } |
+ outer->ClearHistory(); |
+ } |
+ |
HEnvironment* inner = |
new(zone) HEnvironment(outer, function->scope(), target); |
// Get the argument values from the original environment. |
for (int i = 0; i <= arity; ++i) { // Include receiver. |
- HValue* push = ExpressionStackAt(arity - i); |
+ HValue* push = (i <= arguments) ? |
+ ExpressionStackAt(arguments - i) : undefined; |
inner->SetValueAt(i, push); |
} |
// If the function we are inlining is a strict mode function or a |
@@ -7070,7 +7107,7 @@ HEnvironment* HEnvironment::CopyForInlining( |
call_kind == CALL_AS_FUNCTION) { |
inner->SetValueAt(0, undefined); |
} |
- inner->SetValueAt(arity + 1, outer->LookupContext()); |
+ inner->SetValueAt(arity + 1, LookupContext()); |
for (int i = arity + 2; i < inner->length(); ++i) { |
inner->SetValueAt(i, undefined); |
} |
@@ -7086,7 +7123,7 @@ void HEnvironment::PrintTo(StringStream* stream) { |
if (i == parameter_count()) stream->Add("specials\n"); |
if (i == parameter_count() + specials_count()) stream->Add("locals\n"); |
if (i == parameter_count() + specials_count() + local_count()) { |
- stream->Add("expressions"); |
+ stream->Add("expressions\n"); |
} |
HValue* val = values_.at(i); |
stream->Add("%d: ", i); |
@@ -7097,6 +7134,7 @@ void HEnvironment::PrintTo(StringStream* stream) { |
} |
stream->Add("\n"); |
} |
+ PrintF("\n"); |
} |