| Index: src/x64/full-codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/full-codegen-x64.cc (revision 6919)
|
| +++ src/x64/full-codegen-x64.cc (working copy)
|
| @@ -207,43 +207,45 @@
|
| Move(dot_arguments_slot, rcx, rbx, rdx);
|
| }
|
|
|
| - { Comment cmnt(masm_, "[ Declarations");
|
| - // For named function expressions, declare the function name as a
|
| - // constant.
|
| - if (scope()->is_function_scope() && scope()->function() != NULL) {
|
| - EmitDeclaration(scope()->function(), Variable::CONST, NULL);
|
| - }
|
| - // Visit all the explicit declarations unless there is an illegal
|
| - // redeclaration.
|
| - if (scope()->HasIllegalRedeclaration()) {
|
| - scope()->VisitIllegalRedeclaration(this);
|
| - } else {
|
| - VisitDeclarations(scope()->declarations());
|
| - }
|
| - }
|
| -
|
| if (FLAG_trace) {
|
| __ CallRuntime(Runtime::kTraceEnter, 0);
|
| }
|
|
|
| - { Comment cmnt(masm_, "[ Stack check");
|
| - PrepareForBailout(info->function(), NO_REGISTERS);
|
| - NearLabel ok;
|
| - __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
|
| - __ j(above_equal, &ok);
|
| - StackCheckStub stub;
|
| - __ CallStub(&stub);
|
| - __ bind(&ok);
|
| - }
|
| + // Visit the declarations and body unless there is an illegal
|
| + // redeclaration.
|
| + if (scope()->HasIllegalRedeclaration()) {
|
| + Comment cmnt(masm_, "[ Declarations");
|
| + scope()->VisitIllegalRedeclaration(this);
|
| + } else {
|
| + { Comment cmnt(masm_, "[ Declarations");
|
| + // For named function expressions, declare the function name as a
|
| + // constant.
|
| + if (scope()->is_function_scope() && scope()->function() != NULL) {
|
| + EmitDeclaration(scope()->function(), Variable::CONST, NULL);
|
| + }
|
| + VisitDeclarations(scope()->declarations());
|
| + }
|
|
|
| - { Comment cmnt(masm_, "[ Body");
|
| - ASSERT(loop_depth() == 0);
|
| - VisitStatements(function()->body());
|
| - ASSERT(loop_depth() == 0);
|
| + { Comment cmnt(masm_, "[ Stack check");
|
| + PrepareForBailout(info->function(), NO_REGISTERS);
|
| + NearLabel ok;
|
| + __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
|
| + __ j(above_equal, &ok);
|
| + StackCheckStub stub;
|
| + __ CallStub(&stub);
|
| + __ bind(&ok);
|
| + }
|
| +
|
| + { Comment cmnt(masm_, "[ Body");
|
| + ASSERT(loop_depth() == 0);
|
| + VisitStatements(function()->body());
|
| + ASSERT(loop_depth() == 0);
|
| + }
|
| }
|
|
|
| + // Always emit a 'return undefined' in case control fell off the end of
|
| + // the body.
|
| { Comment cmnt(masm_, "[ return <undefined>;");
|
| - // Emit a 'return undefined' in case control fell off the end of the body.
|
| __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
|
| EmitReturnSequence();
|
| }
|
| @@ -1082,7 +1084,10 @@
|
| // Check that last extension is NULL.
|
| __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
|
| __ j(not_equal, slow);
|
| - __ movq(temp, ContextOperand(context, Context::FCONTEXT_INDEX));
|
| +
|
| + // This function is used only for loads, not stores, so it's safe to
|
| + // return an rsi-based operand (the write barrier cannot be allowed to
|
| + // destroy the rsi register).
|
| return ContextOperand(temp, slot->index());
|
| }
|
|
|
| @@ -1730,57 +1735,75 @@
|
| : Builtins::StoreIC_Initialize));
|
| EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
|
|
| - } 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;
|
| + } else if (op == Token::INIT_CONST) {
|
| + // Like var declarations, const declarations are hoisted to function
|
| + // scope. However, unlike var initializers, const initializers are able
|
| + // to drill a hole to that function context, even from inside a 'with'
|
| + // context. We thus bypass the normal static scope lookup.
|
| Slot* slot = var->AsSlot();
|
| + Label skip;
|
| switch (slot->type()) {
|
| case Slot::PARAMETER:
|
| + // No const parameters.
|
| + UNREACHABLE();
|
| + break;
|
| case Slot::LOCAL:
|
| - if (op == Token::INIT_CONST) {
|
| - // Detect const reinitialization by checking for the hole value.
|
| - __ movq(rdx, Operand(rbp, SlotOffset(slot)));
|
| - __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
|
| - __ j(not_equal, &done);
|
| - }
|
| + __ movq(rdx, Operand(rbp, SlotOffset(slot)));
|
| + __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
|
| + __ j(not_equal, &skip);
|
| + __ movq(Operand(rbp, SlotOffset(slot)), rax);
|
| + break;
|
| + case Slot::CONTEXT: {
|
| + __ movq(rcx, ContextOperand(rsi, Context::FCONTEXT_INDEX));
|
| + __ movq(rdx, ContextOperand(rcx, slot->index()));
|
| + __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
|
| + __ j(not_equal, &skip);
|
| + __ movq(ContextOperand(rcx, slot->index()), rax);
|
| + int offset = Context::SlotOffset(slot->index());
|
| + __ movq(rdx, rax); // Preserve the stored value in eax.
|
| + __ RecordWrite(rcx, offset, rdx, rbx);
|
| + break;
|
| + }
|
| + case Slot::LOOKUP:
|
| + __ push(rax);
|
| + __ push(rsi);
|
| + __ Push(var->name());
|
| + __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
|
| + break;
|
| + }
|
| + __ bind(&skip);
|
| +
|
| + } else if (var->mode() != Variable::CONST) {
|
| + // Perform the assignment for non-const variables. Const assignments
|
| + // are simply skipped.
|
| + Slot* slot = var->AsSlot();
|
| + switch (slot->type()) {
|
| + case Slot::PARAMETER:
|
| + case Slot::LOCAL:
|
| // Perform the assignment.
|
| __ movq(Operand(rbp, SlotOffset(slot)), rax);
|
| break;
|
|
|
| case Slot::CONTEXT: {
|
| MemOperand target = EmitSlotSearch(slot, rcx);
|
| - if (op == Token::INIT_CONST) {
|
| - // Detect const reinitialization by checking for the hole value.
|
| - __ movq(rdx, target);
|
| - __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
|
| - __ 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;
|
| + int offset = Context::SlotOffset(slot->index());
|
| __ RecordWrite(rcx, offset, rdx, rbx);
|
| break;
|
| }
|
|
|
| case Slot::LOOKUP:
|
| - // Call the runtime for the assignment. The runtime will ignore
|
| - // const reinitialization.
|
| + // Call the runtime for the assignment.
|
| __ 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);
|
| - }
|
| + __ CallRuntime(Runtime::kStoreContextSlot, 3);
|
| break;
|
| }
|
| - __ bind(&done);
|
| }
|
| }
|
|
|
|
|