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

Unified Diff: src/ia32/fast-codegen-ia32.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/fast-codegen.cc ('k') | src/x64/fast-codegen-x64.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/ia32/fast-codegen-ia32.cc
===================================================================
--- src/ia32/fast-codegen-ia32.cc (revision 3626)
+++ src/ia32/fast-codegen-ia32.cc (working copy)
@@ -29,9 +29,9 @@
#include "codegen-inl.h"
#include "compiler.h"
+#include "debug.h"
#include "fast-codegen.h"
#include "parser.h"
-#include "debug.h"
namespace v8 {
namespace internal {
@@ -116,7 +116,7 @@
__ push(Immediate(Smi::FromInt(fun->num_parameters())));
// Arguments to ArgumentsAccessStub:
// function, receiver address, parameter count.
- // The stub will rewrite receiever and parameter count if the previous
+ // The stub will rewrite receiver and parameter count if the previous
// stack frame was an arguments adapter frame.
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
__ CallStub(&stub);
@@ -193,24 +193,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())) __ mov(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())) __ mov(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:
+ __ mov(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;
}
}
@@ -221,15 +270,30 @@
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
+ // Nothing to do.
break;
case Expression::kValue:
- __ push(Immediate(lit->handle()));
+ switch (location_) {
+ case kAccumulator:
+ __ mov(result_register(), lit->handle());
+ break;
+ case kStack:
+ // Immediates can be pushed directly.
+ __ push(Immediate(lit->handle()));
+ break;
+ }
break;
+
case Expression::kTest:
+ __ mov(result_register(), lit->handle());
+ DoTest(context);
+ break;
+
case Expression::kValueTest:
case Expression::kTestValue:
- __ mov(eax, lit->handle());
- Apply(context, eax);
+ __ mov(result_register(), lit->handle());
+ __ push(result_register());
+ DoTest(context);
break;
}
}
@@ -239,32 +303,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(eax);
- TestAndBranch(eax, true_label_, false_label_);
+ __ pop(result_register());
+ DoTest(context);
break;
- case Expression::kValueTest: {
- Label discard;
- __ mov(eax, Operand(esp, 0));
- TestAndBranch(eax, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
+
+ case Expression::kValueTest:
+ case Expression::kTestValue:
+ __ mov(result_register(), Operand(esp, 0));
+ DoTest(context);
break;
- }
- case Expression::kTestValue: {
- Label discard;
- __ mov(eax, Operand(esp, 0));
- TestAndBranch(eax, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- }
}
}
@@ -277,37 +340,181 @@
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
+
case Expression::kEffect:
__ Drop(count);
break;
+
case Expression::kValue:
- if (count > 1) __ Drop(count - 1);
- __ mov(Operand(esp, 0), reg);
+ switch (location_) {
+ case kAccumulator:
+ __ Drop(count);
+ if (!reg.is(result_register())) __ mov(result_register(), reg);
+ break;
+ case kStack:
+ if (count > 1) __ Drop(count - 1);
+ __ mov(Operand(esp, 0), reg);
+ break;
+ }
break;
+
case Expression::kTest:
__ Drop(count);
- TestAndBranch(reg, true_label_, false_label_);
+ if (!reg.is(result_register())) __ mov(result_register(), reg);
+ DoTest(context);
break;
- case Expression::kValueTest: {
- Label discard;
+
+ case Expression::kValueTest:
+ case Expression::kTestValue:
if (count > 1) __ Drop(count - 1);
- __ mov(Operand(esp, 0), reg);
- TestAndBranch(reg, true_label_, &discard);
+ if (!reg.is(result_register())) __ mov(result_register(), reg);
+ __ mov(Operand(esp, 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);
+ __ mov(result_register(), Factory::true_value());
+ __ jmp(&done);
+ __ bind(materialize_false);
+ __ mov(result_register(), Factory::false_value());
+ break;
+ case kStack:
+ __ bind(materialize_true);
+ __ push(Immediate(Factory::true_value()));
+ __ jmp(&done);
+ __ bind(materialize_false);
+ __ push(Immediate(Factory::false_value()));
+ break;
+ }
+ __ bind(&done);
+ break;
+ }
+
+ case Expression::kTest:
+ break;
+
+ case Expression::kValueTest:
+ __ bind(materialize_true);
+ switch (location_) {
+ case kAccumulator:
+ __ mov(result_register(), Factory::true_value());
+ break;
+ case kStack:
+ __ push(Immediate(Factory::true_value()));
+ break;
+ }
+ __ jmp(true_label_);
+ break;
+
+ case Expression::kTestValue:
+ __ bind(materialize_false);
+ switch (location_) {
+ case kAccumulator:
+ __ mov(result_register(), Factory::false_value());
+ break;
+ case kStack:
+ __ push(Immediate(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.
+ __ cmp(result_register(), Factory::undefined_value());
+ __ j(equal, if_false);
+ __ cmp(result_register(), Factory::true_value());
+ __ j(equal, if_true);
+ __ cmp(result_register(), Factory::false_value());
+ __ j(equal, if_false);
+ ASSERT_EQ(0, kSmiTag);
+ __ test(result_register(), Operand(result_register()));
+ __ j(zero, if_false);
+ __ test(result_register(), Immediate(kSmiTagMask));
+ __ j(zero, if_true);
+
+ // Call the ToBoolean stub for all other cases.
+ ToBooleanStub stub;
+ __ push(result_register());
+ __ CallStub(&stub);
+ __ test(eax, Operand(eax));
+
+ // 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);
- __ mov(Operand(esp, 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;
- }
}
}
@@ -353,36 +560,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.
- __ cmp(source, Factory::undefined_value()); // The undefined value is false.
- __ j(equal, false_label);
- __ cmp(source, Factory::true_value()); // True is true.
- __ j(equal, true_label);
- __ cmp(source, Factory::false_value()); // False is false.
- __ j(equal, false_label);
- ASSERT_EQ(0, kSmiTag);
- __ test(source, Operand(source)); // The smi zero is false.
- __ j(zero, false_label);
- __ test(source, Immediate(kSmiTagMask)); // All other smis are true.
- __ j(zero, true_label);
-
- // Call the stub for all other cases.
- __ push(source);
- ToBooleanStub stub;
- __ CallStub(&stub);
- __ test(eax, Operand(eax)); // 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();
@@ -398,8 +575,8 @@
__ mov(Operand(ebp, SlotOffset(slot)),
Immediate(Factory::the_hole_value()));
} else if (decl->fun() != NULL) {
- Visit(decl->fun());
- __ pop(Operand(ebp, SlotOffset(slot)));
+ VisitForValue(decl->fun(), kAccumulator);
+ __ mov(Operand(ebp, SlotOffset(slot)), result_register());
}
break;
@@ -421,11 +598,11 @@
__ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
// No write barrier since the hole value is in old space.
} else if (decl->fun() != NULL) {
- Visit(decl->fun());
- __ pop(eax);
- __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
+ VisitForValue(decl->fun(), kAccumulator);
+ __ mov(CodeGenerator::ContextOperand(esi, slot->index()),
+ result_register());
int offset = Context::SlotOffset(slot->index());
- __ RecordWrite(esi, offset, eax, ecx);
+ __ RecordWrite(esi, offset, result_register(), ecx);
}
break;
@@ -445,7 +622,7 @@
if (decl->mode() == Variable::CONST) {
__ push(Immediate(Factory::the_hole_value()));
} else if (decl->fun() != NULL) {
- Visit(decl->fun());
+ VisitForValue(decl->fun(), kStack);
} else {
__ push(Immediate(Smi::FromInt(0))); // No initial value!
}
@@ -458,23 +635,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(eax);
+ VisitForValue(decl->fun(), kAccumulator);
} else {
- __ Set(eax, Immediate(Factory::the_hole_value()));
+ __ mov(result_register(), Factory::the_hole_value());
}
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
// Absence of a test eax instruction following the call
// indicates that none of the load was inlined.
+ __ nop();
// Value in eax is ignored (declarations are statements). Receiver
// and key on stack are discarded.
@@ -554,7 +728,7 @@
break;
}
}
- Apply(context, slot, eax);
+ Apply(context, slot);
} else {
Comment cmnt(masm_, "Variable rewritten to property");
// A variable has been rewritten into an explicit access to an object
@@ -634,9 +808,8 @@
__ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
}
- // If result_saved == true: The result is saved on top of the
- // stack and in eax.
- // If result_saved == false: The result not on the stack, just in eax.
+ // If result_saved is true the result is on top of the stack. If
+ // result_saved is false the result is in eax.
bool result_saved = false;
for (int i = 0; i < expr->properties()->length(); i++) {
@@ -650,77 +823,44 @@
result_saved = true;
}
switch (property->kind()) {
- case ObjectLiteral::Property::MATERIALIZED_LITERAL: // Fall through.
+ 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(eax);
+ VisitForValue(value, kAccumulator);
__ mov(ecx, Immediate(key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
+ __ nop();
// StoreIC leaves the receiver on the stack.
- __ mov(eax, Operand(esp, 0)); // Restore result into eax.
break;
}
// Fall through.
case ObjectLiteral::Property::PROTOTYPE:
- __ push(eax);
- Visit(key);
- ASSERT_EQ(Expression::kValue, key->context());
- Visit(value);
- ASSERT_EQ(Expression::kValue, value->context());
+ __ push(Operand(esp, 0)); // Duplicate receiver.
+ VisitForValue(key, kStack);
+ VisitForValue(value, kStack);
__ CallRuntime(Runtime::kSetProperty, 3);
- __ mov(eax, Operand(esp, 0)); // Restore result into eax.
break;
case ObjectLiteral::Property::SETTER:
case ObjectLiteral::Property::GETTER:
- __ push(eax);
- Visit(key);
- ASSERT_EQ(Expression::kValue, key->context());
+ __ push(Operand(esp, 0)); // Duplicate receiver.
+ VisitForValue(key, kStack);
__ push(Immediate(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);
- __ mov(eax, Operand(esp, 0)); // Restore result into eax.
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(eax);
- break;
- case Expression::kTest:
- if (result_saved) __ pop(eax);
- TestAndBranch(eax, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- if (!result_saved) __ push(eax);
- TestAndBranch(eax, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- if (!result_saved) __ push(eax);
- TestAndBranch(eax, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- break;
- }
+
+ if (result_saved) {
+ ApplyTOS(expr->context());
+ } else {
+ Apply(expr->context(), eax);
}
}
@@ -755,51 +895,22 @@
__ push(eax);
result_saved = true;
}
- Visit(subexpr);
- ASSERT_EQ(Expression::kValue, subexpr->context());
+ VisitForValue(subexpr, kAccumulator);
// Store the subexpression value in the array's elements.
- __ pop(eax); // Subexpression value.
__ mov(ebx, Operand(esp, 0)); // Copy of array literal.
__ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
- __ mov(FieldOperand(ebx, offset), eax);
+ __ mov(FieldOperand(ebx, offset), result_register());
// Update the write barrier for the array store.
- __ RecordWrite(ebx, offset, eax, ecx);
+ __ RecordWrite(ebx, offset, result_register(), ecx);
}
- switch (expr->context()) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- if (result_saved) __ Drop(1);
- break;
- case Expression::kValue:
- if (!result_saved) __ push(eax);
- break;
- case Expression::kTest:
- if (result_saved) __ pop(eax);
- TestAndBranch(eax, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- if (!result_saved) __ push(eax);
- TestAndBranch(eax, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- if (!result_saved) __ push(eax);
- TestAndBranch(eax, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- break;
- }
+ if (result_saved) {
+ ApplyTOS(expr->context());
+ } else {
+ Apply(expr->context(), eax);
}
}
@@ -822,8 +933,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);
@@ -840,7 +952,6 @@
// Assignment to a global variable. Use inline caching for the
// assignment. Right-hand-side value is passed in eax, variable name in
// ecx, and the global object on the stack.
- __ pop(eax);
__ mov(ecx, var->name());
__ push(CodeGenerator::GlobalObject());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
@@ -853,66 +964,18 @@
Slot* slot = var->slot();
switch (slot->type()) {
case Slot::LOCAL:
- case Slot::PARAMETER: {
- Operand target = Operand(ebp, 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.
- __ mov(eax, Operand(esp, 0));
- __ mov(target, eax);
- break;
- case Expression::kTest:
- // Perform assignment and test (and discard) value.
- __ pop(eax);
- __ mov(target, eax);
- TestAndBranch(eax, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- __ mov(eax, Operand(esp, 0));
- __ mov(target, eax);
- TestAndBranch(eax, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- __ mov(eax, Operand(esp, 0));
- __ mov(target, eax);
- TestAndBranch(eax, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- break;
- }
- }
+ case Slot::PARAMETER:
+ __ mov(Operand(ebp, SlotOffset(slot)), result_register());
break;
- }
case Slot::CONTEXT: {
MemOperand target = EmitSlotSearch(slot, ecx);
- __ pop(eax);
- __ mov(target, eax);
+ __ mov(target, result_register());
// RecordWrite may destroy all its register arguments.
- if (context == Expression::kValue) {
- __ push(eax);
- } else if (context != Expression::kEffect) {
- __ mov(edx, eax);
- }
+ __ mov(edx, result_register());
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
- __ RecordWrite(ecx, offset, eax, ebx);
- if (context != Expression::kEffect && context != Expression::kValue) {
- Apply(context, edx);
- }
+ __ RecordWrite(ecx, offset, edx, ebx);
break;
}
@@ -920,6 +983,8 @@
UNREACHABLE();
break;
}
+ Apply(context, result_register());
+
} else {
// Variables rewritten as properties are not treated as variables in
// assignments.
@@ -938,17 +1003,18 @@
// change to slow case to avoid the quadratic behavior of repeatedly
// adding fast properties.
if (expr->starts_initialization_block()) {
- __ push(Operand(esp, kPointerSize)); // Receiver is under value.
+ __ push(result_register());
+ __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
__ CallRuntime(Runtime::kToSlowProperties, 1);
+ __ pop(result_register());
}
// Record source code position before IC call.
SetSourcePosition(expr->position());
-
- __ pop(eax);
__ mov(ecx, 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()) {
@@ -969,15 +1035,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(esp, 2 * kPointerSize));
__ CallRuntime(Runtime::kToSlowProperties, 1);
+ __ pop(result_register());
}
// Record source code position before IC call.
SetSourcePosition(expr->position());
-
- __ pop(eax);
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
@@ -987,7 +1053,7 @@
// If the assignment ends an initialization block, revert to fast case.
if (expr->ends_initialization_block()) {
__ push(eax); // Result of assignment, saved even if not needed.
- // Reciever is under the key and value.
+ // Receiver is under the key and value.
__ push(Operand(esp, 2 * kPointerSize));
__ CallRuntime(Runtime::kToFastProperties, 1);
__ pop(eax);
@@ -1003,14 +1069,14 @@
Expression* key = expr->key();
// Evaluate the 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(), eax);
} else {
- Visit(expr->key());
+ VisitForValue(expr->key(), kStack);
EmitKeyedPropertyLoad(expr);
// Drop key and receiver left on the stack by IC.
DropAndApply(2, expr->context(), eax);
@@ -1025,8 +1091,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);
}
__ Set(ecx, Immediate(name));
// Record source position of the IC call.
@@ -1045,7 +1110,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());
@@ -1079,13 +1144,13 @@
Literal* key = prop->key()->AsLiteral();
if (key != NULL && key->handle()->IsSymbol()) {
// Call to a named property, use call IC.
- 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));
@@ -1118,7 +1183,7 @@
loop_depth() == 0) {
lit->set_try_fast_codegen(true);
}
- Visit(fun);
+ VisitForValue(fun, kStack);
// Load global receiver object.
__ mov(ebx, CodeGenerator::GlobalObject());
__ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
@@ -1134,8 +1199,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());
+ VisitForValue(expr->expression(), kStack);
// Push global object (receiver).
__ push(CodeGenerator::GlobalObject());
@@ -1144,10 +1208,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
@@ -1180,8 +1241,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()) {
@@ -1204,8 +1264,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();
@@ -1213,11 +1273,25 @@
case Expression::kEffect:
break;
case Expression::kValue:
- __ push(Immediate(Factory::undefined_value()));
+ switch (location_) {
+ case kAccumulator:
+ __ mov(result_register(), Factory::undefined_value());
+ break;
+ case kStack:
+ __ push(Immediate(Factory::undefined_value()));
+ break;
+ }
break;
case Expression::kTestValue:
// Value is false so it's needed.
- __ push(Immediate(Factory::undefined_value()));
+ switch (location_) {
+ case kAccumulator:
+ __ mov(result_register(), Factory::undefined_value());
+ break;
+ case kStack:
+ __ push(Immediate(Factory::undefined_value()));
+ break;
+ }
// Fall through.
case Expression::kTest:
case Expression::kValueTest:
@@ -1231,45 +1305,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:
- VisitForControl(expr->expression(), &done, &done);
- __ bind(&done);
+ if_true = &done;
+ if_false = &done;
break;
-
case Expression::kValue:
- VisitForControl(expr->expression(), &push_false, &push_true);
- __ bind(&push_true);
- __ push(Immediate(Factory::true_value()));
- __ jmp(&done);
- __ bind(&push_false);
- __ push(Immediate(Factory::false_value()));
- __ bind(&done);
+ if_true = &materialize_false;
+ if_false = &materialize_true;
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);
- __ push(Immediate(Factory::true_value()));
- __ jmp(true_label_);
+ if_false = &materialize_true;
break;
-
case Expression::kTestValue:
- VisitForControl(expr->expression(), &push_false, true_label_);
- __ bind(&push_false);
- __ push(Immediate(Factory::false_value()));
- __ 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;
}
@@ -1298,7 +1361,7 @@
__ push(eax);
} else {
// This expression cannot throw a reference error at the top level.
- Visit(expr->expression());
+ VisitForValue(expr->expression(), kStack);
}
__ CallRuntime(Runtime::kTypeof, 1);
@@ -1331,21 +1394,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(Immediate(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(eax);
@@ -1364,8 +1428,8 @@
break;
case Expression::kValue:
case Expression::kTest:
+ case Expression::kValueTest:
case Expression::kTestValue:
- case Expression::kValueTest:
// 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.
@@ -1395,7 +1459,6 @@
// Store the value returned in eax.
switch (assign_type) {
case VARIABLE:
- __ push(eax);
if (expr->is_postfix()) {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Expression::kEffect);
@@ -1471,20 +1534,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(), eax);
-
- break;
- }
default:
UNREACHABLE();
}
@@ -1493,14 +1548,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_;
@@ -1513,29 +1564,31 @@
if_false = &done;
break;
case Expression::kValue:
- if_true = &push_true;
- if_false = &push_false;
+ 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);
__ cmp(eax, Factory::true_value());
__ j(equal, if_true);
__ jmp(if_false);
break;
- }
case Token::INSTANCEOF: {
+ VisitForValue(expr->right(), kStack);
InstanceofStub stub;
__ CallStub(&stub);
__ test(eax, Operand(eax));
@@ -1545,6 +1598,7 @@
}
default: {
+ VisitForValue(expr->right(), kAccumulator);
Condition cc = no_condition;
bool strict = false;
switch (expr->op()) {
@@ -1553,29 +1607,26 @@
// Fall through
case Token::EQ:
cc = equal;
- __ pop(eax);
__ pop(edx);
break;
case Token::LT:
cc = less;
- __ pop(eax);
__ pop(edx);
break;
case Token::GT:
// Reverse left and right sizes to obtain ECMA-262 conversion order.
cc = less;
- __ pop(edx);
+ __ mov(edx, result_register());
__ pop(eax);
break;
case Token::LTE:
// Reverse left and right sizes to obtain ECMA-262 conversion order.
cc = greater_equal;
- __ pop(edx);
+ __ mov(edx, result_register());
__ pop(eax);
break;
case Token::GTE:
cc = greater_equal;
- __ pop(eax);
__ pop(edx);
break;
case Token::IN:
@@ -1606,39 +1657,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);
- __ push(Immediate(Factory::true_value()));
- __ jmp(&done);
- __ bind(&push_false);
- __ push(Immediate(Factory::false_value()));
- __ bind(&done);
- break;
-
- case Expression::kTest:
- break;
-
- case Expression::kValueTest:
- __ bind(&push_true);
- __ push(Immediate(Factory::true_value()));
- __ jmp(true_label_);
- break;
-
- case Expression::kTestValue:
- __ bind(&push_false);
- __ push(Immediate(Factory::false_value()));
- __ jmp(false_label_);
- break;
- }
+ Apply(expr->context(), if_true, if_false);
}
« no previous file with comments | « src/fast-codegen.cc ('k') | src/x64/fast-codegen-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698