From 927f341d3c84d63ca6b40a402203e81d6161545a Mon Sep 17 00:00:00 2001 From: "mmaly@chromium.org" Date: Mon, 7 Mar 2011 19:23:46 +0000 Subject: [PATCH] Strict mode arguments do not share binding with formal parameters. Move strict mode flag from TemporaryScope to Scope so that it can be accessed from variable binding code. Arguments do not alias in strict mode (ia32, x64 and arm, codegen and full codegen). Hydrogen tolerates null arguments_shadow(). In codegen- arguments object is allocated eagerly to capture values before they get modified. Review URL: http://codereview.chromium.org/6625048/ git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7083 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/codegen-arm.cc | 14 +++++++--- src/arm/full-codegen-arm.cc | 11 +++++--- src/ast-inl.h | 5 ++++ src/ast.h | 6 ++--- src/hydrogen.cc | 7 +++-- src/ia32/codegen-ia32.cc | 16 ++++++++--- src/ia32/full-codegen-ia32.cc | 9 ++++--- src/parser.cc | 56 +++++++++++++++------------------------ src/scopes.cc | 12 +++++++++ src/scopes.h | 8 ++++++ src/x64/codegen-x64.cc | 14 +++++++--- src/x64/full-codegen-x64.cc | 11 +++++--- test/es5conform/es5conform.status | 5 ---- test/mjsunit/strict-mode.js | 19 +++++++++++++ 14 files changed, 125 insertions(+), 68 deletions(-) diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index d32b009..4f243ea 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -577,11 +577,13 @@ void CodeGenerator::LoadGlobalReceiver(Register scratch) { ArgumentsAllocationMode CodeGenerator::ArgumentsMode() { if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; - ASSERT(scope()->arguments_shadow() != NULL); + + // In strict mode there is no need for shadow arguments. + ASSERT(scope()->arguments_shadow() != NULL || scope()->is_strict_mode()); // We don't want to do lazy arguments allocation for functions that // have heap-allocated contexts, because it interfers with the // uninitialized const tracking in the context objects. - return (scope()->num_heap_slots() > 0) + return (scope()->num_heap_slots() > 0 || scope()->is_strict_mode()) ? EAGER_ARGUMENTS_ALLOCATION : LAZY_ARGUMENTS_ALLOCATION; } @@ -615,7 +617,9 @@ void CodeGenerator::StoreArgumentsObject(bool initial) { Variable* arguments = scope()->arguments(); Variable* shadow = scope()->arguments_shadow(); ASSERT(arguments != NULL && arguments->AsSlot() != NULL); - ASSERT(shadow != NULL && shadow->AsSlot() != NULL); + ASSERT((shadow != NULL && shadow->AsSlot() != NULL) || + scope()->is_strict_mode()); + JumpTarget done; if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { // We have to skip storing into the arguments slot if it has @@ -629,7 +633,9 @@ void CodeGenerator::StoreArgumentsObject(bool initial) { } StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT); if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); - StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); + if (shadow != NULL) { + StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); + } } diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 5f5de3a..572611c 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -212,11 +212,14 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { // stack frame was an arguments adapter frame. ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); __ CallStub(&stub); - // Duplicate the value; move-to-slot operation might clobber registers. - __ mov(r3, r0); + + Variable* arguments_shadow = scope()->arguments_shadow(); + if (arguments_shadow != NULL) { + // Duplicate the value; move-to-slot operation might clobber registers. + __ mov(r3, r0); + Move(arguments_shadow->AsSlot(), r3, r1, r2); + } Move(arguments->AsSlot(), r0, r1, r2); - Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot(); - Move(dot_arguments_slot, r3, r1, r2); } if (FLAG_trace) { diff --git a/src/ast-inl.h b/src/ast-inl.h index eb81c3a..6021fd9 100644 --- a/src/ast-inl.h +++ b/src/ast-inl.h @@ -102,6 +102,11 @@ ForInStatement::ForInStatement(ZoneStringList* labels) } +bool FunctionLiteral::strict_mode() const { + return scope()->is_strict_mode(); +} + + } } // namespace v8::internal #endif // V8_AST_INL_H_ diff --git a/src/ast.h b/src/ast.h index 2aee5d7..008d79b 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1673,8 +1673,7 @@ class FunctionLiteral: public Expression { int start_position, int end_position, bool is_expression, - bool contains_loops, - bool strict_mode) + bool contains_loops) : name_(name), scope_(scope), body_(body), @@ -1688,7 +1687,6 @@ class FunctionLiteral: public Expression { end_position_(end_position), is_expression_(is_expression), contains_loops_(contains_loops), - strict_mode_(strict_mode), function_token_position_(RelocInfo::kNoPosition), inferred_name_(Heap::empty_string()), try_full_codegen_(false), @@ -1705,7 +1703,7 @@ class FunctionLiteral: public Expression { int end_position() const { return end_position_; } bool is_expression() const { return is_expression_; } bool contains_loops() const { return contains_loops_; } - bool strict_mode() const { return strict_mode_; } + bool strict_mode() const; int materialized_literal_count() { return materialized_literal_count_; } int expected_property_count() { return expected_property_count_; } diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 6b7ecdb..308a2c3 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -2292,14 +2292,17 @@ void HGraphBuilder::SetupScope(Scope* scope) { // not have declarations). if (scope->arguments() != NULL) { if (!scope->arguments()->IsStackAllocated() || - !scope->arguments_shadow()->IsStackAllocated()) { + (scope->arguments_shadow() != NULL && + !scope->arguments_shadow()->IsStackAllocated())) { BAILOUT("context-allocated arguments"); } HArgumentsObject* object = new HArgumentsObject; AddInstruction(object); graph()->SetArgumentsObject(object); environment()->Bind(scope->arguments(), object); - environment()->Bind(scope->arguments_shadow(), object); + if (scope->arguments_shadow() != NULL) { + environment()->Bind(scope->arguments_shadow(), object); + } } } diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 3a2753d..fcb06d2 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -729,11 +729,14 @@ void CodeGenerator::LoadTypeofExpression(Expression* expr) { ArgumentsAllocationMode CodeGenerator::ArgumentsMode() { if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; - ASSERT(scope()->arguments_shadow() != NULL); + + // In strict mode there is no need for shadow arguments. + ASSERT(scope()->arguments_shadow() != NULL || scope()->is_strict_mode()); + // We don't want to do lazy arguments allocation for functions that // have heap-allocated contexts, because it interfers with the // uninitialized const tracking in the context objects. - return (scope()->num_heap_slots() > 0) + return (scope()->num_heap_slots() > 0 || scope()->is_strict_mode()) ? EAGER_ARGUMENTS_ALLOCATION : LAZY_ARGUMENTS_ALLOCATION; } @@ -760,8 +763,11 @@ Result CodeGenerator::StoreArgumentsObject(bool initial) { Variable* arguments = scope()->arguments(); Variable* shadow = scope()->arguments_shadow(); + ASSERT(arguments != NULL && arguments->AsSlot() != NULL); - ASSERT(shadow != NULL && shadow->AsSlot() != NULL); + ASSERT((shadow != NULL && shadow->AsSlot() != NULL) || + scope()->is_strict_mode()); + JumpTarget done; bool skip_arguments = false; if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { @@ -784,7 +790,9 @@ Result CodeGenerator::StoreArgumentsObject(bool initial) { StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT); if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); } - StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); + if (shadow != NULL) { + StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); + } return frame_->Pop(); } diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 9a7d41a..608aebe 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -199,10 +199,13 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { // stack frame was an arguments adapter frame. ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); __ CallStub(&stub); - __ mov(ecx, eax); // Duplicate result. + + Variable* arguments_shadow = scope()->arguments_shadow(); + if (arguments_shadow != NULL) { + __ mov(ecx, eax); // Duplicate result. + Move(arguments_shadow->AsSlot(), ecx, ebx, edx); + } Move(arguments->AsSlot(), eax, ebx, edx); - Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot(); - Move(dot_arguments_slot, ecx, ebx, edx); } if (FLAG_trace) { diff --git a/src/parser.cc b/src/parser.cc index 3c361a7..7bd0cea 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -283,11 +283,6 @@ class TemporaryScope BASE_EMBEDDED { void AddLoop() { loop_count_++; } bool ContainsLoops() const { return loop_count_ > 0; } - bool StrictMode() { return strict_mode_; } - void EnableStrictMode() { - strict_mode_ = FLAG_strict_mode; - } - private: // Captures the number of literals that need materialization in the // function. Includes regexp literals, and boilerplate for object @@ -305,9 +300,6 @@ class TemporaryScope BASE_EMBEDDED { // Captures the number of loops inside the scope. int loop_count_; - // Parsing strict mode code. - bool strict_mode_; - // Bookkeeping TemporaryScope** variable_; TemporaryScope* parent_; @@ -322,8 +314,6 @@ TemporaryScope::TemporaryScope(TemporaryScope** variable) loop_count_(0), variable_(variable), parent_(*variable) { - // Inherit the strict mode from the parent scope. - strict_mode_ = (parent_ != NULL) && parent_->strict_mode_; *variable = this; } @@ -665,13 +655,13 @@ FunctionLiteral* Parser::DoParseProgram(Handle source, scope); TemporaryScope temp_scope(&this->temp_scope_); if (strict_mode == kStrictMode) { - temp_scope.EnableStrictMode(); + top_scope_->EnableStrictMode(); } ZoneList* body = new ZoneList(16); bool ok = true; int beg_loc = scanner().location().beg_pos; ParseSourceElements(body, Token::EOS, &ok); - if (ok && temp_scope_->StrictMode()) { + if (ok && top_scope_->is_strict_mode()) { CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok); } if (ok) { @@ -687,8 +677,7 @@ FunctionLiteral* Parser::DoParseProgram(Handle source, 0, source->length(), false, - temp_scope.ContainsLoops(), - temp_scope.StrictMode()); + temp_scope.ContainsLoops()); } else if (stack_overflow_) { Top::StackOverflow(); } @@ -753,7 +742,7 @@ FunctionLiteral* Parser::ParseLazy(Handle info, TemporaryScope temp_scope(&this->temp_scope_); if (info->strict_mode()) { - temp_scope.EnableStrictMode(); + top_scope_->EnableStrictMode(); } FunctionLiteralType type = @@ -1140,11 +1129,11 @@ void* Parser::ParseSourceElements(ZoneList* processor, Handle directive = Handle::cast(literal->handle()); // Check "use strict" directive (ES5 14.1). - if (!temp_scope_->StrictMode() && + if (!top_scope_->is_strict_mode() && directive->Equals(Heap::use_strict()) && token_loc.end_pos - token_loc.beg_pos == Heap::use_strict()->length() + 2) { - temp_scope_->EnableStrictMode(); + top_scope_->EnableStrictMode(); // "use strict" is the only directive for now. directive_prologue = false; } @@ -1282,7 +1271,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { case Token::FUNCTION: { // In strict mode, FunctionDeclaration is only allowed in the context // of SourceElements. - if (temp_scope_->StrictMode()) { + if (top_scope_->is_strict_mode()) { ReportMessageAt(scanner().peek_location(), "strict_function", Vector::empty()); *ok = false; @@ -1540,7 +1529,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, Consume(Token::VAR); } else if (peek() == Token::CONST) { Consume(Token::CONST); - if (temp_scope_->StrictMode()) { + if (top_scope_->is_strict_mode()) { ReportMessage("strict_const", Vector::empty()); *ok = false; return NULL; @@ -1576,7 +1565,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, if (fni_ != NULL) fni_->PushVariableName(name); // Strict mode variables may not be named eval or arguments - if (temp_scope_->StrictMode() && IsEvalOrArguments(name)) { + if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) { ReportMessage("strict_var_name", Vector::empty()); *ok = false; return NULL; @@ -1685,7 +1674,7 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, // Add strict mode. // We may want to pass singleton to avoid Literal allocations. arguments->Add(NewNumberLiteral( - temp_scope_->StrictMode() ? kStrictMode : kNonStrictMode)); + top_scope_->is_strict_mode() ? kStrictMode : kNonStrictMode)); // Be careful not to assign a value to the global variable if // we're in a with. The initialization value should not @@ -1958,7 +1947,7 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) { Expect(Token::WITH, CHECK_OK); - if (temp_scope_->StrictMode()) { + if (top_scope_->is_strict_mode()) { ReportMessage("strict_mode_with", Vector::empty()); *ok = false; return NULL; @@ -2097,7 +2086,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { Expect(Token::LPAREN, CHECK_OK); Handle name = ParseIdentifier(CHECK_OK); - if (temp_scope_->StrictMode() && IsEvalOrArguments(name)) { + if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) { ReportMessage("strict_catch_variable", Vector::empty()); *ok = false; return NULL; @@ -2348,7 +2337,7 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) { expression = NewThrowReferenceError(type); } - if (temp_scope_->StrictMode()) { + if (top_scope_->is_strict_mode()) { // Assignment to eval or arguments is disallowed in strict mode. CheckStrictModeLValue(expression, "strict_lhs_assignment", CHECK_OK); } @@ -2567,7 +2556,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { } // "delete identifier" is a syntax error in strict mode. - if (op == Token::DELETE && temp_scope_->StrictMode()) { + if (op == Token::DELETE && top_scope_->is_strict_mode()) { VariableProxy* operand = expression->AsVariableProxy(); if (operand != NULL && !operand->is_this()) { ReportMessage("strict_delete", Vector::empty()); @@ -2590,7 +2579,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) { expression = NewThrowReferenceError(type); } - if (temp_scope_->StrictMode()) { + if (top_scope_->is_strict_mode()) { // Prefix expression operand in strict mode may not be eval or arguments. CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK); } @@ -2621,7 +2610,7 @@ Expression* Parser::ParsePostfixExpression(bool* ok) { expression = NewThrowReferenceError(type); } - if (temp_scope_->StrictMode()) { + if (top_scope_->is_strict_mode()) { // Postfix expression operand in strict mode may not be eval or arguments. CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK); } @@ -2829,7 +2818,7 @@ void Parser::ReportUnexpectedToken(Token::Value token) { return ReportMessage("unexpected_token_identifier", Vector::empty()); case Token::FUTURE_RESERVED_WORD: - return ReportMessage(temp_scope_->StrictMode() ? + return ReportMessage(top_scope_->is_strict_mode() ? "unexpected_strict_reserved" : "unexpected_token_identifier", Vector::empty()); @@ -3334,7 +3323,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { new ZoneList(4); int number_of_boilerplate_properties = 0; - ObjectLiteralPropertyChecker checker(this, temp_scope_->StrictMode()); + ObjectLiteralPropertyChecker checker(this, top_scope_->is_strict_mode()); Expect(Token::LBRACE, CHECK_OK); Scanner::Location loc = scanner().location(); @@ -3631,7 +3620,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle var_name, } // Validate strict mode. - if (temp_scope_->StrictMode()) { + if (top_scope_->is_strict_mode()) { if (IsEvalOrArguments(name)) { int position = function_token_position != RelocInfo::kNoPosition ? function_token_position @@ -3685,8 +3674,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle var_name, start_pos, end_pos, function_name->length() > 0, - temp_scope.ContainsLoops(), - temp_scope.StrictMode()); + temp_scope.ContainsLoops()); function_literal->set_function_token_position(function_token_position); if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal); @@ -3815,7 +3803,7 @@ Handle Parser::ParseIdentifier(bool* ok) { Handle Parser::ParseIdentifierOrReservedWord(bool* is_reserved, bool* ok) { *is_reserved = false; - if (temp_scope_->StrictMode()) { + if (top_scope_->is_strict_mode()) { Expect(Token::IDENTIFIER, ok); } else { if (!Check(Token::IDENTIFIER)) { @@ -3846,7 +3834,7 @@ Handle Parser::ParseIdentifierName(bool* ok) { void Parser::CheckStrictModeLValue(Expression* expression, const char* error, bool* ok) { - ASSERT(temp_scope_->StrictMode()); + ASSERT(top_scope_->is_strict_mode()); VariableProxy* lhs = expression != NULL ? expression->AsVariableProxy() : NULL; diff --git a/src/scopes.cc b/src/scopes.cc index fd573b0..a03dbdd 100644 --- a/src/scopes.cc +++ b/src/scopes.cc @@ -878,6 +878,11 @@ void Scope::AllocateParameterLocals() { ASSERT(is_function_scope()); Variable* arguments = LocalLookup(Factory::arguments_symbol()); ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly + + // Parameters are rewritten to arguments[i] if 'arguments' is used in + // a non-strict mode function. Strict mode code doesn't alias arguments. + bool rewrite_parameters = false; + if (MustAllocate(arguments) && !HasArgumentsParameter()) { // 'arguments' is used. Unless there is also a parameter called // 'arguments', we must be conservative and access all parameters via @@ -909,6 +914,13 @@ void Scope::AllocateParameterLocals() { // allocate the arguments object by setting 'arguments_'. arguments_ = arguments; + // In strict mode 'arguments' does not alias formal parameters. + // Therefore in strict mode we allocate parameters as if 'arguments' + // were not used. + rewrite_parameters = !is_strict_mode(); + } + + if (rewrite_parameters) { // We also need the '.arguments' shadow variable. Declare it and create // and bind the corresponding proxy. It's ok to declare it only now // because it's a local variable that is allocated after the parameters diff --git a/src/scopes.h b/src/scopes.h index a9220eb..123c4d8 100644 --- a/src/scopes.h +++ b/src/scopes.h @@ -193,6 +193,10 @@ class Scope: public ZoneObject { // Inform the scope that the corresponding code contains an eval call. void RecordEvalCall() { scope_calls_eval_ = true; } + // Enable strict mode for the scope (unless disabled by a global flag). + void EnableStrictMode() { + strict_mode_ = FLAG_strict_mode; + } // --------------------------------------------------------------------------- // Predicates. @@ -201,6 +205,7 @@ class Scope: public ZoneObject { bool is_eval_scope() const { return type_ == EVAL_SCOPE; } bool is_function_scope() const { return type_ == FUNCTION_SCOPE; } bool is_global_scope() const { return type_ == GLOBAL_SCOPE; } + bool is_strict_mode() const { return strict_mode_; } // Information about which scopes calls eval. bool calls_eval() const { return scope_calls_eval_; } @@ -363,6 +368,7 @@ class Scope: public ZoneObject { bool scope_inside_with_; // this scope is inside a 'with' of some outer scope bool scope_contains_with_; // this scope contains a 'with' statement bool scope_calls_eval_; // this scope contains an 'eval' call + bool strict_mode_; // this scope is a strict mode scope // Computed via PropagateScopeInfo. bool outer_scope_calls_eval_; @@ -428,6 +434,8 @@ class Scope: public ZoneObject { scope_inside_with_ = false; scope_contains_with_ = false; scope_calls_eval_ = false; + // Inherit the strict mode from the parent scope. + strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_; outer_scope_calls_eval_ = false; inner_scope_calls_eval_ = false; outer_scope_is_eval_scope_ = false; diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index fc4bc04..e3ab7c2 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -611,11 +611,13 @@ void CodeGenerator::LoadTypeofExpression(Expression* expr) { ArgumentsAllocationMode CodeGenerator::ArgumentsMode() { if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; - ASSERT(scope()->arguments_shadow() != NULL); + + // In strict mode there is no need for shadow arguments. + ASSERT(scope()->arguments_shadow() != NULL || scope()->is_strict_mode()); // We don't want to do lazy arguments allocation for functions that // have heap-allocated contexts, because it interfers with the // uninitialized const tracking in the context objects. - return (scope()->num_heap_slots() > 0) + return (scope()->num_heap_slots() > 0 || scope()->is_strict_mode()) ? EAGER_ARGUMENTS_ALLOCATION : LAZY_ARGUMENTS_ALLOCATION; } @@ -643,7 +645,9 @@ Result CodeGenerator::StoreArgumentsObject(bool initial) { Variable* arguments = scope()->arguments(); Variable* shadow = scope()->arguments_shadow(); ASSERT(arguments != NULL && arguments->AsSlot() != NULL); - ASSERT(shadow != NULL && shadow->AsSlot() != NULL); + ASSERT((shadow != NULL && shadow->AsSlot() != NULL) || + scope()->is_strict_mode()); + JumpTarget done; bool skip_arguments = false; if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { @@ -666,7 +670,9 @@ Result CodeGenerator::StoreArgumentsObject(bool initial) { StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT); if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); } - StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); + if (shadow != NULL) { + StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); + } return frame_->Pop(); } diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 780f4b0..d7db7fd 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -200,11 +200,14 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { // stack frame was an arguments adapter frame. ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); __ CallStub(&stub); - // Store new arguments object in both "arguments" and ".arguments" slots. - __ movq(rcx, rax); + + Variable* arguments_shadow = scope()->arguments_shadow(); + if (arguments_shadow != NULL) { + // Store new arguments object in both "arguments" and ".arguments" slots. + __ movq(rcx, rax); + Move(arguments_shadow->AsSlot(), rcx, rbx, rdx); + } Move(arguments->AsSlot(), rax, rbx, rdx); - Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot(); - Move(dot_arguments_slot, rcx, rbx, rdx); } if (FLAG_trace) { diff --git a/test/es5conform/es5conform.status b/test/es5conform/es5conform.status index d6f7caf..58ee0d1 100644 --- a/test/es5conform/es5conform.status +++ b/test/es5conform/es5conform.status @@ -239,11 +239,6 @@ chapter15/15.10/15.10.7/15.10.7.5/15.10.7.5-2: FAIL_OK # Incorrect test - need double escape in eval. chapter07/7.8/7.8.4/7.8.4-1-s: FAIL -# arguments[i] remains same after changing actual parameters in strict mode -chapter10/10.6/10.6-10-c-ii-1-s: FAIL -# arguments[i] doesn't map to actual parameters in strict mode -chapter10/10.6/10.6-10-c-ii-2-s: FAIL - # Accessing caller property of Arguments object throws TypeError in strict mode chapter10/10.6/10.6-13-b-1-s: FAIL # arguments.caller exists in strict mode diff --git a/test/mjsunit/strict-mode.js b/test/mjsunit/strict-mode.js index 69be19c..2064162 100644 --- a/test/mjsunit/strict-mode.js +++ b/test/mjsunit/strict-mode.js @@ -957,3 +957,22 @@ repeat(10, function() { testAssignToUndefined(false); }); assertThrows(function() { str_obj.length = 1; }, TypeError); assertThrows(function() { str_cat.length = 1; }, TypeError); })(); + + +(function TestArgumentsAliasing() { + function strict(a, b) { + "use strict"; + a = "c"; + b = "d"; + return [a, b, arguments[0], arguments[1]]; + } + + function nonstrict(a, b) { + a = "c"; + b = "d"; + return [a, b, arguments[0], arguments[1]]; + } + + assertEquals(["c", "d", "a", "b"], strict("a", "b")); + assertEquals(["c", "d", "c", "d"], nonstrict("a", "b")); +})(); -- 2.7.4