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

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

Issue 541047: Introduce 'top-of-stack caching' to the toplevel code generator by... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
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/ia32/fast-codegen-ia32.cc ('k') | test/mjsunit/compiler/short-circuit.js » ('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 3626)
+++ 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);
@@ -202,24 +200,73 @@
}
-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::kValueTest:
+ case Expression::kTestValue:
+ // Push an extra copy of the value in case it's needed.
+ __ push(reg);
+ // Fall through.
+
+ case Expression::kTest:
+ // For simplicity we always test the accumulator register.
+ if (!reg.is(result_register())) __ movq(result_register(), reg);
+ 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);
+ __ push(result_register());
+ DoTest(context);
break;
}
}
@@ -230,15 +277,29 @@
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());
+ __ push(result_register());
+ DoTest(context);
break;
}
}
@@ -248,32 +309,31 @@
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:
+ __ movq(result_register(), Operand(rsp, 0));
+ 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 +346,181 @@
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;
+
+ case Expression::kValueTest:
+ case Expression::kTestValue:
if (count > 1) __ Drop(count - 1);
- __ movq(Operand(rsp, 0), reg);
- TestAndBranch(reg, true_label_, &discard);
+ if (!reg.is(result_register())) __ movq(result_register(), reg);
+ __ movq(Operand(rsp, 0), result_register());
+ 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);
+
+ 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, and duplicated on the stack if
+ // necessary (for value/test and test/value contexts).
+ ASSERT_NE(NULL, true_label_);
+ ASSERT_NE(NULL, false_label_);
+
+ // If there is a value on the stack, use a discard label for the
+ // value-is-unneeded branch in the inlined part of the test.
+ Label discard;
+ Label* if_true =
+ (context == Expression::kTestValue) ? &discard : true_label_;
+ Label* if_false =
+ (context == Expression::kValueTest) ? &discard : false_label_;
+
+ // 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);
+
+ // 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 +566,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 +581,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 +605,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 +629,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 +642,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 +700,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 +715,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 +734,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 +746,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 +768,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 +796,6 @@
__ Push(expr->pattern());
__ Push(expr->flags());
__ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
- // Label done:
__ bind(&done);
Apply(expr->context(), rax);
}
@@ -647,9 +813,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 +828,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,51 +901,22 @@
__ 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);
}
}
@@ -835,8 +939,9 @@
}
-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);
@@ -853,7 +958,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));
@@ -865,66 +969,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;
}
@@ -932,6 +988,7 @@
UNREACHABLE();
break;
}
+ Apply(context, result_register());
} else {
// Variables rewritten as properties are not treated as variables in
// assignments.
@@ -950,17 +1007,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());
}
// Record source code position before IC call.
SetSourcePosition(expr->position());
-
- __ pop(rax);
__ 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()) {
@@ -981,15 +1039,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());
}
// Record source code position before IC call.
SetSourcePosition(expr->position());
-
- __ pop(rax);
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
@@ -999,7 +1057,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);
@@ -1015,14 +1073,14 @@
Expression* key = expr->key();
// Evaluate receiver.
- Visit(expr->obj());
+ VisitForValue(expr->obj(), kStack);
if (key->IsPropertyName()) {
EmitNamedPropertyLoad(expr);
// Drop receiver left on the stack by IC.
DropAndApply(1, expr->context(), rax);
} else {
- Visit(expr->key());
+ VisitForValue(expr->key(), kStack);
EmitKeyedPropertyLoad(expr);
// Drop key and receiver left on the stack by IC.
DropAndApply(2, expr->context(), rax);
@@ -1037,8 +1095,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());
+ VisitForValue(args->at(i), kStack);
}
// Record source position for debugger.
SetSourcePosition(expr->position());
@@ -1059,7 +1116,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());
@@ -1097,13 +1154,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));
@@ -1136,7 +1193,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));
@@ -1152,9 +1209,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());
@@ -1163,10 +1218,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
@@ -1200,8 +1252,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()) {
@@ -1224,8 +1275,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();
@@ -1233,11 +1284,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:
@@ -1251,45 +1316,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;
}
@@ -1318,7 +1372,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);
@@ -1351,21 +1405,22 @@
// 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);
} else {
- Visit(prop->key());
- ASSERT_EQ(Expression::kValue, prop->key()->context());
+ VisitForValue(prop->key(), kStack);
EmitKeyedPropertyLoad(prop);
}
__ push(rax);
@@ -1382,10 +1437,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.
@@ -1415,7 +1470,6 @@
// Store the value returned in rax.
switch (assign_type) {
case VARIABLE:
- __ push(rax);
if (expr->is_postfix()) {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Expression::kEffect);
@@ -1490,20 +1544,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();
}
@@ -1512,14 +1558,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_;
@@ -1527,34 +1569,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);
@@ -1564,6 +1608,7 @@
}
default: {
+ VisitForValue(expr->right(), kAccumulator);
Condition cc = no_condition;
bool strict = false;
switch (expr->op()) {
@@ -1572,29 +1617,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:
@@ -1622,39 +1664,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/ia32/fast-codegen-ia32.cc ('k') | test/mjsunit/compiler/short-circuit.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698