| 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);
|
| }
|
|
|
|
|
|
|