| Index: src/x64/full-codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/full-codegen-x64.cc (revision 4643)
|
| +++ src/x64/full-codegen-x64.cc (working copy)
|
| @@ -777,19 +777,28 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
|
| - Comment cmnt(masm_, "[ FunctionLiteral");
|
| +void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
|
| + UNREACHABLE();
|
| +}
|
|
|
| - // Build the shared function info and instantiate the function based
|
| - // on it.
|
| - Handle<SharedFunctionInfo> function_info =
|
| - Compiler::BuildFunctionInfo(expr, script(), this);
|
| - if (HasStackOverflow()) return;
|
|
|
| - // Create a new closure.
|
| - __ push(rsi);
|
| - __ Push(function_info);
|
| - __ CallRuntime(Runtime::kNewClosure, 2);
|
| +void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
|
| + // 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) {
|
| + FastNewClosureStub stub;
|
| + __ Push(info);
|
| + __ CallStub(&stub);
|
| + } else {
|
| + __ push(rsi);
|
| + __ Push(info);
|
| + __ CallRuntime(Runtime::kNewClosure, 2);
|
| + }
|
| Apply(context_, rax);
|
| }
|
|
|
| @@ -1019,7 +1028,13 @@
|
|
|
| void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
| Comment cmnt(masm_, "[ Assignment");
|
| - ASSERT(expr->op() != Token::INIT_CONST);
|
| + // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
|
| + // on the left-hand side.
|
| + if (!expr->target()->IsValidLeftHandSide()) {
|
| + VisitForEffect(expr->target());
|
| + return;
|
| + }
|
| +
|
| // Left-hand side can only be a property, a global or a (parameter or local)
|
| // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
|
| enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
|
| @@ -1045,8 +1060,15 @@
|
| }
|
| break;
|
| case KEYED_PROPERTY:
|
| - VisitForValue(prop->obj(), kStack);
|
| - VisitForValue(prop->key(), kStack);
|
| + if (expr->is_compound()) {
|
| + VisitForValue(prop->obj(), kStack);
|
| + VisitForValue(prop->key(), kAccumulator);
|
| + __ movq(rdx, Operand(rsp, 0));
|
| + __ push(rax);
|
| + } else {
|
| + VisitForValue(prop->obj(), kStack);
|
| + VisitForValue(prop->key(), kStack);
|
| + }
|
| break;
|
| }
|
|
|
| @@ -1091,6 +1113,7 @@
|
| switch (assign_type) {
|
| case VARIABLE:
|
| EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
|
| + expr->op(),
|
| context_);
|
| break;
|
| case NAMED_PROPERTY:
|
| @@ -1133,60 +1156,78 @@
|
|
|
|
|
| void FullCodeGenerator::EmitVariableAssignment(Variable* var,
|
| + Token::Value op,
|
| Expression::Context context) {
|
| - // Three main cases: non-this global variables, lookup slots, and
|
| - // all other types of slots. Left-hand-side parameters that rewrite
|
| - // to explicit property accesses do not reach here.
|
| + // Left-hand sides that rewrite to explicit property accesses do not reach
|
| + // here.
|
| ASSERT(var != NULL);
|
| ASSERT(var->is_global() || var->slot() != NULL);
|
| - Slot* slot = var->slot();
|
| +
|
| if (var->is_global()) {
|
| ASSERT(!var->is_this());
|
| // Assignment to a global variable. Use inline caching for the
|
| // assignment. Right-hand-side value is passed in rax, variable name in
|
| - // rcx, and the global object in rdx.
|
| + // rcx, and the global object on the stack.
|
| __ Move(rcx, var->name());
|
| __ movq(rdx, CodeGenerator::GlobalObject());
|
| Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
| __ Call(ic, RelocInfo::CODE_TARGET);
|
| - Apply(context, rax);
|
| + __ nop();
|
|
|
| - } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
|
| - __ push(result_register()); // Value.
|
| - __ push(rsi); // Context.
|
| - __ Push(var->name());
|
| - __ CallRuntime(Runtime::kStoreContextSlot, 3);
|
| - Apply(context, rax);
|
| -
|
| - } else if (var->slot() != NULL) {
|
| + } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
|
| + // Perform the assignment for non-const variables and for initialization
|
| + // of const variables. Const assignments are simply skipped.
|
| + Label done;
|
| + Slot* slot = var->slot();
|
| switch (slot->type()) {
|
| + case Slot::PARAMETER:
|
| case Slot::LOCAL:
|
| - case Slot::PARAMETER:
|
| - __ movq(Operand(rbp, SlotOffset(slot)), result_register());
|
| + if (op == Token::INIT_CONST) {
|
| + // Detect const reinitialization by checking for the hole value.
|
| + __ movq(rdx, Operand(rbp, SlotOffset(slot)));
|
| + __ Cmp(rdx, Factory::the_hole_value());
|
| + __ j(not_equal, &done);
|
| + }
|
| + // Perform the assignment.
|
| + __ movq(Operand(rbp, SlotOffset(slot)), rax);
|
| break;
|
|
|
| case Slot::CONTEXT: {
|
| MemOperand target = EmitSlotSearch(slot, rcx);
|
| - __ movq(target, result_register());
|
| -
|
| - // RecordWrite may destroy all its register arguments.
|
| - __ movq(rdx, result_register());
|
| + if (op == Token::INIT_CONST) {
|
| + // Detect const reinitialization by checking for the hole value.
|
| + __ movq(rdx, target);
|
| + __ Cmp(rdx, Factory::the_hole_value());
|
| + __ j(not_equal, &done);
|
| + }
|
| + // Perform the assignment and issue the write barrier.
|
| + __ movq(target, rax);
|
| + // The value of the assignment is in rax. RecordWrite clobbers its
|
| + // register arguments.
|
| + __ movq(rdx, rax);
|
| int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
|
| __ RecordWrite(rcx, offset, rdx, rbx);
|
| break;
|
| }
|
|
|
| case Slot::LOOKUP:
|
| - UNREACHABLE();
|
| + // Call the runtime for the assignment. The runtime will ignore
|
| + // const reinitialization.
|
| + __ push(rax); // Value.
|
| + __ push(rsi); // Context.
|
| + __ Push(var->name());
|
| + if (op == Token::INIT_CONST) {
|
| + // The runtime will ignore const redeclaration.
|
| + __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
|
| + } else {
|
| + __ CallRuntime(Runtime::kStoreContextSlot, 3);
|
| + }
|
| break;
|
| }
|
| - Apply(context, result_register());
|
| + __ bind(&done);
|
| + }
|
|
|
| - } else {
|
| - // Variables rewritten as properties are not treated as variables in
|
| - // assignments.
|
| - UNREACHABLE();
|
| - }
|
| + Apply(context, rax);
|
| }
|
|
|
|
|
| @@ -1735,7 +1776,9 @@
|
| switch (assign_type) {
|
| case VARIABLE:
|
| if (expr->is_postfix()) {
|
| + // Perform the assignment as if via '='.
|
| EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
|
| + Token::ASSIGN,
|
| Expression::kEffect);
|
| // For all contexts except kEffect: We have the result on
|
| // top of the stack.
|
| @@ -1743,7 +1786,9 @@
|
| ApplyTOS(context_);
|
| }
|
| } else {
|
| + // Perform the assignment as if via '='.
|
| EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
|
| + Token::ASSIGN,
|
| context_);
|
| }
|
| break;
|
|
|