Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(147)

Unified Diff: src/x64/fast-codegen-x64.cc

Issue 555073: Merge r3610, r3611, r3612, r3630, r3636, r3640, and r3664... (Closed) Base URL: http://v8.googlecode.com/svn/trunk/
Patch Set: Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/x64/codegen-x64.cc ('k') | src/x64/virtual-frame-x64.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/x64/fast-codegen-x64.cc
===================================================================
--- src/x64/fast-codegen-x64.cc (revision 3684)
+++ src/x64/fast-codegen-x64.cc (working copy)
@@ -62,11 +62,9 @@
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = fun->scope()->num_stack_slots();
- if (locals_count <= 1) {
- if (locals_count > 0) {
- __ PushRoot(Heap::kUndefinedValueRootIndex);
- }
- } else {
+ if (locals_count == 1) {
+ __ PushRoot(Heap::kUndefinedValueRootIndex);
+ } else if (locals_count > 1) {
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
for (int i = 0; i < locals_count; i++) {
__ push(rdx);
@@ -132,6 +130,10 @@
Move(dot_arguments_slot, rcx, rbx, rdx);
}
+ { Comment cmnt(masm_, "[ Declarations");
+ VisitDeclarations(fun->scope()->declarations());
+ }
+
{ Comment cmnt(masm_, "[ Stack check");
Label ok;
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
@@ -141,10 +143,6 @@
__ bind(&ok);
}
- { Comment cmnt(masm_, "[ Declarations");
- VisitDeclarations(fun->scope()->declarations());
- }
-
if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceEnter, 0);
}
@@ -202,24 +200,86 @@
}
-void FastCodeGenerator::Apply(Expression::Context context,
- Slot* slot,
- Register scratch) {
+void FastCodeGenerator::Apply(Expression::Context context, Register reg) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
+
case Expression::kEffect:
+ // Nothing to do.
break;
+
+ case Expression::kValue:
+ // Move value into place.
+ switch (location_) {
+ case kAccumulator:
+ if (!reg.is(result_register())) __ movq(result_register(), reg);
+ break;
+ case kStack:
+ __ push(reg);
+ break;
+ }
+ break;
+
+ case Expression::kTest:
+ // For simplicity we always test the accumulator register.
+ if (!reg.is(result_register())) __ movq(result_register(), reg);
+ DoTest(context);
+ break;
+
+ case Expression::kValueTest:
+ case Expression::kTestValue:
+ if (!reg.is(result_register())) __ movq(result_register(), reg);
+ switch (location_) {
+ case kAccumulator:
+ break;
+ case kStack:
+ __ push(result_register());
+ break;
+ }
+ DoTest(context);
+ break;
+ }
+}
+
+
+void FastCodeGenerator::Apply(Expression::Context context, Slot* slot) {
+ switch (context) {
+ case Expression::kUninitialized:
+ UNREACHABLE();
+ case Expression::kEffect:
+ // Nothing to do.
+ break;
case Expression::kValue: {
- MemOperand location = EmitSlotSearch(slot, scratch);
- __ push(location);
+ MemOperand slot_operand = EmitSlotSearch(slot, result_register());
+ switch (location_) {
+ case kAccumulator:
+ __ movq(result_register(), slot_operand);
+ break;
+ case kStack:
+ // Memory operands can be pushed directly.
+ __ push(slot_operand);
+ break;
+ }
break;
}
+
case Expression::kTest:
+ Move(result_register(), slot);
+ DoTest(context);
+ break;
+
case Expression::kValueTest:
case Expression::kTestValue:
- Move(scratch, slot);
- Apply(context, scratch);
+ Move(result_register(), slot);
+ switch (location_) {
+ case kAccumulator:
+ break;
+ case kStack:
+ __ push(result_register());
+ break;
+ }
+ DoTest(context);
break;
}
}
@@ -230,15 +290,35 @@
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
+ // Nothing to do.
break;
case Expression::kValue:
- __ Push(lit->handle());
+ switch (location_) {
+ case kAccumulator:
+ __ Move(result_register(), lit->handle());
+ break;
+ case kStack:
+ __ Push(lit->handle());
+ break;
+ }
break;
+
case Expression::kTest:
+ __ Move(result_register(), lit->handle());
+ DoTest(context);
+ break;
+
case Expression::kValueTest:
case Expression::kTestValue:
- __ Move(rax, lit->handle());
- Apply(context, rax);
+ __ Move(result_register(), lit->handle());
+ switch (location_) {
+ case kAccumulator:
+ break;
+ case kStack:
+ __ push(result_register());
+ break;
+ }
+ DoTest(context);
break;
}
}
@@ -248,32 +328,38 @@
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
+
case Expression::kEffect:
__ Drop(1);
break;
+
case Expression::kValue:
+ switch (location_) {
+ case kAccumulator:
+ __ pop(result_register());
+ break;
+ case kStack:
+ break;
+ }
break;
+
case Expression::kTest:
- __ pop(rax);
- TestAndBranch(rax, true_label_, false_label_);
+ __ pop(result_register());
+ DoTest(context);
break;
- case Expression::kValueTest: {
- Label discard;
- __ movq(rax, Operand(rsp, 0));
- TestAndBranch(rax, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
+
+ case Expression::kValueTest:
+ case Expression::kTestValue:
+ switch (location_) {
+ case kAccumulator:
+ __ pop(result_register());
+ break;
+ case kStack:
+ __ movq(result_register(), Operand(rsp, 0));
+ break;
+ }
+ DoTest(context);
break;
- }
- case Expression::kTestValue: {
- Label discard;
- __ movq(rax, Operand(rsp, 0));
- TestAndBranch(rax, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- }
}
}
@@ -286,37 +372,244 @@
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
+
case Expression::kEffect:
__ Drop(count);
break;
+
case Expression::kValue:
- if (count > 1) __ Drop(count - 1);
- __ movq(Operand(rsp, 0), reg);
+ switch (location_) {
+ case kAccumulator:
+ __ Drop(count);
+ if (!reg.is(result_register())) __ movq(result_register(), reg);
+ break;
+ case kStack:
+ if (count > 1) __ Drop(count - 1);
+ __ movq(Operand(rsp, 0), reg);
+ break;
+ }
break;
+
case Expression::kTest:
__ Drop(count);
- TestAndBranch(reg, true_label_, false_label_);
+ if (!reg.is(result_register())) __ movq(result_register(), reg);
+ DoTest(context);
break;
- case Expression::kValueTest: {
- Label discard;
- if (count > 1) __ Drop(count - 1);
- __ movq(Operand(rsp, 0), reg);
- TestAndBranch(reg, true_label_, &discard);
+
+ case Expression::kValueTest:
+ case Expression::kTestValue:
+ switch (location_) {
+ case kAccumulator:
+ __ Drop(count);
+ if (!reg.is(result_register())) __ movq(result_register(), reg);
+ break;
+ case kStack:
+ if (count > 1) __ Drop(count - 1);
+ __ movq(result_register(), reg);
+ __ movq(Operand(rsp, 0), result_register());
+ break;
+ }
+ DoTest(context);
+ break;
+ }
+}
+
+
+void FastCodeGenerator::Apply(Expression::Context context,
+ Label* materialize_true,
+ Label* materialize_false) {
+ switch (context) {
+ case Expression::kUninitialized:
+
+ case Expression::kEffect:
+ ASSERT_EQ(materialize_true, materialize_false);
+ __ bind(materialize_true);
+ break;
+
+ case Expression::kValue: {
+ Label done;
+ switch (location_) {
+ case kAccumulator:
+ __ bind(materialize_true);
+ __ Move(result_register(), Factory::true_value());
+ __ jmp(&done);
+ __ bind(materialize_false);
+ __ Move(result_register(), Factory::false_value());
+ break;
+ case kStack:
+ __ bind(materialize_true);
+ __ Push(Factory::true_value());
+ __ jmp(&done);
+ __ bind(materialize_false);
+ __ Push(Factory::false_value());
+ break;
+ }
+ __ bind(&done);
+ break;
+ }
+
+ case Expression::kTest:
+ break;
+
+ case Expression::kValueTest:
+ __ bind(materialize_true);
+ switch (location_) {
+ case kAccumulator:
+ __ Move(result_register(), Factory::true_value());
+ break;
+ case kStack:
+ __ Push(Factory::true_value());
+ break;
+ }
+ __ jmp(true_label_);
+ break;
+
+ case Expression::kTestValue:
+ __ bind(materialize_false);
+ switch (location_) {
+ case kAccumulator:
+ __ Move(result_register(), Factory::false_value());
+ break;
+ case kStack:
+ __ Push(Factory::false_value());
+ break;
+ }
+ __ jmp(false_label_);
+ break;
+ }
+}
+
+
+void FastCodeGenerator::DoTest(Expression::Context context) {
+ // The value to test is in the accumulator. If the value might be needed
+ // on the stack (value/test and test/value contexts with a stack location
+ // desired), then the value is already duplicated on the stack.
+ ASSERT_NE(NULL, true_label_);
+ ASSERT_NE(NULL, false_label_);
+
+ // In value/test and test/value expression contexts with stack as the
+ // desired location, there is already an extra value on the stack. Use a
+ // label to discard it if unneeded.
+ Label discard;
+ Label* if_true = true_label_;
+ Label* if_false = false_label_;
+ switch (context) {
+ case Expression::kUninitialized:
+ case Expression::kEffect:
+ case Expression::kValue:
+ UNREACHABLE();
+ case Expression::kTest:
+ break;
+ case Expression::kValueTest:
+ switch (location_) {
+ case kAccumulator:
+ break;
+ case kStack:
+ if_false = &discard;
+ break;
+ }
+ break;
+ case Expression::kTestValue:
+ switch (location_) {
+ case kAccumulator:
+ break;
+ case kStack:
+ if_true = &discard;
+ break;
+ }
+ break;
+ }
+
+ // Emit the inlined tests assumed by the stub.
+ __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex);
+ __ j(equal, if_false);
+ __ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
+ __ j(equal, if_true);
+ __ CompareRoot(result_register(), Heap::kFalseValueRootIndex);
+ __ j(equal, if_false);
+ ASSERT_EQ(0, kSmiTag);
+ __ SmiCompare(result_register(), Smi::FromInt(0));
+ __ j(equal, if_false);
+ Condition is_smi = masm_->CheckSmi(result_register());
+ __ j(is_smi, if_true);
+
+ // Save a copy of the value if it may be needed and isn't already saved.
+ switch (context) {
+ case Expression::kUninitialized:
+ case Expression::kEffect:
+ case Expression::kValue:
+ UNREACHABLE();
+ case Expression::kTest:
+ break;
+ case Expression::kValueTest:
+ switch (location_) {
+ case kAccumulator:
+ __ push(result_register());
+ break;
+ case kStack:
+ break;
+ }
+ break;
+ case Expression::kTestValue:
+ switch (location_) {
+ case kAccumulator:
+ __ push(result_register());
+ break;
+ case kStack:
+ break;
+ }
+ break;
+ }
+
+ // Call the ToBoolean stub for all other cases.
+ ToBooleanStub stub;
+ __ push(result_register());
+ __ CallStub(&stub);
+ __ testq(rax, rax);
+
+ // The stub returns nonzero for true. Complete based on the context.
+ switch (context) {
+ case Expression::kUninitialized:
+ case Expression::kEffect:
+ case Expression::kValue:
+ UNREACHABLE();
+
+ case Expression::kTest:
+ __ j(not_zero, true_label_);
+ __ jmp(false_label_);
+ break;
+
+ case Expression::kValueTest:
+ switch (location_) {
+ case kAccumulator:
+ __ j(zero, &discard);
+ __ pop(result_register());
+ __ jmp(true_label_);
+ break;
+ case kStack:
+ __ j(not_zero, true_label_);
+ break;
+ }
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
break;
- }
- case Expression::kTestValue: {
- Label discard;
- if (count > 1) __ Drop(count - 1);
- __ movq(Operand(rsp, 0), reg);
- TestAndBranch(reg, &discard, false_label_);
+
+ case Expression::kTestValue:
+ switch (location_) {
+ case kAccumulator:
+ __ j(not_zero, &discard);
+ __ pop(result_register());
+ __ jmp(false_label_);
+ break;
+ case kStack:
+ __ j(zero, false_label_);
+ break;
+ }
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
break;
- }
}
}
@@ -362,38 +655,6 @@
}
-void FastCodeGenerator::TestAndBranch(Register source,
- Label* true_label,
- Label* false_label) {
- ASSERT_NE(NULL, true_label);
- ASSERT_NE(NULL, false_label);
- // Use the shared ToBoolean stub to compile the value in the register into
- // control flow to the code generator's true and false labels. Perform
- // the fast checks assumed by the stub.
-
- // The undefined value is false.
- __ CompareRoot(source, Heap::kUndefinedValueRootIndex);
- __ j(equal, false_label);
- __ CompareRoot(source, Heap::kTrueValueRootIndex); // True is true.
- __ j(equal, true_label);
- __ CompareRoot(source, Heap::kFalseValueRootIndex); // False is false.
- __ j(equal, false_label);
- ASSERT_EQ(0, kSmiTag);
- __ SmiCompare(source, Smi::FromInt(0)); // The smi zero is false.
- __ j(equal, false_label);
- Condition is_smi = masm_->CheckSmi(source); // All other smis are true.
- __ j(is_smi, true_label);
-
- // Call the stub for all other cases.
- __ push(source);
- ToBooleanStub stub;
- __ CallStub(&stub);
- __ testq(rax, rax); // The stub returns nonzero for true.
- __ j(not_zero, true_label);
- __ jmp(false_label);
-}
-
-
void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
Comment cmnt(masm_, "[ Declaration");
Variable* var = decl->proxy()->var();
@@ -409,8 +670,8 @@
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
__ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
} else if (decl->fun() != NULL) {
- Visit(decl->fun());
- __ pop(Operand(rbp, SlotOffset(slot)));
+ VisitForValue(decl->fun(), kAccumulator);
+ __ movq(Operand(rbp, SlotOffset(slot)), result_register());
}
break;
@@ -433,11 +694,11 @@
kScratchRegister);
// No write barrier since the hole value is in old space.
} else if (decl->fun() != NULL) {
- Visit(decl->fun());
- __ pop(rax);
- __ movq(CodeGenerator::ContextOperand(rsi, slot->index()), rax);
+ VisitForValue(decl->fun(), kAccumulator);
+ __ movq(CodeGenerator::ContextOperand(rsi, slot->index()),
+ result_register());
int offset = Context::SlotOffset(slot->index());
- __ RecordWrite(rsi, offset, rax, rcx);
+ __ RecordWrite(rsi, offset, result_register(), rcx);
}
break;
@@ -457,7 +718,7 @@
if (decl->mode() == Variable::CONST) {
__ PushRoot(Heap::kTheHoleValueRootIndex);
} else if (decl->fun() != NULL) {
- Visit(decl->fun());
+ VisitForValue(decl->fun(), kStack);
} else {
__ Push(Smi::FromInt(0)); // no initial value!
}
@@ -470,24 +731,20 @@
if (decl->fun() != NULL || decl->mode() == Variable::CONST) {
// We are declaring a function or constant that rewrites to a
// property. Use (keyed) IC to set the initial value.
- ASSERT_EQ(Expression::kValue, prop->obj()->context());
- Visit(prop->obj());
- ASSERT_EQ(Expression::kValue, prop->key()->context());
- Visit(prop->key());
+ VisitForValue(prop->obj(), kStack);
+ VisitForValue(prop->key(), kStack);
if (decl->fun() != NULL) {
- ASSERT_EQ(Expression::kValue, decl->fun()->context());
- Visit(decl->fun());
- __ pop(rax);
+ VisitForValue(decl->fun(), kAccumulator);
} else {
- __ LoadRoot(rax, Heap::kTheHoleValueRootIndex);
+ __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex);
}
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
-
// Absence of a test rax instruction following the call
// indicates that none of the load was inlined.
+ __ nop();
// Value in rax is ignored (declarations are statements). Receiver
// and key on stack are discarded.
@@ -532,7 +789,7 @@
void FastCodeGenerator::EmitVariableLoad(Variable* var,
- Expression::Context context) {
+ Expression::Context context) {
Expression* rewrite = var->rewrite();
if (rewrite == NULL) {
ASSERT(var->is_global());
@@ -547,14 +804,13 @@
// indicate that the inobject property case was inlined. Ensure there
// is no test rax instruction here.
__ nop();
-
DropAndApply(1, context, rax);
} else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
if (FLAG_debug_code) {
switch (slot->type()) {
- case Slot::LOCAL:
- case Slot::PARAMETER: {
+ case Slot::PARAMETER:
+ case Slot::LOCAL: {
Comment cmnt(masm_, "Stack slot");
break;
}
@@ -567,7 +823,7 @@
break;
}
}
- Apply(context, slot, rax);
+ Apply(context, slot);
} else {
Comment cmnt(masm_, "Variable rewritten to property");
// A variable has been rewritten into an explicit access to an object
@@ -579,9 +835,9 @@
// "slot[literal]".
// Assert that the object is in a slot.
- Variable* object = property->obj()->AsVariableProxy()->AsVariable();
- ASSERT_NOT_NULL(object);
- Slot* object_slot = object->slot();
+ Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
+ ASSERT_NOT_NULL(object_var);
+ Slot* object_slot = object_var->slot();
ASSERT_NOT_NULL(object_slot);
// Load the object.
@@ -601,7 +857,7 @@
__ 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.
-
+ __ nop();
// Drop key and object left on the stack by IC, and push the result.
DropAndApply(2, context, rax);
}
@@ -629,7 +885,6 @@
__ Push(expr->pattern());
__ Push(expr->flags());
__ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
- // Label done:
__ bind(&done);
Apply(expr->context(), rax);
}
@@ -647,9 +902,8 @@
__ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
}
- // If result_saved == true: The result is saved on top of the
- // stack and in rax.
- // If result_saved == false: The result not on the stack, just in rax.
+ // If result_saved is true the result is on top of the stack. If
+ // result_saved is false the result is in rax.
bool result_saved = false;
for (int i = 0; i < expr->properties()->length(); i++) {
@@ -663,77 +917,45 @@
result_saved = true;
}
switch (property->kind()) {
+ case ObjectLiteral::Property::CONSTANT:
+ UNREACHABLE();
case ObjectLiteral::Property::MATERIALIZED_LITERAL:
ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
+ // Fall through.
case ObjectLiteral::Property::COMPUTED:
if (key->handle()->IsSymbol()) {
- Visit(value);
- ASSERT_EQ(Expression::kValue, value->context());
- __ pop(rax);
+ VisitForValue(value, kAccumulator);
__ Move(rcx, key->handle());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
+ __ nop();
// StoreIC leaves the receiver on the stack.
- __ movq(rax, Operand(rsp, 0)); // Restore result back into rax.
break;
}
// Fall through.
case ObjectLiteral::Property::PROTOTYPE:
- __ push(rax);
- Visit(key);
- ASSERT_EQ(Expression::kValue, key->context());
- Visit(value);
- ASSERT_EQ(Expression::kValue, value->context());
+ __ push(Operand(rsp, 0)); // Duplicate receiver.
+ VisitForValue(key, kStack);
+ VisitForValue(value, kStack);
__ CallRuntime(Runtime::kSetProperty, 3);
- __ movq(rax, Operand(rsp, 0)); // Restore result into rax.
break;
case ObjectLiteral::Property::SETTER:
case ObjectLiteral::Property::GETTER:
- __ push(rax);
- Visit(key);
- ASSERT_EQ(Expression::kValue, key->context());
+ __ push(Operand(rsp, 0)); // Duplicate receiver.
+ VisitForValue(key, kStack);
__ Push(property->kind() == ObjectLiteral::Property::SETTER ?
Smi::FromInt(1) :
Smi::FromInt(0));
- Visit(value);
- ASSERT_EQ(Expression::kValue, value->context());
+ VisitForValue(value, kStack);
__ CallRuntime(Runtime::kDefineAccessor, 4);
- __ movq(rax, Operand(rsp, 0)); // Restore result into rax.
break;
- default: UNREACHABLE();
}
}
- switch (expr->context()) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- if (result_saved) __ Drop(1);
- break;
- case Expression::kValue:
- if (!result_saved) __ push(rax);
- break;
- case Expression::kTest:
- if (result_saved) __ pop(rax);
- TestAndBranch(rax, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- if (!result_saved) __ push(rax);
- TestAndBranch(rax, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- if (!result_saved) __ push(rax);
- TestAndBranch(rax, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- break;
- }
+
+ if (result_saved) {
+ ApplyTOS(expr->context());
+ } else {
+ Apply(expr->context(), rax);
}
}
@@ -768,77 +990,47 @@
__ push(rax);
result_saved = true;
}
- Visit(subexpr);
- ASSERT_EQ(Expression::kValue, subexpr->context());
+ VisitForValue(subexpr, kAccumulator);
// Store the subexpression value in the array's elements.
- __ pop(rax); // Subexpression value.
__ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
__ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
- __ movq(FieldOperand(rbx, offset), rax);
+ __ movq(FieldOperand(rbx, offset), result_register());
// Update the write barrier for the array store.
- __ RecordWrite(rbx, offset, rax, rcx);
+ __ RecordWrite(rbx, offset, result_register(), rcx);
}
- switch (expr->context()) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- if (result_saved) __ Drop(1);
- break;
- case Expression::kValue:
- if (!result_saved) __ push(rax);
- break;
- case Expression::kTest:
- if (result_saved) __ pop(rax);
- TestAndBranch(rax, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- if (!result_saved) __ push(rax);
- TestAndBranch(rax, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- if (!result_saved) __ push(rax);
- TestAndBranch(rax, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- break;
- }
+ if (result_saved) {
+ ApplyTOS(expr->context());
+ } else {
+ Apply(expr->context(), rax);
}
}
-void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
- Expression::Context context) {
+void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position());
Literal* key = prop->key()->AsLiteral();
__ Move(rcx, key->handle());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
- Apply(context, rax);
+ __ nop();
}
-void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop,
- Expression::Context context) {
+void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
- Apply(context, rax);
+ __ nop();
}
-void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
- Expression::Context context) {
+void FastCodeGenerator::EmitBinaryOp(Token::Value op,
+ Expression::Context context) {
+ __ push(result_register());
GenericBinaryOpStub stub(op,
NO_OVERWRITE,
NO_GENERIC_BINARY_FLAGS);
@@ -855,7 +1047,6 @@
// 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 on the stack.
- __ pop(rax);
__ Move(rcx, var->name());
__ push(CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
@@ -867,66 +1058,18 @@
Slot* slot = var->slot();
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(target);
- break;
- case Expression::kValue:
- // Perform assignment and preserve value.
- __ movq(rax, Operand(rsp, 0));
- __ movq(target, rax);
- break;
- case Expression::kTest:
- // Perform assignment and test (and discard) value.
- __ pop(rax);
- __ movq(target, rax);
- TestAndBranch(rax, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- __ movq(rax, Operand(rsp, 0));
- __ movq(target, rax);
- TestAndBranch(rax, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- __ movq(rax, Operand(rsp, 0));
- __ movq(target, rax);
- TestAndBranch(rax, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- break;
- }
- }
+ case Slot::PARAMETER:
+ __ movq(Operand(rbp, SlotOffset(slot)), result_register());
break;
- }
case Slot::CONTEXT: {
MemOperand target = EmitSlotSearch(slot, rcx);
- __ pop(rax);
- __ movq(target, rax);
+ __ movq(target, result_register());
// RecordWrite may destroy all its register arguments.
- if (context == Expression::kValue) {
- __ push(rax);
- } else if (context != Expression::kEffect) {
- __ movq(rdx, rax);
- }
+ __ movq(rdx, result_register());
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
- __ RecordWrite(rcx, offset, rax, rbx);
- if (context != Expression::kEffect && context != Expression::kValue) {
- Apply(context, rdx);
- }
+ __ RecordWrite(rcx, offset, rdx, rbx);
break;
}
@@ -934,6 +1077,7 @@
UNREACHABLE();
break;
}
+ Apply(context, result_register());
} else {
// Variables rewritten as properties are not treated as variables in
// assignments.
@@ -952,14 +1096,18 @@
// change to slow case to avoid the quadratic behavior of repeatedly
// adding fast properties.
if (expr->starts_initialization_block()) {
- __ push(Operand(rsp, kPointerSize)); // Receiver is under value.
+ __ push(result_register());
+ __ push(Operand(rsp, kPointerSize)); // Receiver is now under value.
__ CallRuntime(Runtime::kToSlowProperties, 1);
+ __ pop(result_register());
}
- __ pop(rax);
+ // Record source code position before IC call.
+ SetSourcePosition(expr->position());
__ Move(rcx, prop->key()->AsLiteral()->handle());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
+ __ nop();
// If the assignment ends an initialization block, revert to fast case.
if (expr->ends_initialization_block()) {
@@ -980,12 +1128,15 @@
// change to slow case to avoid the quadratic behavior of repeatedly
// adding fast properties.
if (expr->starts_initialization_block()) {
- // Reciever is under the key and value.
+ __ push(result_register());
+ // Receiver is now under the key and value.
__ push(Operand(rsp, 2 * kPointerSize));
__ CallRuntime(Runtime::kToSlowProperties, 1);
+ __ pop(result_register());
}
- __ pop(rax);
+ // Record source code position before IC call.
+ SetSourcePosition(expr->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// This nop signals to the IC that there is no inlined code at the call
@@ -995,7 +1146,7 @@
// If the assignment ends an initialization block, revert to fast case.
if (expr->ends_initialization_block()) {
__ push(rax); // Result of assignment, saved even if not needed.
- // Reciever is under the key and value.
+ // Receiver is under the key and value.
__ push(Operand(rsp, 2 * kPointerSize));
__ CallRuntime(Runtime::kToFastProperties, 1);
__ pop(rax);
@@ -1010,30 +1161,16 @@
Comment cmnt(masm_, "[ Property");
Expression* key = expr->key();
- // Record the source position for the property load.
- SetSourcePosition(expr->position());
-
// Evaluate receiver.
- Visit(expr->obj());
+ VisitForValue(expr->obj(), kStack);
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();
+ EmitNamedPropertyLoad(expr);
+ // Drop receiver left on the stack by IC.
DropAndApply(1, expr->context(), rax);
} else {
- // 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.
- __ nop();
+ VisitForValue(expr->key(), kStack);
+ EmitKeyedPropertyLoad(expr);
// Drop key and receiver left on the stack by IC.
DropAndApply(2, expr->context(), rax);
}
@@ -1047,15 +1184,15 @@
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
- Visit(args->at(i));
- ASSERT_EQ(Expression::kValue, args->at(i)->context());
+ VisitForValue(args->at(i), kStack);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
+ InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
- NOT_IN_LOOP);
- __ call(ic, mode);
+ in_loop);
+ __ Call(ic, mode);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Discard the function left on TOS.
@@ -1068,7 +1205,7 @@
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
- Visit(args->at(i));
+ VisitForValue(args->at(i), kStack);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
@@ -1106,13 +1243,13 @@
if (key != NULL && key->handle()->IsSymbol()) {
// Call to a named property, use call IC.
__ Push(key->handle());
- Visit(prop->obj());
+ VisitForValue(prop->obj(), kStack);
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else {
// Call to a keyed property, use keyed load IC followed by function
// call.
- Visit(prop->obj());
- Visit(prop->key());
+ VisitForValue(prop->obj(), kStack);
+ VisitForValue(prop->key(), kStack);
// Record source code position for IC call.
SetSourcePosition(prop->position());
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
@@ -1145,7 +1282,7 @@
loop_depth() == 0) {
lit->set_try_fast_codegen(true);
}
- Visit(fun);
+ VisitForValue(fun, kStack);
// Load global receiver object.
__ movq(rbx, CodeGenerator::GlobalObject());
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
@@ -1161,9 +1298,7 @@
// expression in new calls must be evaluated before the
// arguments.
// Push function on the stack.
- Visit(expr->expression());
- ASSERT_EQ(Expression::kValue, expr->expression()->context());
- // If location is value, already on the stack,
+ VisitForValue(expr->expression(), kStack);
// Push global object (receiver).
__ push(CodeGenerator::GlobalObject());
@@ -1172,10 +1307,7 @@
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
- Visit(args->at(i));
- ASSERT_EQ(Expression::kValue, args->at(i)->context());
- // If location is value, it is already on the stack,
- // so nothing to do here.
+ VisitForValue(args->at(i), kStack);
}
// Call the construct call builtin that handles allocation and
@@ -1209,8 +1341,7 @@
// Push the arguments ("left-to-right").
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
- Visit(args->at(i));
- ASSERT_EQ(Expression::kValue, args->at(i)->context());
+ VisitForValue(args->at(i), kStack);
}
if (expr->is_jsruntime()) {
@@ -1233,8 +1364,8 @@
switch (expr->op()) {
case Token::VOID: {
Comment cmnt(masm_, "[ UnaryOperation (VOID)");
+ ASSERT_EQ(Expression::kEffect, expr->expression()->context());
Visit(expr->expression());
- ASSERT_EQ(Expression::kEffect, expr->expression()->context());
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
@@ -1242,11 +1373,25 @@
case Expression::kEffect:
break;
case Expression::kValue:
- __ PushRoot(Heap::kUndefinedValueRootIndex);
+ switch (location_) {
+ case kAccumulator:
+ __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
+ break;
+ case kStack:
+ __ PushRoot(Heap::kUndefinedValueRootIndex);
+ break;
+ }
break;
case Expression::kTestValue:
// Value is false so it's needed.
- __ PushRoot(Heap::kUndefinedValueRootIndex);
+ switch (location_) {
+ case kAccumulator:
+ __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
+ break;
+ case kStack:
+ __ PushRoot(Heap::kUndefinedValueRootIndex);
+ break;
+ }
// Fall through.
case Expression::kTest:
case Expression::kValueTest:
@@ -1260,45 +1405,34 @@
Comment cmnt(masm_, "[ UnaryOperation (NOT)");
ASSERT_EQ(Expression::kTest, expr->expression()->context());
- Label push_true, push_false, done;
+ Label materialize_true, materialize_false, done;
+ // Initially assume a pure test context. Notice that the labels are
+ // swapped.
+ Label* if_true = false_label_;
+ Label* if_false = true_label_;
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
break;
-
+ case Expression::kEffect:
+ if_true = &done;
+ if_false = &done;
+ break;
case Expression::kValue:
- VisitForControl(expr->expression(), &push_false, &push_true);
- __ bind(&push_true);
- __ PushRoot(Heap::kTrueValueRootIndex);
- __ jmp(&done);
- __ bind(&push_false);
- __ PushRoot(Heap::kFalseValueRootIndex);
- __ bind(&done);
+ if_true = &materialize_false;
+ if_false = &materialize_true;
break;
-
- case Expression::kEffect:
- VisitForControl(expr->expression(), &done, &done);
- __ bind(&done);
- break;
-
case Expression::kTest:
- VisitForControl(expr->expression(), false_label_, true_label_);
break;
-
case Expression::kValueTest:
- VisitForControl(expr->expression(), false_label_, &push_true);
- __ bind(&push_true);
- __ PushRoot(Heap::kTrueValueRootIndex);
- __ jmp(true_label_);
+ if_false = &materialize_true;
break;
-
case Expression::kTestValue:
- VisitForControl(expr->expression(), &push_false, true_label_);
- __ bind(&push_false);
- __ PushRoot(Heap::kFalseValueRootIndex);
- __ jmp(false_label_);
+ if_true = &materialize_false;
break;
}
+ VisitForControl(expr->expression(), if_true, if_false);
+ Apply(expr->context(), if_false, if_true); // Labels swapped.
break;
}
@@ -1327,7 +1461,7 @@
__ push(rax);
} else {
// This expression cannot throw a reference error at the top level.
- Visit(expr->expression());
+ VisitForValue(expr->expression(), kStack);
}
__ CallRuntime(Runtime::kTypeof, 1);
@@ -1360,23 +1494,25 @@
// Evaluate expression and get value.
if (assign_type == VARIABLE) {
ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
+ Location saved_location = location_;
+ location_ = kStack;
EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
Expression::kValue);
+ location_ = saved_location;
} else {
// Reserve space for result of postfix operation.
if (expr->is_postfix() && expr->context() != Expression::kEffect) {
ASSERT(expr->context() != Expression::kUninitialized);
__ Push(Smi::FromInt(0));
}
- Visit(prop->obj());
- ASSERT_EQ(Expression::kValue, prop->obj()->context());
+ VisitForValue(prop->obj(), kStack);
if (assign_type == NAMED_PROPERTY) {
- EmitNamedPropertyLoad(prop, Expression::kValue);
+ EmitNamedPropertyLoad(prop);
} else {
- Visit(prop->key());
- ASSERT_EQ(Expression::kValue, prop->key()->context());
- EmitKeyedPropertyLoad(prop, Expression::kValue);
+ VisitForValue(prop->key(), kStack);
+ EmitKeyedPropertyLoad(prop);
}
+ __ push(rax);
}
// Convert to number.
@@ -1390,10 +1526,10 @@
case Expression::kEffect:
// Do not save result.
break;
- case Expression::kValue: // Fall through
- case Expression::kTest: // Fall through
- case Expression::kTestValue: // Fall through
+ case Expression::kValue:
+ case Expression::kTest:
case Expression::kValueTest:
+ case Expression::kTestValue:
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
@@ -1412,19 +1548,17 @@
}
}
- // Call runtime for +1/-1.
+ // Call stub for +1/-1.
__ push(rax);
__ Push(Smi::FromInt(1));
- if (expr->op() == Token::INC) {
- __ CallRuntime(Runtime::kNumberAdd, 2);
- } else {
- __ CallRuntime(Runtime::kNumberSub, 2);
- }
+ GenericBinaryOpStub stub(expr->binary_op(),
+ NO_OVERWRITE,
+ NO_GENERIC_BINARY_FLAGS);
+ __ CallStub(&stub);
// Store the value returned in rax.
switch (assign_type) {
case VARIABLE:
- __ push(rax);
if (expr->is_postfix()) {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Expression::kEffect);
@@ -1499,20 +1633,12 @@
case Token::BIT_XOR:
case Token::SHL:
case Token::SHR:
- case Token::SAR: {
- ASSERT_EQ(Expression::kValue, expr->left()->context());
- ASSERT_EQ(Expression::kValue, expr->right()->context());
+ case Token::SAR:
+ VisitForValue(expr->left(), kStack);
+ VisitForValue(expr->right(), kAccumulator);
+ EmitBinaryOp(expr->op(), expr->context());
+ break;
- Visit(expr->left());
- Visit(expr->right());
- GenericBinaryOpStub stub(expr->op(),
- NO_OVERWRITE,
- NO_GENERIC_BINARY_FLAGS);
- __ CallStub(&stub);
- Apply(expr->context(), rax);
-
- break;
- }
default:
UNREACHABLE();
}
@@ -1521,14 +1647,10 @@
void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Comment cmnt(masm_, "[ CompareOperation");
- ASSERT_EQ(Expression::kValue, expr->left()->context());
- ASSERT_EQ(Expression::kValue, expr->right()->context());
- Visit(expr->left());
- Visit(expr->right());
// Always perform the comparison for its control flow. Pack the result
// into the expression's context after the comparison is performed.
- Label push_true, push_false, done;
+ Label materialize_true, materialize_false, done;
// Initially assume we are in a test context.
Label* if_true = true_label_;
Label* if_false = false_label_;
@@ -1536,34 +1658,36 @@
case Expression::kUninitialized:
UNREACHABLE();
break;
- case Expression::kValue:
- if_true = &push_true;
- if_false = &push_false;
- break;
case Expression::kEffect:
if_true = &done;
if_false = &done;
break;
+ case Expression::kValue:
+ if_true = &materialize_true;
+ if_false = &materialize_false;
+ break;
case Expression::kTest:
break;
case Expression::kValueTest:
- if_true = &push_true;
+ if_true = &materialize_true;
break;
case Expression::kTestValue:
- if_false = &push_false;
+ if_false = &materialize_false;
break;
}
+ VisitForValue(expr->left(), kStack);
switch (expr->op()) {
- case Token::IN: {
+ case Token::IN:
+ VisitForValue(expr->right(), kStack);
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
__ j(equal, if_true);
__ jmp(if_false);
break;
- }
case Token::INSTANCEOF: {
+ VisitForValue(expr->right(), kStack);
InstanceofStub stub;
__ CallStub(&stub);
__ testq(rax, rax);
@@ -1573,6 +1697,7 @@
}
default: {
+ VisitForValue(expr->right(), kAccumulator);
Condition cc = no_condition;
bool strict = false;
switch (expr->op()) {
@@ -1581,29 +1706,26 @@
// Fall through.
case Token::EQ:
cc = equal;
- __ pop(rax);
__ pop(rdx);
break;
case Token::LT:
cc = less;
- __ pop(rax);
__ pop(rdx);
break;
case Token::GT:
// Reverse left and right sizes to obtain ECMA-262 conversion order.
cc = less;
- __ pop(rdx);
+ __ movq(rdx, result_register());
__ pop(rax);
break;
case Token::LTE:
// Reverse left and right sizes to obtain ECMA-262 conversion order.
cc = greater_equal;
- __ pop(rdx);
+ __ movq(rdx, result_register());
__ pop(rax);
break;
case Token::GTE:
cc = greater_equal;
- __ pop(rax);
__ pop(rdx);
break;
case Token::IN:
@@ -1631,39 +1753,7 @@
// Convert the result of the comparison into one expected for this
// expression's context.
- switch (expr->context()) {
- case Expression::kUninitialized:
- UNREACHABLE();
- break;
-
- case Expression::kEffect:
- __ bind(&done);
- break;
-
- case Expression::kValue:
- __ bind(&push_true);
- __ PushRoot(Heap::kTrueValueRootIndex);
- __ jmp(&done);
- __ bind(&push_false);
- __ PushRoot(Heap::kFalseValueRootIndex);
- __ bind(&done);
- break;
-
- case Expression::kTest:
- break;
-
- case Expression::kValueTest:
- __ bind(&push_true);
- __ PushRoot(Heap::kTrueValueRootIndex);
- __ jmp(true_label_);
- break;
-
- case Expression::kTestValue:
- __ bind(&push_false);
- __ PushRoot(Heap::kFalseValueRootIndex);
- __ jmp(false_label_);
- break;
- }
+ Apply(expr->context(), if_true, if_false);
}
« no previous file with comments | « src/x64/codegen-x64.cc ('k') | src/x64/virtual-frame-x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698