| Index: src/x64/fast-codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/fast-codegen-x64.cc (revision 3241)
|
| +++ src/x64/fast-codegen-x64.cc (working copy)
|
| @@ -418,6 +418,7 @@
|
| Comment cmnt(masm_, "[ VariableProxy");
|
| Expression* rewrite = expr->var()->rewrite();
|
| if (rewrite == NULL) {
|
| + ASSERT(expr->var()->is_global());
|
| Comment cmnt(masm_, "Global variable");
|
| // Use inline caching. Variable name is passed in rcx and the global
|
| // object on the stack.
|
| @@ -425,14 +426,55 @@
|
| __ Move(rcx, expr->name());
|
| Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
| __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
| -
|
| // A test rax instruction following the call is used by the IC to
|
| // indicate that the inobject property case was inlined. Ensure there
|
| // is no test rax instruction here.
|
| + __ nop();
|
| +
|
| DropAndMove(expr->context(), rax);
|
| } else {
|
| - Comment cmnt(masm_, "Stack slot");
|
| - Move(expr->context(), rewrite->AsSlot());
|
| + Slot* slot = rewrite->AsSlot();
|
| + ASSERT_NE(NULL, slot);
|
| + switch (slot->type()) {
|
| + case Slot::LOCAL:
|
| + case Slot::PARAMETER: {
|
| + Comment cmnt(masm_, "Stack slot");
|
| + Move(expr->context(), slot);
|
| + break;
|
| + }
|
| +
|
| + case Slot::CONTEXT: {
|
| + Comment cmnt(masm_, "Context slot");
|
| + int chain_length =
|
| + function_->scope()->ContextChainLength(slot->var()->scope());
|
| + if (chain_length > 0) {
|
| + // Move up the chain of contexts to the context containing the slot.
|
| + __ movq(rax,
|
| + Operand(rsi, Context::SlotOffset(Context::CLOSURE_INDEX)));
|
| + // Load the function context (which is the incoming, outer context).
|
| + __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
|
| + for (int i = 1; i < chain_length; i++) {
|
| + __ movq(rax,
|
| + Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)));
|
| + __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
|
| + }
|
| + // The context may be an intermediate context, not a function context.
|
| + __ movq(rax,
|
| + Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX)));
|
| + } else { // Slot is in the current function context.
|
| + // The context may be an intermediate context, not a function context.
|
| + __ movq(rax,
|
| + Operand(rsi, Context::SlotOffset(Context::FCONTEXT_INDEX)));
|
| + }
|
| + __ movq(rax, Operand(rax, Context::SlotOffset(slot->index())));
|
| + Move(expr->context(), rax);
|
| + break;
|
| + }
|
| +
|
| + case Slot::LOOKUP:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| }
|
| }
|
|
|
| @@ -695,44 +737,96 @@
|
| DropAndMove(expr->context(), rax);
|
|
|
| } else {
|
| - switch (expr->context()) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| - case Expression::kEffect:
|
| - // Perform assignment and discard value.
|
| - __ pop(Operand(rbp, SlotOffset(var->slot())));
|
| + Slot* slot = var->slot();
|
| + ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled.
|
| + switch (slot->type()) {
|
| + case Slot::LOCAL:
|
| + case Slot::PARAMETER: {
|
| + switch (expr->context()) {
|
| + case Expression::kUninitialized:
|
| + UNREACHABLE();
|
| + case Expression::kEffect:
|
| + // Perform assignment and discard value.
|
| + __ pop(Operand(rbp, SlotOffset(var->slot())));
|
| + break;
|
| + case Expression::kValue:
|
| + // Perform assignment and preserve value.
|
| + __ movq(rax, Operand(rsp, 0));
|
| + __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
| + break;
|
| + case Expression::kTest:
|
| + // Perform assignment and test (and discard) value.
|
| + __ pop(rax);
|
| + __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
| + TestAndBranch(rax, true_label_, false_label_);
|
| + break;
|
| + case Expression::kValueTest: {
|
| + Label discard;
|
| + __ movq(rax, Operand(rsp, 0));
|
| + __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
| + TestAndBranch(rax, true_label_, &discard);
|
| + __ bind(&discard);
|
| + __ addq(rsp, Immediate(kPointerSize));
|
| + __ jmp(false_label_);
|
| + break;
|
| + }
|
| + case Expression::kTestValue: {
|
| + Label discard;
|
| + __ movq(rax, Operand(rsp, 0));
|
| + __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
| + TestAndBranch(rax, &discard, false_label_);
|
| + __ bind(&discard);
|
| + __ addq(rsp, Immediate(kPointerSize));
|
| + __ jmp(true_label_);
|
| + break;
|
| + }
|
| + }
|
| break;
|
| - case Expression::kValue:
|
| - // Perform assignment and preserve value.
|
| - __ movq(rax, Operand(rsp, 0));
|
| - __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
| + }
|
| +
|
| + case Slot::CONTEXT: {
|
| + int chain_length =
|
| + function_->scope()->ContextChainLength(slot->var()->scope());
|
| + if (chain_length > 0) {
|
| + // Move up the context chain to the context containing the slot.
|
| + __ movq(rax,
|
| + Operand(rsi, Context::SlotOffset(Context::CLOSURE_INDEX)));
|
| + // Load the function context (which is the incoming, outer context).
|
| + __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
|
| + for (int i = 1; i < chain_length; i++) {
|
| + __ movq(rax,
|
| + Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)));
|
| + __ movq(rax, FieldOperand(rax, JSFunction::kContextOffset));
|
| + }
|
| + } else { // Slot is in the current context. Generate optimized code.
|
| + __ movq(rax, rsi); // RecordWrite destroys the object register.
|
| + }
|
| + if (FLAG_debug_code) {
|
| + __ cmpq(rax,
|
| + Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX)));
|
| + __ Check(equal, "Context Slot chain length wrong.");
|
| + }
|
| + __ pop(rcx);
|
| + __ movq(Operand(rax, Context::SlotOffset(slot->index())), rcx);
|
| +
|
| + // RecordWrite may destroy all its register arguments.
|
| + if (expr->context() == Expression::kValue) {
|
| + __ push(rcx);
|
| + } else if (expr->context() != Expression::kEffect) {
|
| + __ movq(rdx, rcx);
|
| + }
|
| + int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
|
| + __ RecordWrite(rax, offset, rcx, rbx);
|
| + if (expr->context() != Expression::kEffect &&
|
| + expr->context() != Expression::kValue) {
|
| + Move(expr->context(), rdx);
|
| + }
|
| break;
|
| - case Expression::kTest:
|
| - // Perform assignment and test (and discard) value.
|
| - __ pop(rax);
|
| - __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
| - TestAndBranch(rax, true_label_, false_label_);
|
| - break;
|
| - case Expression::kValueTest: {
|
| - Label discard;
|
| - __ movq(rax, Operand(rsp, 0));
|
| - __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
| - TestAndBranch(rax, true_label_, &discard);
|
| - __ bind(&discard);
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| - __ jmp(false_label_);
|
| - break;
|
| }
|
| - case Expression::kTestValue: {
|
| - Label discard;
|
| - __ movq(rax, Operand(rsp, 0));
|
| - __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
| - TestAndBranch(rax, &discard, false_label_);
|
| - __ bind(&discard);
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| - __ jmp(true_label_);
|
| +
|
| + case Slot::LOOKUP:
|
| + UNREACHABLE();
|
| break;
|
| - }
|
| }
|
| }
|
| }
|
|
|