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;
}
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
}
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);
+ }
}
// 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) {
}
+bool FunctionLiteral::strict_mode() const {
+ return scope()->is_strict_mode();
+}
+
+
} } // namespace v8::internal
#endif // V8_AST_INL_H_
int start_position,
int end_position,
bool is_expression,
- bool contains_loops,
- bool strict_mode)
+ bool contains_loops)
: name_(name),
scope_(scope),
body_(body),
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),
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_; }
// 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);
+ }
}
}
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;
}
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) {
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();
}
// 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) {
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
// Captures the number of loops inside the scope.
int loop_count_;
- // Parsing strict mode code.
- bool strict_mode_;
-
// Bookkeeping
TemporaryScope** variable_;
TemporaryScope* parent_;
loop_count_(0),
variable_(variable),
parent_(*variable) {
- // Inherit the strict mode from the parent scope.
- strict_mode_ = (parent_ != NULL) && parent_->strict_mode_;
*variable = this;
}
scope);
TemporaryScope temp_scope(&this->temp_scope_);
if (strict_mode == kStrictMode) {
- temp_scope.EnableStrictMode();
+ top_scope_->EnableStrictMode();
}
ZoneList<Statement*>* body = new ZoneList<Statement*>(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) {
0,
source->length(),
false,
- temp_scope.ContainsLoops(),
- temp_scope.StrictMode());
+ temp_scope.ContainsLoops());
} else if (stack_overflow_) {
Top::StackOverflow();
}
TemporaryScope temp_scope(&this->temp_scope_);
if (info->strict_mode()) {
- temp_scope.EnableStrictMode();
+ top_scope_->EnableStrictMode();
}
FunctionLiteralType type =
Handle<String> directive = Handle<String>::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;
}
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<const char*>::empty());
*ok = false;
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<const char*>::empty());
*ok = false;
return NULL;
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<const char*>::empty());
*ok = false;
return NULL;
// 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
Expect(Token::WITH, CHECK_OK);
- if (temp_scope_->StrictMode()) {
+ if (top_scope_->is_strict_mode()) {
ReportMessage("strict_mode_with", Vector<const char*>::empty());
*ok = false;
return NULL;
Expect(Token::LPAREN, CHECK_OK);
Handle<String> name = ParseIdentifier(CHECK_OK);
- if (temp_scope_->StrictMode() && IsEvalOrArguments(name)) {
+ if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
ReportMessage("strict_catch_variable", Vector<const char*>::empty());
*ok = false;
return NULL;
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);
}
}
// "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<const char*>::empty());
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);
}
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);
}
return ReportMessage("unexpected_token_identifier",
Vector<const char*>::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<const char*>::empty());
new ZoneList<ObjectLiteral::Property*>(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();
}
// 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
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);
Handle<String> 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)) {
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;
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
// 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
// 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.
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_; }
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_;
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;
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;
}
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) {
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();
}
// 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) {
# 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
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"));
+})();