| Index: src/arm/full-codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/full-codegen-arm.cc (revision 5316)
|
| +++ src/arm/full-codegen-arm.cc (working copy)
|
| @@ -266,16 +266,10 @@
|
| }
|
| 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);
|
| + // For simplicity we always test the accumulator register.
|
| + if (!reg.is(result_register())) __ mov(result_register(), reg);
|
| + DoTest(true_label_, false_label_, NULL);
|
| break;
|
| }
|
| }
|
| @@ -290,8 +284,6 @@
|
| break;
|
| case Expression::kValue:
|
| case Expression::kTest:
|
| - case Expression::kValueTest:
|
| - case Expression::kTestValue:
|
| // On ARM we have to move the value into a register to do anything
|
| // with it.
|
| Move(result_register(), slot);
|
| @@ -310,8 +302,6 @@
|
| // Nothing to do.
|
| case Expression::kValue:
|
| case Expression::kTest:
|
| - case Expression::kValueTest:
|
| - case Expression::kTestValue:
|
| // On ARM we have to move the value into a register to do anything
|
| // with it.
|
| __ mov(result_register(), Operand(lit->handle()));
|
| @@ -340,15 +330,9 @@
|
| }
|
| 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:
|
| - DoTest(context);
|
| + __ pop(result_register());
|
| + DoTest(true_label_, false_label_, NULL);
|
| break;
|
| }
|
| }
|
| @@ -381,23 +365,10 @@
|
| break;
|
|
|
| case Expression::kTest:
|
| - if (count > 1) __ Drop(count - 1);
|
| - __ str(reg, MemOperand(sp));
|
| - DoTest(context);
|
| + __ Drop(count);
|
| + if (!reg.is(result_register())) __ mov(result_register(), reg);
|
| + DoTest(true_label_, false_label_, NULL);
|
| 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;
|
| }
|
| }
|
|
|
| @@ -422,14 +393,6 @@
|
| *if_true = true_label_;
|
| *if_false = false_label_;
|
| break;
|
| - case Expression::kValueTest:
|
| - *if_true = materialize_true;
|
| - *if_false = false_label_;
|
| - break;
|
| - case Expression::kTestValue:
|
| - *if_true = true_label_;
|
| - *if_false = materialize_false;
|
| - break;
|
| }
|
| }
|
|
|
| @@ -471,34 +434,6 @@
|
|
|
| case Expression::kTest:
|
| break;
|
| -
|
| - case Expression::kValueTest:
|
| - __ bind(materialize_true);
|
| - switch (location_) {
|
| - case kAccumulator:
|
| - __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
|
| - break;
|
| - case kStack:
|
| - __ LoadRoot(ip, Heap::kTrueValueRootIndex);
|
| - __ push(ip);
|
| - break;
|
| - }
|
| - __ jmp(true_label_);
|
| - break;
|
| -
|
| - case Expression::kTestValue:
|
| - __ bind(materialize_false);
|
| - switch (location_) {
|
| - case kAccumulator:
|
| - __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
|
| - break;
|
| - case kStack:
|
| - __ LoadRoot(ip, Heap::kFalseValueRootIndex);
|
| - __ push(ip);
|
| - break;
|
| - }
|
| - __ jmp(false_label_);
|
| - break;
|
| }
|
| }
|
|
|
| @@ -529,101 +464,34 @@
|
| case Expression::kTest:
|
| __ b(flag ? true_label_ : false_label_);
|
| break;
|
| - case Expression::kTestValue:
|
| - switch (location_) {
|
| - case kAccumulator:
|
| - // If value is false it's needed.
|
| - if (!flag) __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
|
| - break;
|
| - case kStack:
|
| - // If value is false it's needed.
|
| - if (!flag) {
|
| - __ LoadRoot(ip, Heap::kFalseValueRootIndex);
|
| - __ push(ip);
|
| - }
|
| - break;
|
| - }
|
| - __ b(flag ? true_label_ : false_label_);
|
| - break;
|
| - case Expression::kValueTest:
|
| - switch (location_) {
|
| - case kAccumulator:
|
| - // If value is true it's needed.
|
| - if (flag) __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
|
| - break;
|
| - case kStack:
|
| - // If value is true it's needed.
|
| - if (flag) {
|
| - __ LoadRoot(ip, Heap::kTrueValueRootIndex);
|
| - __ push(ip);
|
| - }
|
| - break;
|
| - }
|
| - __ b(flag ? true_label_ : false_label_);
|
| - break;
|
| }
|
| }
|
|
|
|
|
| -void FullCodeGenerator::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_);
|
| -
|
| +void FullCodeGenerator::DoTest(Label* if_true,
|
| + Label* if_false,
|
| + Label* fall_through) {
|
| // Call the runtime to find the boolean value of the source and then
|
| // translate it into control flow to the pair of labels.
|
| + __ push(result_register());
|
| __ CallRuntime(Runtime::kToBool, 1);
|
| __ LoadRoot(ip, Heap::kTrueValueRootIndex);
|
| __ cmp(r0, ip);
|
| + Split(eq, if_true, if_false, fall_through);
|
| +}
|
|
|
| - // 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;
|
| - 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;
|
| - 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_);
|
| - break;
|
| - }
|
| +void FullCodeGenerator::Split(Condition cc,
|
| + Label* if_true,
|
| + Label* if_false,
|
| + Label* fall_through) {
|
| + if (if_false == fall_through) {
|
| + __ b(cc, if_true);
|
| + } else if (if_true == fall_through) {
|
| + __ b(NegateCondition(cc), if_false);
|
| + } else {
|
| + __ b(cc, if_true);
|
| + __ b(if_false);
|
| }
|
| }
|
|
|
| @@ -1107,28 +975,33 @@
|
| // r2 = RegExp pattern
|
| // r1 = RegExp flags
|
| // r0 = temp + materialized value (RegExp literal)
|
| - __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
| - __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
|
| + __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
| + __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
|
| int literal_offset =
|
| - FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
|
| + FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
|
| __ ldr(r0, FieldMemOperand(r4, literal_offset));
|
| __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
| __ cmp(r0, ip);
|
| __ b(ne, &materialized);
|
| +
|
| + // Create regexp literal using runtime function.
|
| + // Result will be in r0.
|
| __ mov(r3, Operand(Smi::FromInt(expr->literal_index())));
|
| __ mov(r2, Operand(expr->pattern()));
|
| __ mov(r1, Operand(expr->flags()));
|
| __ Push(r4, r3, r2, r1);
|
| __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
|
| +
|
| __ bind(&materialized);
|
| int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
|
| __ push(r0);
|
| __ mov(r0, Operand(Smi::FromInt(size)));
|
| __ push(r0);
|
| __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
|
| +
|
| // After this, registers are used as follows:
|
| // r0: Newly allocated regexp.
|
| - // r1: Materialized regexp
|
| + // r1: Materialized regexp.
|
| // r2: temp.
|
| __ pop(r1);
|
| __ CopyFields(r0, r1, r2.bit(), size / kPointerSize);
|
| @@ -1885,8 +1758,7 @@
|
| PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
|
|
|
| __ tst(r0, Operand(kSmiTagMask | 0x80000000));
|
| - __ b(eq, if_true);
|
| - __ b(if_false);
|
| + Split(eq, if_true, if_false, NULL);
|
|
|
| Apply(context_, if_true, if_false);
|
| }
|
| @@ -1914,8 +1786,7 @@
|
| __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
|
| __ b(lt, if_false);
|
| __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
|
| - __ b(le, if_true);
|
| - __ b(if_false);
|
| + Split(le, if_true, if_false, NULL);
|
|
|
| Apply(context_, if_true, if_false);
|
| }
|
| @@ -1933,8 +1804,7 @@
|
|
|
| __ BranchOnSmi(r0, if_false);
|
| __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
|
| - __ b(ge, if_true);
|
| - __ b(if_false);
|
| + Split(ge, if_true, if_false, NULL);
|
|
|
| Apply(context_, if_true, if_false);
|
| }
|
| @@ -1954,8 +1824,7 @@
|
| __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
|
| __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
|
| __ tst(r1, Operand(1 << Map::kIsUndetectable));
|
| - __ b(ne, if_true);
|
| - __ b(if_false);
|
| + Split(ne, if_true, if_false, NULL);
|
|
|
| Apply(context_, if_true, if_false);
|
| }
|
| @@ -1993,8 +1862,7 @@
|
|
|
| __ BranchOnSmi(r0, if_false);
|
| __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
|
| - __ b(eq, if_true);
|
| - __ b(if_false);
|
| + Split(eq, if_true, if_false, NULL);
|
|
|
| Apply(context_, if_true, if_false);
|
| }
|
| @@ -2012,8 +1880,7 @@
|
|
|
| __ BranchOnSmi(r0, if_false);
|
| __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE);
|
| - __ b(eq, if_true);
|
| - __ b(if_false);
|
| + Split(eq, if_true, if_false, NULL);
|
|
|
| Apply(context_, if_true, if_false);
|
| }
|
| @@ -2031,8 +1898,7 @@
|
|
|
| __ BranchOnSmi(r0, if_false);
|
| __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
|
| - __ b(eq, if_true);
|
| - __ b(if_false);
|
| + Split(eq, if_true, if_false, NULL);
|
|
|
| Apply(context_, if_true, if_false);
|
| }
|
| @@ -2061,8 +1927,7 @@
|
| __ bind(&check_frame_marker);
|
| __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset));
|
| __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
|
| - __ b(eq, if_true);
|
| - __ b(if_false);
|
| + Split(eq, if_true, if_false, NULL);
|
|
|
| Apply(context_, if_true, if_false);
|
| }
|
| @@ -2082,8 +1947,7 @@
|
|
|
| __ pop(r1);
|
| __ cmp(r0, r1);
|
| - __ b(eq, if_true);
|
| - __ b(if_false);
|
| + Split(eq, if_true, if_false, NULL);
|
|
|
| Apply(context_, if_true, if_false);
|
| }
|
| @@ -2752,19 +2616,7 @@
|
| break;
|
| }
|
| break;
|
| - case Expression::kTestValue:
|
| - // Value is false so it's needed.
|
| - __ 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_);
|
| break;
|
| }
|
| @@ -2945,8 +2797,6 @@
|
| break;
|
| case Expression::kValue:
|
| case Expression::kTest:
|
| - case Expression::kValueTest:
|
| - case Expression::kTestValue:
|
| // Save the result on the stack. If we have a named or keyed property
|
| // we store the result under the receiver that is currently on top
|
| // of the stack.
|
| @@ -3034,41 +2884,6 @@
|
| }
|
|
|
|
|
| -void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
| - Comment cmnt(masm_, "[ BinaryOperation");
|
| - switch (expr->op()) {
|
| - case Token::COMMA:
|
| - VisitForEffect(expr->left());
|
| - Visit(expr->right());
|
| - break;
|
| -
|
| - case Token::OR:
|
| - case Token::AND:
|
| - EmitLogicalOperation(expr);
|
| - break;
|
| -
|
| - case Token::ADD:
|
| - case Token::SUB:
|
| - case Token::DIV:
|
| - case Token::MOD:
|
| - case Token::MUL:
|
| - case Token::BIT_OR:
|
| - case Token::BIT_AND:
|
| - case Token::BIT_XOR:
|
| - case Token::SHL:
|
| - case Token::SHR:
|
| - case Token::SAR:
|
| - VisitForValue(expr->left(), kStack);
|
| - VisitForValue(expr->right(), kAccumulator);
|
| - EmitBinaryOp(expr->op(), context_);
|
| - break;
|
| -
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -}
|
| -
|
| -
|
| void FullCodeGenerator::EmitNullCompare(bool strict,
|
| Register obj,
|
| Register null_const,
|
| @@ -3077,7 +2892,7 @@
|
| Register scratch) {
|
| __ cmp(obj, null_const);
|
| if (strict) {
|
| - __ b(eq, if_true);
|
| + Split(eq, if_true, if_false, NULL);
|
| } else {
|
| __ b(eq, if_true);
|
| __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
| @@ -3088,9 +2903,8 @@
|
| __ ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
|
| __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
|
| __ tst(scratch, Operand(1 << Map::kIsUndetectable));
|
| - __ b(ne, if_true);
|
| + Split(ne, if_true, if_false, NULL);
|
| }
|
| - __ jmp(if_false);
|
| }
|
|
|
|
|
| @@ -3112,17 +2926,16 @@
|
| __ InvokeBuiltin(Builtins::IN, CALL_JS);
|
| __ LoadRoot(ip, Heap::kTrueValueRootIndex);
|
| __ cmp(r0, ip);
|
| - __ b(eq, if_true);
|
| - __ jmp(if_false);
|
| + Split(eq, if_true, if_false, NULL);
|
| break;
|
|
|
| case Token::INSTANCEOF: {
|
| VisitForValue(expr->right(), kStack);
|
| InstanceofStub stub;
|
| __ CallStub(&stub);
|
| + // The stub returns 0 for true.
|
| __ tst(r0, r0);
|
| - __ b(eq, if_true); // The stub returns 0 for true.
|
| - __ jmp(if_false);
|
| + Split(eq, if_true, if_false, NULL);
|
| break;
|
| }
|
|
|
| @@ -3191,8 +3004,7 @@
|
| CompareStub stub(cc, strict, kBothCouldBeNaN, true, r1, r0);
|
| __ CallStub(&stub);
|
| __ cmp(r0, Operand(0));
|
| - __ b(cc, if_true);
|
| - __ jmp(if_false);
|
| + Split(cc, if_true, if_false, NULL);
|
| }
|
| }
|
|
|
|
|