| Index: src/x64/fast-codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/fast-codegen-x64.cc (revision 3576)
|
| +++ src/x64/fast-codegen-x64.cc (working copy)
|
| @@ -202,57 +202,106 @@
|
| }
|
|
|
|
|
| -void FastCodeGenerator::Move(Expression::Context context, Register source) {
|
| +void FastCodeGenerator::Apply(Expression::Context context,
|
| + Slot* slot,
|
| + Register scratch) {
|
| switch (context) {
|
| case Expression::kUninitialized:
|
| UNREACHABLE();
|
| case Expression::kEffect:
|
| break;
|
| + case Expression::kValue: {
|
| + MemOperand location = EmitSlotSearch(slot, scratch);
|
| + __ push(location);
|
| + break;
|
| + }
|
| + case Expression::kTest:
|
| + case Expression::kValueTest:
|
| + case Expression::kTestValue:
|
| + Move(scratch, slot);
|
| + Apply(context, scratch);
|
| + break;
|
| + }
|
| +}
|
| +
|
| +
|
| +void FastCodeGenerator::Apply(Expression::Context context, Literal* lit) {
|
| + switch (context) {
|
| + case Expression::kUninitialized:
|
| + UNREACHABLE();
|
| + case Expression::kEffect:
|
| + break;
|
| case Expression::kValue:
|
| - __ push(source);
|
| + __ Push(lit->handle());
|
| break;
|
| case Expression::kTest:
|
| - TestAndBranch(source, true_label_, false_label_);
|
| + case Expression::kValueTest:
|
| + case Expression::kTestValue:
|
| + __ Move(rax, lit->handle());
|
| + Apply(context, rax);
|
| break;
|
| + }
|
| +}
|
| +
|
| +
|
| +void FastCodeGenerator::ApplyTOS(Expression::Context context) {
|
| + switch (context) {
|
| + case Expression::kUninitialized:
|
| + UNREACHABLE();
|
| + case Expression::kEffect:
|
| + __ Drop(1);
|
| + break;
|
| + case Expression::kValue:
|
| + break;
|
| + case Expression::kTest:
|
| + __ pop(rax);
|
| + TestAndBranch(rax, true_label_, false_label_);
|
| + break;
|
| case Expression::kValueTest: {
|
| Label discard;
|
| - __ push(source);
|
| - TestAndBranch(source, true_label_, &discard);
|
| + __ movq(rax, Operand(rsp, 0));
|
| + TestAndBranch(rax, true_label_, &discard);
|
| __ bind(&discard);
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| + __ Drop(1);
|
| __ jmp(false_label_);
|
| break;
|
| }
|
| case Expression::kTestValue: {
|
| Label discard;
|
| - __ push(source);
|
| - TestAndBranch(source, &discard, false_label_);
|
| + __ movq(rax, Operand(rsp, 0));
|
| + TestAndBranch(rax, &discard, false_label_);
|
| __ bind(&discard);
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| + __ Drop(1);
|
| __ jmp(true_label_);
|
| - break;
|
| }
|
| }
|
| }
|
|
|
|
|
| -void FastCodeGenerator::MoveTOS(Expression::Context context) {
|
| +void FastCodeGenerator::DropAndApply(int count,
|
| + Expression::Context context,
|
| + Register reg) {
|
| + ASSERT(count > 0);
|
| + ASSERT(!reg.is(rsp));
|
| switch (context) {
|
| case Expression::kUninitialized:
|
| UNREACHABLE();
|
| case Expression::kEffect:
|
| - __ Drop(1);
|
| + __ Drop(count);
|
| break;
|
| case Expression::kValue:
|
| + if (count > 1) __ Drop(count - 1);
|
| + __ movq(Operand(rsp, 0), reg);
|
| break;
|
| case Expression::kTest:
|
| - __ pop(rax);
|
| - TestAndBranch(rax, true_label_, false_label_);
|
| + __ Drop(count);
|
| + TestAndBranch(reg, true_label_, false_label_);
|
| break;
|
| case Expression::kValueTest: {
|
| Label discard;
|
| - __ movq(rax, Operand(rsp, 0));
|
| - TestAndBranch(rax, true_label_, &discard);
|
| + if (count > 1) __ Drop(count - 1);
|
| + __ movq(Operand(rsp, 0), reg);
|
| + TestAndBranch(reg, true_label_, &discard);
|
| __ bind(&discard);
|
| __ Drop(1);
|
| __ jmp(false_label_);
|
| @@ -260,11 +309,13 @@
|
| }
|
| case Expression::kTestValue: {
|
| Label discard;
|
| - __ movq(rax, Operand(rsp, 0));
|
| - TestAndBranch(rax, &discard, false_label_);
|
| + if (count > 1) __ Drop(count - 1);
|
| + __ movq(Operand(rsp, 0), reg);
|
| + TestAndBranch(reg, &discard, false_label_);
|
| __ bind(&discard);
|
| __ Drop(1);
|
| __ jmp(true_label_);
|
| + break;
|
| }
|
| }
|
| }
|
| @@ -295,48 +346,6 @@
|
| }
|
|
|
|
|
| -void FastCodeGenerator::Move(Expression::Context context,
|
| - Slot* source,
|
| - Register scratch) {
|
| - switch (context) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| - case Expression::kEffect:
|
| - break;
|
| - case Expression::kValue: {
|
| - MemOperand location = EmitSlotSearch(source, scratch);
|
| - __ push(location);
|
| - break;
|
| - }
|
| - case Expression::kTest:
|
| - case Expression::kValueTest:
|
| - case Expression::kTestValue:
|
| - Move(scratch, source);
|
| - Move(context, scratch);
|
| - break;
|
| - }
|
| -}
|
| -
|
| -
|
| -void FastCodeGenerator::Move(Expression::Context context, Literal* expr) {
|
| - switch (context) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| - case Expression::kEffect:
|
| - break;
|
| - case Expression::kValue:
|
| - __ Push(expr->handle());
|
| - break;
|
| - case Expression::kTest:
|
| - case Expression::kValueTest:
|
| - case Expression::kTestValue:
|
| - __ Move(rax, expr->handle());
|
| - Move(context, rax);
|
| - break;
|
| - }
|
| -}
|
| -
|
| -
|
| void FastCodeGenerator::Move(Slot* dst,
|
| Register src,
|
| Register scratch1,
|
| @@ -353,52 +362,6 @@
|
| }
|
|
|
|
|
| -void FastCodeGenerator::DropAndMove(Expression::Context context,
|
| - Register source,
|
| - int drop_count) {
|
| - ASSERT(drop_count > 0);
|
| - switch (context) {
|
| - case Expression::kUninitialized:
|
| - UNREACHABLE();
|
| - case Expression::kEffect:
|
| - __ addq(rsp, Immediate(drop_count * kPointerSize));
|
| - break;
|
| - case Expression::kValue:
|
| - if (drop_count > 1) {
|
| - __ addq(rsp, Immediate((drop_count - 1) * kPointerSize));
|
| - }
|
| - __ movq(Operand(rsp, 0), source);
|
| - break;
|
| - case Expression::kTest:
|
| - ASSERT(!source.is(rsp));
|
| - __ addq(rsp, Immediate(drop_count * kPointerSize));
|
| - TestAndBranch(source, true_label_, false_label_);
|
| - break;
|
| - case Expression::kValueTest: {
|
| - Label discard;
|
| - if (drop_count > 1) {
|
| - __ addq(rsp, Immediate((drop_count - 1) * kPointerSize));
|
| - }
|
| - __ movq(Operand(rsp, 0), source);
|
| - TestAndBranch(source, true_label_, &discard);
|
| - __ bind(&discard);
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| - __ jmp(false_label_);
|
| - break;
|
| - }
|
| - case Expression::kTestValue: {
|
| - Label discard;
|
| - __ movq(Operand(rsp, 0), source);
|
| - TestAndBranch(source, &discard, false_label_);
|
| - __ bind(&discard);
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| - __ jmp(true_label_);
|
| - break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| void FastCodeGenerator::TestAndBranch(Register source,
|
| Label* true_label,
|
| Label* false_label) {
|
| @@ -528,7 +491,7 @@
|
|
|
| // Value in rax is ignored (declarations are statements). Receiver
|
| // and key on stack are discarded.
|
| - __ addq(rsp, Immediate(2 * kPointerSize));
|
| + __ Drop(2);
|
| }
|
| }
|
| }
|
| @@ -558,7 +521,7 @@
|
| __ push(rsi);
|
| __ Push(boilerplate);
|
| __ CallRuntime(Runtime::kNewClosure, 2);
|
| - Move(expr->context(), rax);
|
| + Apply(expr->context(), rax);
|
| }
|
|
|
|
|
| @@ -585,7 +548,7 @@
|
| // is no test rax instruction here.
|
| __ nop();
|
|
|
| - DropAndMove(context, rax);
|
| + DropAndApply(1, context, rax);
|
| } else if (rewrite->AsSlot() != NULL) {
|
| Slot* slot = rewrite->AsSlot();
|
| if (FLAG_debug_code) {
|
| @@ -604,41 +567,43 @@
|
| break;
|
| }
|
| }
|
| - Move(context, slot, rax);
|
| + Apply(context, slot, rax);
|
| } else {
|
| - // A variable has been rewritten into an explicit access to
|
| - // an object property.
|
| + Comment cmnt(masm_, "Variable rewritten to property");
|
| + // A variable has been rewritten into an explicit access to an object
|
| + // property.
|
| Property* property = rewrite->AsProperty();
|
| ASSERT_NOT_NULL(property);
|
|
|
| - // Currently the only parameter expressions that can occur are
|
| - // on the form "slot[literal]".
|
| + // The only property expressions that can occur are of the form
|
| + // "slot[literal]".
|
|
|
| - // Check that the object is in a slot.
|
| + // Assert that the object is in a slot.
|
| Variable* object = property->obj()->AsVariableProxy()->AsVariable();
|
| ASSERT_NOT_NULL(object);
|
| Slot* object_slot = object->slot();
|
| ASSERT_NOT_NULL(object_slot);
|
|
|
| // Load the object.
|
| - Move(Expression::kValue, object_slot, rax);
|
| + MemOperand object_loc = EmitSlotSearch(object_slot, rax);
|
| + __ push(object_loc);
|
|
|
| - // Check that the key is a smi.
|
| + // Assert that the key is a smi.
|
| Literal* key_literal = property->key()->AsLiteral();
|
| ASSERT_NOT_NULL(key_literal);
|
| ASSERT(key_literal->handle()->IsSmi());
|
|
|
| // Load the key.
|
| - Move(Expression::kValue, key_literal);
|
| + __ Push(key_literal->handle());
|
|
|
| - // Do a KEYED property load.
|
| + // Do a keyed property load.
|
| Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
| __ call(ic, RelocInfo::CODE_TARGET);
|
| - // Notice: We must not have a "test rax, ..." instruction after
|
| - // the call. It is treated specially by the LoadIC code.
|
| + // Notice: We must not have a "test rax, ..." instruction after the
|
| + // call. It is treated specially by the LoadIC code.
|
|
|
| // Drop key and object left on the stack by IC, and push the result.
|
| - DropAndMove(context, rax, 2);
|
| + DropAndApply(2, context, rax);
|
| }
|
| }
|
|
|
| @@ -666,7 +631,7 @@
|
| __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
|
| // Label done:
|
| __ bind(&done);
|
| - Move(expr->context(), rax);
|
| + Apply(expr->context(), rax);
|
| }
|
|
|
|
|
| @@ -742,7 +707,7 @@
|
| case Expression::kUninitialized:
|
| UNREACHABLE();
|
| case Expression::kEffect:
|
| - if (result_saved) __ addq(rsp, Immediate(kPointerSize));
|
| + if (result_saved) __ Drop(1);
|
| break;
|
| case Expression::kValue:
|
| if (!result_saved) __ push(rax);
|
| @@ -756,7 +721,7 @@
|
| if (!result_saved) __ push(rax);
|
| TestAndBranch(rax, true_label_, &discard);
|
| __ bind(&discard);
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| + __ Drop(1);
|
| __ jmp(false_label_);
|
| break;
|
| }
|
| @@ -765,7 +730,7 @@
|
| if (!result_saved) __ push(rax);
|
| TestAndBranch(rax, &discard, false_label_);
|
| __ bind(&discard);
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| + __ Drop(1);
|
| __ jmp(true_label_);
|
| break;
|
| }
|
| @@ -821,7 +786,7 @@
|
| case Expression::kUninitialized:
|
| UNREACHABLE();
|
| case Expression::kEffect:
|
| - if (result_saved) __ addq(rsp, Immediate(kPointerSize));
|
| + if (result_saved) __ Drop(1);
|
| break;
|
| case Expression::kValue:
|
| if (!result_saved) __ push(rax);
|
| @@ -835,7 +800,7 @@
|
| if (!result_saved) __ push(rax);
|
| TestAndBranch(rax, true_label_, &discard);
|
| __ bind(&discard);
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| + __ Drop(1);
|
| __ jmp(false_label_);
|
| break;
|
| }
|
| @@ -844,7 +809,7 @@
|
| if (!result_saved) __ push(rax);
|
| TestAndBranch(rax, &discard, false_label_);
|
| __ bind(&discard);
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| + __ Drop(1);
|
| __ jmp(true_label_);
|
| break;
|
| }
|
| @@ -859,7 +824,7 @@
|
| __ Move(rcx, key->handle());
|
| Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
| __ Call(ic, RelocInfo::CODE_TARGET);
|
| - Move(context, rax);
|
| + Apply(context, rax);
|
| }
|
|
|
|
|
| @@ -868,7 +833,7 @@
|
| SetSourcePosition(prop->position());
|
| Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
| __ Call(ic, RelocInfo::CODE_TARGET);
|
| - Move(context, rax);
|
| + Apply(context, rax);
|
| }
|
|
|
|
|
| @@ -878,7 +843,7 @@
|
| NO_OVERWRITE,
|
| NO_GENERIC_BINARY_FLAGS);
|
| __ CallStub(&stub);
|
| - Move(context, rax);
|
| + Apply(context, rax);
|
| }
|
|
|
|
|
| @@ -896,7 +861,7 @@
|
| Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
| __ Call(ic, RelocInfo::CODE_TARGET);
|
| // Overwrite the global object on the stack with the result if needed.
|
| - DropAndMove(context, rax);
|
| + DropAndApply(1, context, rax);
|
|
|
| } else if (var->slot() != NULL) {
|
| Slot* slot = var->slot();
|
| @@ -928,7 +893,7 @@
|
| __ movq(target, rax);
|
| TestAndBranch(rax, true_label_, &discard);
|
| __ bind(&discard);
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| + __ Drop(1);
|
| __ jmp(false_label_);
|
| break;
|
| }
|
| @@ -938,7 +903,7 @@
|
| __ movq(target, rax);
|
| TestAndBranch(rax, &discard, false_label_);
|
| __ bind(&discard);
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| + __ Drop(1);
|
| __ jmp(true_label_);
|
| break;
|
| }
|
| @@ -959,9 +924,8 @@
|
| }
|
| int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
|
| __ RecordWrite(rcx, offset, rax, rbx);
|
| - if (context != Expression::kEffect &&
|
| - context != Expression::kValue) {
|
| - Move(context, rdx);
|
| + if (context != Expression::kEffect && context != Expression::kValue) {
|
| + Apply(context, rdx);
|
| }
|
| break;
|
| }
|
| @@ -1005,7 +969,7 @@
|
| __ pop(rax);
|
| }
|
|
|
| - DropAndMove(expr->context(), rax);
|
| + DropAndApply(1, expr->context(), rax);
|
| }
|
|
|
|
|
| @@ -1038,15 +1002,13 @@
|
| }
|
|
|
| // Receiver and key are still on stack.
|
| - __ addq(rsp, Immediate(2 * kPointerSize));
|
| - Move(expr->context(), rax);
|
| + DropAndApply(2, expr->context(), rax);
|
| }
|
|
|
|
|
| void FastCodeGenerator::VisitProperty(Property* expr) {
|
| Comment cmnt(masm_, "[ Property");
|
| Expression* key = expr->key();
|
| - uint32_t dummy;
|
|
|
| // Record the source position for the property load.
|
| SetSourcePosition(expr->position());
|
| @@ -1054,29 +1016,27 @@
|
| // Evaluate receiver.
|
| Visit(expr->obj());
|
|
|
| -
|
| - if (key->AsLiteral() != NULL && key->AsLiteral()->handle()->IsSymbol() &&
|
| - !String::cast(*(key->AsLiteral()->handle()))->AsArrayIndex(&dummy)) {
|
| - // Do a NAMED property load.
|
| - // The IC expects the property name in rcx and the receiver on the stack.
|
| + if (key->IsPropertyName()) {
|
| + // Do a named property load. The IC expects the property name in rcx
|
| + // and the receiver on the stack.
|
| __ Move(rcx, key->AsLiteral()->handle());
|
| Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
| __ call(ic, RelocInfo::CODE_TARGET);
|
| // By emitting a nop we make sure that we do not have a "test rax,..."
|
| // instruction after the call it is treated specially by the LoadIC code.
|
| __ nop();
|
| + DropAndApply(1, expr->context(), rax);
|
| } else {
|
| - // Do a KEYED property load.
|
| + // Do a keyed property load.
|
| Visit(expr->key());
|
| Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
| __ call(ic, RelocInfo::CODE_TARGET);
|
| - // Notice: We must not have a "test rax, ..." instruction after
|
| - // the call. It is treated specially by the LoadIC code.
|
| -
|
| - // Drop key left on the stack by IC.
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| + // Notice: We must not have a "test rax, ..." instruction after the
|
| + // call. It is treated specially by the LoadIC code.
|
| + __ nop();
|
| + // Drop key and receiver left on the stack by IC.
|
| + DropAndApply(2, expr->context(), rax);
|
| }
|
| - DropAndMove(expr->context(), rax);
|
| }
|
|
|
|
|
| @@ -1099,7 +1059,7 @@
|
| // Restore context register.
|
| __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
| // Discard the function left on TOS.
|
| - DropAndMove(expr->context(), rax);
|
| + DropAndApply(1, expr->context(), rax);
|
| }
|
|
|
|
|
| @@ -1117,7 +1077,7 @@
|
| // Restore context register.
|
| __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
| // Discard the function left on TOS.
|
| - DropAndMove(expr->context(), rax);
|
| + DropAndApply(1, expr->context(), rax);
|
| }
|
|
|
|
|
| @@ -1161,7 +1121,7 @@
|
| // instruction after the call it is treated specially by the LoadIC code.
|
| __ nop();
|
| // Drop key left on the stack by IC.
|
| - __ addq(rsp, Immediate(kPointerSize));
|
| + __ Drop(1);
|
| // Pop receiver.
|
| __ pop(rbx);
|
| // Push result (function).
|
| @@ -1230,7 +1190,7 @@
|
| __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
|
|
|
| // Replace function on TOS with result in rax, or pop it.
|
| - DropAndMove(expr->context(), rax);
|
| + DropAndApply(1, expr->context(), rax);
|
| }
|
|
|
|
|
| @@ -1260,10 +1220,10 @@
|
| // Restore context register.
|
| __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
|
| // Discard the function left on TOS.
|
| - DropAndMove(expr->context(), rax);
|
| + DropAndApply(1, expr->context(), rax);
|
| } else {
|
| __ CallRuntime(expr->function(), arg_count);
|
| - Move(expr->context(), rax);
|
| + Apply(expr->context(), rax);
|
| }
|
| }
|
|
|
| @@ -1386,7 +1346,7 @@
|
| }
|
|
|
| __ CallRuntime(Runtime::kTypeof, 1);
|
| - Move(expr->context(), rax);
|
| + Apply(expr->context(), rax);
|
| break;
|
| }
|
|
|
| @@ -1486,7 +1446,7 @@
|
| // For all contexts except kEffect: We have the result on
|
| // top of the stack.
|
| if (expr->context() != Expression::kEffect) {
|
| - MoveTOS(expr->context());
|
| + ApplyTOS(expr->context());
|
| }
|
| } else {
|
| EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
|
| @@ -1503,10 +1463,10 @@
|
| if (expr->is_postfix()) {
|
| __ Drop(1); // Result is on the stack under the receiver.
|
| if (expr->context() != Expression::kEffect) {
|
| - MoveTOS(expr->context());
|
| + ApplyTOS(expr->context());
|
| }
|
| } else {
|
| - DropAndMove(expr->context(), rax);
|
| + DropAndApply(1, expr->context(), rax);
|
| }
|
| break;
|
| }
|
| @@ -1519,10 +1479,10 @@
|
| if (expr->is_postfix()) {
|
| __ Drop(2); // Result is on the stack under the key and the receiver.
|
| if (expr->context() != Expression::kEffect) {
|
| - MoveTOS(expr->context());
|
| + ApplyTOS(expr->context());
|
| }
|
| } else {
|
| - DropAndMove(expr->context(), rax, 2);
|
| + DropAndApply(2, expr->context(), rax);
|
| }
|
| break;
|
| }
|
| @@ -1564,7 +1524,7 @@
|
| NO_OVERWRITE,
|
| NO_GENERIC_BINARY_FLAGS);
|
| __ CallStub(&stub);
|
| - Move(expr->context(), rax);
|
| + Apply(expr->context(), rax);
|
|
|
| break;
|
| }
|
| @@ -1732,7 +1692,7 @@
|
|
|
| void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
|
| __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
|
| - Move(expr->context(), rax);
|
| + Apply(expr->context(), rax);
|
| }
|
|
|
|
|
|
|