| Index: src/x64/fast-codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/fast-codegen-x64.cc (revision 3532)
|
| +++ src/x64/fast-codegen-x64.cc (working copy)
|
| @@ -270,30 +270,28 @@
|
| }
|
|
|
|
|
| -template <>
|
| -Operand FastCodeGenerator::CreateSlotOperand<Operand>(Slot* source,
|
| - Register scratch) {
|
| - switch (source->type()) {
|
| +MemOperand FastCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
|
| + switch (slot->type()) {
|
| case Slot::PARAMETER:
|
| case Slot::LOCAL:
|
| - return Operand(rbp, SlotOffset(source));
|
| + return Operand(rbp, SlotOffset(slot));
|
| case Slot::CONTEXT: {
|
| int context_chain_length =
|
| - function_->scope()->ContextChainLength(source->var()->scope());
|
| + function_->scope()->ContextChainLength(slot->var()->scope());
|
| __ LoadContext(scratch, context_chain_length);
|
| - return CodeGenerator::ContextOperand(scratch, source->index());
|
| + return CodeGenerator::ContextOperand(scratch, slot->index());
|
| }
|
| case Slot::LOOKUP:
|
| - UNIMPLEMENTED();
|
| + UNREACHABLE();
|
| }
|
| UNREACHABLE();
|
| return Operand(rax, 0);
|
| }
|
|
|
|
|
| -void FastCodeGenerator::Move(Register dst, Slot* source) {
|
| - Operand location = CreateSlotOperand<Operand>(source, dst);
|
| - __ movq(dst, location);
|
| +void FastCodeGenerator::Move(Register destination, Slot* source) {
|
| + MemOperand location = EmitSlotSearch(source, destination);
|
| + __ movq(destination, location);
|
| }
|
|
|
|
|
| @@ -306,7 +304,7 @@
|
| case Expression::kEffect:
|
| break;
|
| case Expression::kValue: {
|
| - Operand location = CreateSlotOperand<Operand>(source, scratch);
|
| + MemOperand location = EmitSlotSearch(source, scratch);
|
| __ push(location);
|
| break;
|
| }
|
| @@ -343,25 +341,14 @@
|
| Register src,
|
| Register scratch1,
|
| Register scratch2) {
|
| - switch (dst->type()) {
|
| - case Slot::PARAMETER:
|
| - case Slot::LOCAL:
|
| - __ movq(Operand(rbp, SlotOffset(dst)), src);
|
| - break;
|
| - case Slot::CONTEXT: {
|
| - ASSERT(!src.is(scratch1));
|
| - ASSERT(!src.is(scratch2));
|
| - ASSERT(!scratch1.is(scratch2));
|
| - int context_chain_length =
|
| - function_->scope()->ContextChainLength(dst->var()->scope());
|
| - __ LoadContext(scratch1, context_chain_length);
|
| - __ movq(Operand(scratch1, Context::SlotOffset(dst->index())), src);
|
| - int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
|
| - __ RecordWrite(scratch1, offset, src, scratch2);
|
| - break;
|
| - }
|
| - case Slot::LOOKUP:
|
| - UNIMPLEMENTED();
|
| + ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
|
| + ASSERT(!scratch1.is(src) && !scratch2.is(src));
|
| + MemOperand location = EmitSlotSearch(dst, scratch1);
|
| + __ movq(location, src);
|
| + // Emit the write barrier code if the location is in the heap.
|
| + if (dst->type() == Slot::CONTEXT) {
|
| + int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
|
| + __ RecordWrite(scratch1, offset, src, scratch2);
|
| }
|
| }
|
|
|
| @@ -457,14 +444,17 @@
|
| case Slot::LOCAL:
|
| if (decl->mode() == Variable::CONST) {
|
| __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
|
| - __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister);
|
| + __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
|
| } else if (decl->fun() != NULL) {
|
| Visit(decl->fun());
|
| - __ pop(Operand(rbp, SlotOffset(var->slot())));
|
| + __ pop(Operand(rbp, SlotOffset(slot)));
|
| }
|
| break;
|
|
|
| case Slot::CONTEXT:
|
| + // We bypass the general EmitSlotSearch because we know more about
|
| + // this specific context.
|
| +
|
| // The variable in the decl always resides in the current context.
|
| ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope()));
|
| if (FLAG_debug_code) {
|
| @@ -908,34 +898,34 @@
|
| // Overwrite the global object on the stack with the result if needed.
|
| DropAndMove(context, rax);
|
|
|
| - } else if (var->slot()) {
|
| + } else if (var->slot() != NULL) {
|
| Slot* slot = var->slot();
|
| - ASSERT_NOT_NULL(slot); // Variables rewritten as properties not handled.
|
| switch (slot->type()) {
|
| case Slot::LOCAL:
|
| case Slot::PARAMETER: {
|
| + Operand target = Operand(rbp, SlotOffset(slot));
|
| switch (context) {
|
| case Expression::kUninitialized:
|
| UNREACHABLE();
|
| case Expression::kEffect:
|
| // Perform assignment and discard value.
|
| - __ pop(Operand(rbp, SlotOffset(var->slot())));
|
| + __ pop(target);
|
| break;
|
| case Expression::kValue:
|
| // Perform assignment and preserve value.
|
| __ movq(rax, Operand(rsp, 0));
|
| - __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
| + __ movq(target, rax);
|
| break;
|
| case Expression::kTest:
|
| // Perform assignment and test (and discard) value.
|
| __ pop(rax);
|
| - __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
| + __ movq(target, 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);
|
| + __ movq(target, rax);
|
| TestAndBranch(rax, true_label_, &discard);
|
| __ bind(&discard);
|
| __ addq(rsp, Immediate(kPointerSize));
|
| @@ -945,7 +935,7 @@
|
| case Expression::kTestValue: {
|
| Label discard;
|
| __ movq(rax, Operand(rsp, 0));
|
| - __ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
| + __ movq(target, rax);
|
| TestAndBranch(rax, &discard, false_label_);
|
| __ bind(&discard);
|
| __ addq(rsp, Immediate(kPointerSize));
|
| @@ -957,38 +947,18 @@
|
| }
|
|
|
| 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);
|
| + MemOperand target = EmitSlotSearch(slot, rcx);
|
| + __ pop(rax);
|
| + __ movq(target, rax);
|
|
|
| // RecordWrite may destroy all its register arguments.
|
| if (context == Expression::kValue) {
|
| - __ push(rcx);
|
| + __ push(rax);
|
| } else if (context != Expression::kEffect) {
|
| - __ movq(rdx, rcx);
|
| + __ movq(rdx, rax);
|
| }
|
| int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
|
| - __ RecordWrite(rax, offset, rcx, rbx);
|
| + __ RecordWrite(rcx, offset, rax, rbx);
|
| if (context != Expression::kEffect &&
|
| context != Expression::kValue) {
|
| Move(context, rdx);
|
| @@ -1000,6 +970,10 @@
|
| UNREACHABLE();
|
| break;
|
| }
|
| + } else {
|
| + // Variables rewritten as properties are not treated as variables in
|
| + // assignments.
|
| + UNREACHABLE();
|
| }
|
| }
|
|
|
|
|