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

Unified Diff: src/arm/fast-codegen-arm.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 | « no previous file | src/fast-codegen.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/arm/fast-codegen-arm.cc
===================================================================
--- src/arm/fast-codegen-arm.cc (revision 3626)
+++ src/arm/fast-codegen-arm.cc (working copy)
@@ -214,20 +214,57 @@
}
-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:
+ // We always call the runtime on ARM, so push the value as argument.
+ __ push(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:
+ case Expression::kTest:
case Expression::kValueTest:
case Expression::kTestValue:
- Move(scratch, slot);
- Apply(context, scratch);
+ // On ARM we have to move the value into a register to do anything
+ // with it.
+ Move(result_register(), slot);
+ Apply(context, result_register());
break;
}
}
@@ -239,12 +276,15 @@
UNREACHABLE();
case Expression::kEffect:
break;
+ // Nothing to do.
case Expression::kValue:
case Expression::kTest:
case Expression::kValueTest:
case Expression::kTestValue:
- __ mov(ip, Operand(lit->handle()));
- Apply(context, ip);
+ // On ARM we have to move the value into a register to do anything
+ // with it.
+ __ mov(result_register(), Operand(lit->handle()));
+ Apply(context, result_register());
break;
}
}
@@ -254,32 +294,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::kValueTest:
+ case Expression::kTestValue:
+ // Duplicate the value on the stack in case it's needed.
+ __ ldr(ip, MemOperand(sp));
+ __ push(ip);
+ // Fall through.
+
case Expression::kTest:
- __ pop(r0);
- TestAndBranch(r0, true_label_, false_label_);
+ DoTest(context);
break;
- case Expression::kValueTest: {
- Label discard;
- __ ldr(r0, MemOperand(sp, 0));
- TestAndBranch(r0, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- __ ldr(r0, MemOperand(sp, 0));
- TestAndBranch(r0, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- }
}
}
@@ -292,32 +331,161 @@
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
+
case Expression::kEffect:
__ Drop(count);
break;
+
case Expression::kValue:
+ switch (location_) {
+ case kAccumulator:
+ __ Drop(count);
+ if (!reg.is(result_register())) __ mov(result_register(), reg);
+ break;
+ case kStack:
+ if (count > 1) __ Drop(count - 1);
+ __ str(reg, MemOperand(sp));
+ break;
+ }
+ break;
+
+ case Expression::kTest:
if (count > 1) __ Drop(count - 1);
__ str(reg, MemOperand(sp));
+ DoTest(context);
break;
+
+ case Expression::kValueTest:
+ case Expression::kTestValue:
+ if (count == 1) {
+ __ str(reg, MemOperand(sp));
+ __ push(reg);
+ } else { // count > 1
+ __ Drop(count - 2);
+ __ str(reg, MemOperand(sp, kPointerSize));
+ __ str(reg, MemOperand(sp));
+ }
+ 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;
+ __ bind(materialize_true);
+ __ mov(result_register(), Operand(Factory::true_value()));
+ __ jmp(&done);
+ __ bind(materialize_false);
+ __ mov(result_register(), Operand(Factory::false_value()));
+ __ bind(&done);
+ switch (location_) {
+ case kAccumulator:
+ break;
+ case kStack:
+ __ push(result_register());
+ break;
+ }
+ break;
+ }
+
case Expression::kTest:
- __ Drop(count);
- TestAndBranch(reg, true_label_, false_label_);
break;
+
+ case Expression::kValueTest:
+ __ bind(materialize_true);
+ __ mov(result_register(), Operand(Factory::true_value()));
+ switch (location_) {
+ case kAccumulator:
+ break;
+ case kStack:
+ __ push(result_register());
+ break;
+ }
+ __ jmp(true_label_);
+ break;
+
+ case Expression::kTestValue:
+ __ bind(materialize_false);
+ __ mov(result_register(), Operand(Factory::false_value()));
+ switch (location_) {
+ case kAccumulator:
+ break;
+ case kStack:
+ __ push(result_register());
+ break;
+ }
+ __ jmp(false_label_);
+ break;
+ }
+}
+
+
+void FastCodeGenerator::DoTest(Expression::Context context) {
+ // The value to test is pushed on the stack, and duplicated on the stack
+ // if necessary (for value/test and test/value contexts).
+ ASSERT_NE(NULL, true_label_);
+ ASSERT_NE(NULL, false_label_);
+
+ // Call the runtime to find the boolean value of the source and then
+ // translate it into control flow to the pair of labels.
+ __ CallRuntime(Runtime::kToBool, 1);
+ __ LoadRoot(ip, Heap::kTrueValueRootIndex);
+ __ cmp(r0, ip);
+
+ // Complete based on the context.
+ switch (context) {
+ case Expression::kUninitialized:
+ case Expression::kEffect:
+ case Expression::kValue:
+ UNREACHABLE();
+
+ case Expression::kTest:
+ __ b(eq, true_label_);
+ __ jmp(false_label_);
+ break;
+
case Expression::kValueTest: {
Label discard;
- if (count > 1) __ Drop(count - 1);
- __ str(reg, MemOperand(sp));
- TestAndBranch(reg, true_label_, &discard);
+ switch (location_) {
+ case kAccumulator:
+ __ b(ne, &discard);
+ __ pop(result_register());
+ __ jmp(true_label_);
+ break;
+ case kStack:
+ __ b(eq, true_label_);
+ break;
+ }
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
break;
}
+
case Expression::kTestValue: {
Label discard;
- if (count > 1) __ Drop(count - 1);
- __ str(reg, MemOperand(sp));
- TestAndBranch(reg, &discard, false_label_);
+ switch (location_) {
+ case kAccumulator:
+ __ b(eq, &discard);
+ __ pop(result_register());
+ __ jmp(false_label_);
+ break;
+ case kStack:
+ __ b(ne, false_label_);
+ break;
+ }
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
@@ -348,12 +516,11 @@
void FastCodeGenerator::Move(Register destination, Slot* source) {
// Use destination as scratch.
- MemOperand location = EmitSlotSearch(source, destination);
- __ ldr(destination, location);
+ MemOperand slot_operand = EmitSlotSearch(source, destination);
+ __ ldr(destination, slot_operand);
}
-
void FastCodeGenerator::Move(Slot* dst,
Register src,
Register scratch1,
@@ -370,23 +537,6 @@
}
-
-void FastCodeGenerator::TestAndBranch(Register source,
- Label* true_label,
- Label* false_label) {
- ASSERT_NE(NULL, true_label);
- ASSERT_NE(NULL, false_label);
- // Call the runtime to find the boolean value of the source and then
- // translate it into control flow to the pair of labels.
- __ push(source);
- __ CallRuntime(Runtime::kToBool, 1);
- __ LoadRoot(ip, Heap::kTrueValueRootIndex);
- __ cmp(r0, ip);
- __ b(eq, true_label);
- __ jmp(false_label);
-}
-
-
void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
Comment cmnt(masm_, "[ Declaration");
Variable* var = decl->proxy()->var();
@@ -402,9 +552,8 @@
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ str(ip, MemOperand(fp, SlotOffset(slot)));
} else if (decl->fun() != NULL) {
- Visit(decl->fun());
- __ pop(ip);
- __ str(ip, MemOperand(fp, SlotOffset(slot)));
+ VisitForValue(decl->fun(), kAccumulator);
+ __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
}
break;
@@ -426,13 +575,13 @@
__ str(ip, CodeGenerator::ContextOperand(cp, slot->index()));
// No write barrier since the_hole_value is in old space.
} else if (decl->fun() != NULL) {
- Visit(decl->fun());
- __ pop(r0);
- __ str(r0, CodeGenerator::ContextOperand(cp, slot->index()));
+ VisitForValue(decl->fun(), kAccumulator);
+ __ str(result_register(),
+ CodeGenerator::ContextOperand(cp, slot->index()));
int offset = Context::SlotOffset(slot->index());
__ mov(r2, Operand(offset));
// We know that we have written a function, which is not a smi.
- __ RecordWrite(cp, r2, r0);
+ __ RecordWrite(cp, r2, result_register());
}
break;
@@ -453,7 +602,8 @@
__ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit());
} else if (decl->fun() != NULL) {
__ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit());
- Visit(decl->fun()); // Initial value for function decl.
+ // Push initial value for function declaration.
+ VisitForValue(decl->fun(), kStack);
} else {
__ mov(r0, Operand(Smi::FromInt(0))); // No initial value!
__ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit());
@@ -467,17 +617,13 @@
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(r0);
+ VisitForValue(decl->fun(), kAccumulator);
} else {
- __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
+ __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex);
}
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
@@ -558,7 +704,7 @@
break;
}
}
- Apply(context, slot, r0);
+ Apply(context, slot);
} else {
Comment cmnt(masm_, "Variable rewritten to property");
// A variable has been rewritten into an explicit access to an object
@@ -639,9 +785,8 @@
__ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
}
- // If result_saved == true: The result is saved on top of the
- // stack and in r0.
- // If result_saved == false: The result not on the stack, just in r0.
+ // If result_saved is true the result is on top of the stack. If
+ // result_saved is false the result is in r0.
bool result_saved = false;
for (int i = 0; i < expr->properties()->length(); i++) {
@@ -657,80 +802,47 @@
switch (property->kind()) {
case ObjectLiteral::Property::CONSTANT:
UNREACHABLE();
-
- case ObjectLiteral::Property::MATERIALIZED_LITERAL: // Fall through.
+ case ObjectLiteral::Property::MATERIALIZED_LITERAL:
ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value()));
+ // Fall through.
case ObjectLiteral::Property::COMPUTED:
if (key->handle()->IsSymbol()) {
- Visit(value);
- ASSERT_EQ(Expression::kValue, value->context());
- __ pop(r0);
+ VisitForValue(value, kAccumulator);
__ mov(r2, Operand(key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// StoreIC leaves the receiver on the stack.
- __ ldr(r0, MemOperand(sp)); // Restore result into r0.
break;
}
// Fall through.
-
case ObjectLiteral::Property::PROTOTYPE:
+ // Duplicate receiver on stack.
+ __ ldr(r0, MemOperand(sp));
__ push(r0);
- Visit(key);
- ASSERT_EQ(Expression::kValue, key->context());
- Visit(value);
- ASSERT_EQ(Expression::kValue, value->context());
+ VisitForValue(key, kStack);
+ VisitForValue(value, kStack);
__ CallRuntime(Runtime::kSetProperty, 3);
- __ ldr(r0, MemOperand(sp)); // Restore result into r0.
break;
-
case ObjectLiteral::Property::GETTER:
case ObjectLiteral::Property::SETTER:
+ // Duplicate receiver on stack.
+ __ ldr(r0, MemOperand(sp));
__ push(r0);
- Visit(key);
- ASSERT_EQ(Expression::kValue, key->context());
+ VisitForValue(key, kStack);
__ mov(r1, Operand(property->kind() == ObjectLiteral::Property::SETTER ?
Smi::FromInt(1) :
Smi::FromInt(0)));
__ push(r1);
- Visit(value);
- ASSERT_EQ(Expression::kValue, value->context());
+ VisitForValue(value, kStack);
__ CallRuntime(Runtime::kDefineAccessor, 4);
- __ ldr(r0, MemOperand(sp)); // Restore result into r0
break;
}
}
- switch (expr->context()) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- if (result_saved) __ Drop(1);
- break;
- case Expression::kValue:
- if (!result_saved) __ push(r0);
- break;
- case Expression::kTest:
- if (result_saved) __ pop(r0);
- TestAndBranch(r0, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- if (!result_saved) __ push(r0);
- TestAndBranch(r0, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- if (!result_saved) __ push(r0);
- TestAndBranch(r0, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- break;
- }
+
+ if (result_saved) {
+ ApplyTOS(expr->context());
+ } else {
+ Apply(expr->context(), r0);
}
}
@@ -766,53 +878,24 @@
__ push(r0);
result_saved = true;
}
- Visit(subexpr);
- ASSERT_EQ(Expression::kValue, subexpr->context());
+ VisitForValue(subexpr, kAccumulator);
// Store the subexpression value in the array's elements.
- __ pop(r0); // Subexpression value.
__ ldr(r1, MemOperand(sp)); // Copy of array literal.
__ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
- __ str(r0, FieldMemOperand(r1, offset));
+ __ str(result_register(), FieldMemOperand(r1, offset));
// Update the write barrier for the array store with r0 as the scratch
// register.
__ mov(r2, Operand(offset));
- __ RecordWrite(r1, r2, r0);
+ __ RecordWrite(r1, r2, result_register());
}
- switch (expr->context()) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- if (result_saved) __ Drop(1);
- break;
- case Expression::kValue:
- if (!result_saved) __ push(r0);
- break;
- case Expression::kTest:
- if (result_saved) __ pop(r0);
- TestAndBranch(r0, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- if (!result_saved) __ push(r0);
- TestAndBranch(r0, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- if (!result_saved) __ push(r0);
- TestAndBranch(r0, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- break;
- }
+ if (result_saved) {
+ ApplyTOS(expr->context());
+ } else {
+ Apply(expr->context(), r0);
}
}
@@ -833,12 +916,10 @@
}
-void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
- Expression::Context context) {
- __ pop(r0);
+void FastCodeGenerator::EmitBinaryOp(Token::Value op,
+ Expression::Context context) {
__ pop(r1);
- GenericBinaryOpStub stub(op,
- NO_OVERWRITE);
+ GenericBinaryOpStub stub(op, NO_OVERWRITE);
__ CallStub(&stub);
Apply(context, r0);
}
@@ -852,7 +933,6 @@
// Assignment to a global variable. Use inline caching for the
// assignment. Right-hand-side value is passed in r0, variable name in
// r2, and the global object on the stack.
- __ pop(r0);
__ mov(r2, Operand(var->name()));
__ ldr(ip, CodeGenerator::GlobalObject());
__ push(ip);
@@ -865,77 +945,20 @@
Slot* slot = var->slot();
switch (slot->type()) {
case Slot::LOCAL:
- case Slot::PARAMETER: {
- MemOperand target = MemOperand(fp, SlotOffset(slot));
- switch (context) {
- case Expression::kUninitialized:
- UNREACHABLE();
- case Expression::kEffect:
- // Perform assignment and discard value.
- __ pop(r0);
- __ str(r0, target);
- break;
- case Expression::kValue:
- // Perform assignment and preserve value.
- __ ldr(r0, MemOperand(sp));
- __ str(r0, target);
- break;
- case Expression::kTest:
- // Perform assignment and test (and discard) value.
- __ pop(r0);
- __ str(r0, target);
- TestAndBranch(r0, true_label_, false_label_);
- break;
- case Expression::kValueTest: {
- Label discard;
- __ ldr(r0, MemOperand(sp));
- __ str(r0, target);
- TestAndBranch(r0, true_label_, &discard);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
- break;
- }
- case Expression::kTestValue: {
- Label discard;
- __ ldr(r0, MemOperand(sp));
- __ str(r0, target);
- TestAndBranch(r0, &discard, false_label_);
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- break;
- }
- }
+ case Slot::PARAMETER:
+ __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
break;
- }
case Slot::CONTEXT: {
MemOperand target = EmitSlotSearch(slot, r1);
- __ pop(r0);
- __ str(r0, target);
+ __ str(result_register(), target);
// RecordWrite may destroy all its register arguments.
- if (context == Expression::kValue) {
- __ push(r0);
- } else if (context != Expression::kEffect) {
- __ mov(r3, r0);
- }
+ __ mov(r3, result_register());
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
- // Update the write barrier for the array store with r0 as the scratch
- // register. Skip the write barrier if the value written (r1) is a smi.
- // The smi test is part of RecordWrite on other platforms, not on arm.
- Label exit;
- __ tst(r0, Operand(kSmiTagMask));
- __ b(eq, &exit);
-
__ mov(r2, Operand(offset));
- __ RecordWrite(r1, r2, r0);
- __ bind(&exit);
- if (context != Expression::kEffect && context != Expression::kValue) {
- Apply(context, r3);
- }
+ __ RecordWrite(r1, r2, r3);
break;
}
@@ -943,6 +966,7 @@
UNREACHABLE();
break;
}
+ Apply(context, result_register());
} else {
// Variables rewritten as properties are not treated as variables in
// assignments.
@@ -961,15 +985,15 @@
// change to slow case to avoid the quadratic behavior of repeatedly
// adding fast properties.
if (expr->starts_initialization_block()) {
- __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is under value.
+ __ push(result_register());
+ __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is now under value.
__ push(ip);
__ CallRuntime(Runtime::kToSlowProperties, 1);
+ __ pop(result_register());
}
// Record source code position before IC call.
SetSourcePosition(expr->position());
-
- __ pop(r0);
__ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
@@ -994,23 +1018,23 @@
// change to slow case to avoid the quadratic behavior of repeatedly
// adding fast properties.
if (expr->starts_initialization_block()) {
- // Receiver is under the key and value.
+ __ push(result_register());
+ // Receiver is now under the key and value.
__ ldr(ip, MemOperand(sp, 2 * kPointerSize));
__ push(ip);
__ CallRuntime(Runtime::kToSlowProperties, 1);
+ __ pop(result_register());
}
// Record source code position before IC call.
SetSourcePosition(expr->position());
-
- __ pop(r0);
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
// If the assignment ends an initialization block, revert to fast case.
if (expr->ends_initialization_block()) {
__ push(r0); // Result of assignment, saved even if not needed.
- // Reciever is under the key and value.
+ // Receiver is under the key and value.
__ ldr(ip, MemOperand(sp, 2 * kPointerSize));
__ push(ip);
__ CallRuntime(Runtime::kToFastProperties, 1);
@@ -1027,14 +1051,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(), r0);
} else {
- Visit(expr->key());
+ VisitForValue(expr->key(), kStack);
EmitKeyedPropertyLoad(expr);
// Drop key and receiver left on the stack by IC.
DropAndApply(2, expr->context(), r0);
@@ -1048,8 +1072,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());
@@ -1069,7 +1092,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());
@@ -1109,13 +1132,13 @@
// Call to a named property, use call IC.
__ mov(r0, Operand(key->handle()));
__ push(r0);
- 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));
@@ -1142,7 +1165,7 @@
loop_depth() == 0) {
lit->set_try_fast_codegen(true);
}
- Visit(fun);
+ VisitForValue(fun, kStack);
// Load global receiver object.
__ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
@@ -1159,8 +1182,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).
__ ldr(r0, CodeGenerator::GlobalObject());
@@ -1169,10 +1191,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
@@ -1207,8 +1226,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()) {
@@ -1232,8 +1250,8 @@
switch (expr->op()) {
case Token::VOID: {
Comment cmnt(masm_, "[ UnaryOperation (VOID)");
- Visit(expr->expression());
ASSERT_EQ(Expression::kEffect, expr->expression()->context());
+ Visit(expr->expression());
switch (expr->context()) {
case Expression::kUninitialized:
UNREACHABLE();
@@ -1241,13 +1259,26 @@
case Expression::kEffect:
break;
case Expression::kValue:
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
- __ push(ip);
+ __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
+ switch (location_) {
+ case kAccumulator:
+ break;
+ case kStack:
+ __ push(result_register());
+ break;
+ }
break;
case Expression::kTestValue:
// Value is false so it's needed.
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
- __ push(ip);
+ __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
+ switch (location_) {
+ case kAccumulator:
+ break;
+ case kStack:
+ __ push(result_register());
+ break;
+ }
+ // Fall through.
case Expression::kTest:
case Expression::kValueTest:
__ jmp(false_label_);
@@ -1260,49 +1291,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);
- __ LoadRoot(ip, Heap::kTrueValueRootIndex);
- __ push(ip);
- __ jmp(&done);
- __ bind(&push_false);
- __ LoadRoot(ip, Heap::kFalseValueRootIndex);
- __ push(ip);
- __ 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);
- __ LoadRoot(ip, Heap::kTrueValueRootIndex);
- __ push(ip);
- __ jmp(true_label_);
+ if_false = &materialize_true;
break;
-
case Expression::kTestValue:
- VisitForControl(expr->expression(), &push_false, true_label_);
- __ bind(&push_false);
- __ LoadRoot(ip, Heap::kFalseValueRootIndex);
- __ push(ip);
- __ 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;
}
@@ -1332,7 +1348,7 @@
__ push(r0);
} else {
// This expression cannot throw a reference error at the top level.
- Visit(expr->expression());
+ VisitForValue(expr->expression(), kStack);
}
__ CallRuntime(Runtime::kTypeof, 1);
@@ -1365,8 +1381,11 @@
// 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) {
@@ -1374,13 +1393,11 @@
__ mov(ip, Operand(Smi::FromInt(0)));
__ push(ip);
}
- 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(r0);
@@ -1399,8 +1416,8 @@
break;
case Expression::kValue:
case Expression::kTest:
- case Expression::kTestValue:
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.
@@ -1429,7 +1446,6 @@
// Store the value returned in r0.
switch (assign_type) {
case VARIABLE:
- __ push(r0);
if (expr->is_postfix()) {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Expression::kEffect);
@@ -1499,21 +1515,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());
-
- Visit(expr->left());
- Visit(expr->right());
- __ pop(r0);
- __ pop(r1);
- GenericBinaryOpStub stub(expr->op(),
- NO_OVERWRITE);
- __ CallStub(&stub);
- Apply(expr->context(), r0);
-
+ case Token::SAR:
+ VisitForValue(expr->left(), kStack);
+ VisitForValue(expr->right(), kAccumulator);
+ EmitBinaryOp(expr->op(), expr->context());
break;
- }
+
default:
UNREACHABLE();
}
@@ -1522,14 +1529,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_;
@@ -1542,30 +1545,32 @@
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_JS);
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ cmp(r0, ip);
__ b(eq, if_true);
__ jmp(if_false);
break;
- }
case Token::INSTANCEOF: {
+ VisitForValue(expr->right(), kStack);
InstanceofStub stub;
__ CallStub(&stub);
__ tst(r0, r0);
@@ -1575,6 +1580,7 @@
}
default: {
+ VisitForValue(expr->right(), kAccumulator);
Condition cc = eq;
bool strict = false;
switch (expr->op()) {
@@ -1583,29 +1589,26 @@
// Fall through
case Token::EQ:
cc = eq;
- __ pop(r0);
__ pop(r1);
break;
case Token::LT:
cc = lt;
- __ pop(r0);
__ pop(r1);
break;
case Token::GT:
// Reverse left and right sides to obtain ECMA-262 conversion order.
cc = lt;
- __ pop(r1);
+ __ mov(r1, result_register());
__ pop(r0);
break;
case Token::LTE:
// Reverse left and right sides to obtain ECMA-262 conversion order.
cc = ge;
- __ pop(r1);
+ __ mov(r1, result_register());
__ pop(r0);
break;
case Token::GTE:
cc = ge;
- __ pop(r0);
__ pop(r1);
break;
case Token::IN:
@@ -1635,43 +1638,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);
- __ LoadRoot(ip, Heap::kTrueValueRootIndex);
- __ push(ip);
- __ jmp(&done);
- __ bind(&push_false);
- __ LoadRoot(ip, Heap::kFalseValueRootIndex);
- __ push(ip);
- __ bind(&done);
- break;
-
- case Expression::kTest:
- break;
-
- case Expression::kValueTest:
- __ bind(&push_true);
- __ LoadRoot(ip, Heap::kTrueValueRootIndex);
- __ push(ip);
- __ jmp(true_label_);
- break;
-
- case Expression::kTestValue:
- __ bind(&push_false);
- __ LoadRoot(ip, Heap::kFalseValueRootIndex);
- __ push(ip);
- __ jmp(false_label_);
- break;
- }
+ Apply(expr->context(), if_true, if_false);
}
« no previous file with comments | « no previous file | src/fast-codegen.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698