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

Side by Side Diff: src/arm/codegen-arm.cc

Issue 151003: Add a compare stub on ARM. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 5 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/arm/codegen-arm.h ('k') | src/arm/simulator-arm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 23 matching lines...) Expand all
34 #include "register-allocator-inl.h" 34 #include "register-allocator-inl.h"
35 #include "runtime.h" 35 #include "runtime.h"
36 #include "scopes.h" 36 #include "scopes.h"
37 37
38 38
39 namespace v8 { 39 namespace v8 {
40 namespace internal { 40 namespace internal {
41 41
42 #define __ ACCESS_MASM(masm_) 42 #define __ ACCESS_MASM(masm_)
43 43
44 static void EmitIdenticalObjectComparison(MacroAssembler* masm,
45 Label* slow,
46 Condition cc);
47 static void EmitSmiNonsmiComparison(MacroAssembler* masm,
48 Label* rhs_not_nan,
49 Label* slow,
50 bool strict);
51 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc);
52 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm);
53
54
55
44 // ------------------------------------------------------------------------- 56 // -------------------------------------------------------------------------
45 // Platform-specific DeferredCode functions. 57 // Platform-specific DeferredCode functions.
46 58
47 void DeferredCode::SaveRegisters() { 59 void DeferredCode::SaveRegisters() {
48 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { 60 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
49 int action = registers_[i]; 61 int action = registers_[i];
50 if (action == kPush) { 62 if (action == kPush) {
51 __ push(RegisterAllocator::ToRegister(i)); 63 __ push(RegisterAllocator::ToRegister(i));
52 } else if (action != kIgnore && (action & kSyncedFlag) == 0) { 64 } else if (action != kIgnore && (action & kSyncedFlag) == 0) {
53 __ str(RegisterAllocator::ToRegister(i), MemOperand(fp, action)); 65 __ str(RegisterAllocator::ToRegister(i), MemOperand(fp, action));
(...skipping 941 matching lines...) Expand 10 before | Expand all | Expand 10 after
995 frame_->EmitPush(r0); 1007 frame_->EmitPush(r0);
996 } 1008 }
997 GenericBinaryOperation(op, mode); 1009 GenericBinaryOperation(op, mode);
998 break; 1010 break;
999 } 1011 }
1000 1012
1001 exit.Bind(); 1013 exit.Bind();
1002 } 1014 }
1003 1015
1004 1016
1005 void CodeGenerator::Comparison(Condition cc, bool strict) { 1017 void CodeGenerator::Comparison(Condition cc,
1018 Expression* left,
1019 Expression* right,
1020 bool strict) {
1021 if (left != NULL) LoadAndSpill(left);
1022 if (right != NULL) LoadAndSpill(right);
1023
1006 VirtualFrame::SpilledScope spilled_scope; 1024 VirtualFrame::SpilledScope spilled_scope;
1007 // sp[0] : y 1025 // sp[0] : y
1008 // sp[1] : x 1026 // sp[1] : x
1009 // result : cc register 1027 // result : cc register
1010 1028
1011 // Strict only makes sense for equality comparisons. 1029 // Strict only makes sense for equality comparisons.
1012 ASSERT(!strict || cc == eq); 1030 ASSERT(!strict || cc == eq);
1013 1031
1014 JumpTarget exit; 1032 JumpTarget exit;
1015 JumpTarget smi; 1033 JumpTarget smi;
1016 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. 1034 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
1017 if (cc == gt || cc == le) { 1035 if (cc == gt || cc == le) {
1018 cc = ReverseCondition(cc); 1036 cc = ReverseCondition(cc);
1019 frame_->EmitPop(r1); 1037 frame_->EmitPop(r1);
1020 frame_->EmitPop(r0); 1038 frame_->EmitPop(r0);
1021 } else { 1039 } else {
1022 frame_->EmitPop(r0); 1040 frame_->EmitPop(r0);
1023 frame_->EmitPop(r1); 1041 frame_->EmitPop(r1);
1024 } 1042 }
1025 __ orr(r2, r0, Operand(r1)); 1043 __ orr(r2, r0, Operand(r1));
1026 __ tst(r2, Operand(kSmiTagMask)); 1044 __ tst(r2, Operand(kSmiTagMask));
1027 smi.Branch(eq); 1045 smi.Branch(eq);
1028 1046
1029 // Perform non-smi comparison by runtime call. 1047 // Perform non-smi comparison by stub.
1030 frame_->EmitPush(r1); 1048 // CompareStub takes arguments in r0 and r1, returns <0, >0 or 0 in r0.
1049 // We call with 0 args because there are 0 on the stack.
1050 CompareStub stub(cc, strict);
1051 frame_->CallStub(&stub, 0);
1031 1052
1032 // Figure out which native to call and setup the arguments. 1053 Result result = allocator_->Allocate(r0);
1033 Builtins::JavaScript native; 1054 ASSERT(result.is_valid());
1034 int arg_count = 1;
1035 if (cc == eq) {
1036 native = strict ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
1037 } else {
1038 native = Builtins::COMPARE;
1039 int ncr; // NaN compare result
1040 if (cc == lt || cc == le) {
1041 ncr = GREATER;
1042 } else {
1043 ASSERT(cc == gt || cc == ge); // remaining cases
1044 ncr = LESS;
1045 }
1046 frame_->EmitPush(r0);
1047 arg_count++;
1048 __ mov(r0, Operand(Smi::FromInt(ncr)));
1049 }
1050
1051 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
1052 // tagged as a small integer.
1053 frame_->EmitPush(r0);
1054 Result arg_count_register = allocator_->Allocate(r0);
1055 ASSERT(arg_count_register.is_valid());
1056 __ mov(arg_count_register.reg(), Operand(arg_count));
1057 Result result = frame_->InvokeBuiltin(native,
1058 CALL_JS,
1059 &arg_count_register,
1060 arg_count + 1);
1061 __ cmp(result.reg(), Operand(0)); 1055 __ cmp(result.reg(), Operand(0));
1062 result.Unuse(); 1056 result.Unuse();
1063 exit.Jump(); 1057 exit.Jump();
1064 1058
1065 // test smi equality by pointer comparison. 1059 // Do smi comparisons by pointer comparison.
1066 smi.Bind(); 1060 smi.Bind();
1067 __ cmp(r1, Operand(r0)); 1061 __ cmp(r1, Operand(r0));
1068 1062
1069 exit.Bind(); 1063 exit.Bind();
1070 cc_reg_ = cc; 1064 cc_reg_ = cc;
1071 } 1065 }
1072 1066
1073 1067
1074 class CallFunctionStub: public CodeStub { 1068 class CallFunctionStub: public CodeStub {
1075 public: 1069 public:
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after
1498 continue; 1492 continue;
1499 } 1493 }
1500 1494
1501 Comment cmnt(masm_, "[ Case clause"); 1495 Comment cmnt(masm_, "[ Case clause");
1502 // Compile the test. 1496 // Compile the test.
1503 next_test.Bind(); 1497 next_test.Bind();
1504 next_test.Unuse(); 1498 next_test.Unuse();
1505 // Duplicate TOS. 1499 // Duplicate TOS.
1506 __ ldr(r0, frame_->Top()); 1500 __ ldr(r0, frame_->Top());
1507 frame_->EmitPush(r0); 1501 frame_->EmitPush(r0);
1508 LoadAndSpill(clause->label()); 1502 Comparison(eq, NULL, clause->label(), true);
1509 Comparison(eq, true);
1510 Branch(false, &next_test); 1503 Branch(false, &next_test);
1511 1504
1512 // Before entering the body from the test, remove the switch value from 1505 // Before entering the body from the test, remove the switch value from
1513 // the stack. 1506 // the stack.
1514 frame_->Drop(); 1507 frame_->Drop();
1515 1508
1516 // Label the body so that fall through is enabled. 1509 // Label the body so that fall through is enabled.
1517 if (i > 0 && cases->at(i - 1)->is_default()) { 1510 if (i > 0 && cases->at(i - 1)->is_default()) {
1518 default_exit.Bind(); 1511 default_exit.Bind();
1519 } else { 1512 } else {
(...skipping 1968 matching lines...) Expand 10 before | Expand all | Expand 10 after
3488 frame_->EmitPop(r0); 3481 frame_->EmitPop(r0);
3489 switch (op) { 3482 switch (op) {
3490 case Token::NOT: 3483 case Token::NOT:
3491 case Token::DELETE: 3484 case Token::DELETE:
3492 case Token::TYPEOF: 3485 case Token::TYPEOF:
3493 UNREACHABLE(); // handled above 3486 UNREACHABLE(); // handled above
3494 break; 3487 break;
3495 3488
3496 case Token::SUB: { 3489 case Token::SUB: {
3497 bool overwrite = 3490 bool overwrite =
3498 (node->AsBinaryOperation() != NULL && 3491 (node->expression()->AsBinaryOperation() != NULL &&
3499 node->AsBinaryOperation()->ResultOverwriteAllowed()); 3492 node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
3500 UnarySubStub stub(overwrite); 3493 UnarySubStub stub(overwrite);
3501 frame_->CallStub(&stub, 0); 3494 frame_->CallStub(&stub, 0);
3502 break; 3495 break;
3503 } 3496 }
3504 3497
3505 case Token::BIT_NOT: { 3498 case Token::BIT_NOT: {
3506 // smi check 3499 // smi check
3507 JumpTarget smi_label; 3500 JumpTarget smi_label;
3508 JumpTarget continue_label; 3501 JumpTarget continue_label;
3509 __ tst(r0, Operand(kSmiTagMask)); 3502 __ tst(r0, Operand(kSmiTagMask));
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after
3953 } else { 3946 } else {
3954 // Uncommon case: typeof testing against a string literal that is 3947 // Uncommon case: typeof testing against a string literal that is
3955 // never returned from the typeof operator. 3948 // never returned from the typeof operator.
3956 false_target()->Jump(); 3949 false_target()->Jump();
3957 } 3950 }
3958 ASSERT(!has_valid_frame() || 3951 ASSERT(!has_valid_frame() ||
3959 (has_cc() && frame_->height() == original_height)); 3952 (has_cc() && frame_->height() == original_height));
3960 return; 3953 return;
3961 } 3954 }
3962 3955
3963 LoadAndSpill(left);
3964 LoadAndSpill(right);
3965 switch (op) { 3956 switch (op) {
3966 case Token::EQ: 3957 case Token::EQ:
3967 Comparison(eq, false); 3958 Comparison(eq, left, right, false);
3968 break; 3959 break;
3969 3960
3970 case Token::LT: 3961 case Token::LT:
3971 Comparison(lt); 3962 Comparison(lt, left, right);
3972 break; 3963 break;
3973 3964
3974 case Token::GT: 3965 case Token::GT:
3975 Comparison(gt); 3966 Comparison(gt, left, right);
3976 break; 3967 break;
3977 3968
3978 case Token::LTE: 3969 case Token::LTE:
3979 Comparison(le); 3970 Comparison(le, left, right);
3980 break; 3971 break;
3981 3972
3982 case Token::GTE: 3973 case Token::GTE:
3983 Comparison(ge); 3974 Comparison(ge, left, right);
3984 break; 3975 break;
3985 3976
3986 case Token::EQ_STRICT: 3977 case Token::EQ_STRICT:
3987 Comparison(eq, true); 3978 Comparison(eq, left, right, true);
3988 break; 3979 break;
3989 3980
3990 case Token::IN: { 3981 case Token::IN: {
3982 LoadAndSpill(left);
3983 LoadAndSpill(right);
3991 Result arg_count = allocator_->Allocate(r0); 3984 Result arg_count = allocator_->Allocate(r0);
3992 ASSERT(arg_count.is_valid()); 3985 ASSERT(arg_count.is_valid());
3993 __ mov(arg_count.reg(), Operand(1)); // not counting receiver 3986 __ mov(arg_count.reg(), Operand(1)); // not counting receiver
3994 Result result = frame_->InvokeBuiltin(Builtins::IN, 3987 Result result = frame_->InvokeBuiltin(Builtins::IN,
3995 CALL_JS, 3988 CALL_JS,
3996 &arg_count, 3989 &arg_count,
3997 2); 3990 2);
3998 frame_->EmitPush(result.reg()); 3991 frame_->EmitPush(result.reg());
3999 break; 3992 break;
4000 } 3993 }
4001 3994
4002 case Token::INSTANCEOF: { 3995 case Token::INSTANCEOF: {
3996 LoadAndSpill(left);
3997 LoadAndSpill(right);
4003 InstanceofStub stub; 3998 InstanceofStub stub;
4004 Result result = frame_->CallStub(&stub, 2); 3999 Result result = frame_->CallStub(&stub, 2);
4005 // At this point if instanceof succeeded then r0 == 0. 4000 // At this point if instanceof succeeded then r0 == 0.
4006 __ tst(result.reg(), Operand(result.reg())); 4001 __ tst(result.reg(), Operand(result.reg()));
4007 cc_reg_ = eq; 4002 cc_reg_ = eq;
4008 break; 4003 break;
4009 } 4004 }
4010 4005
4011 default: 4006 default:
4012 UNREACHABLE(); 4007 UNREACHABLE();
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after
4475 // significant 1 bit is not stored. 4470 // significant 1 bit is not stored.
4476 non_smi_exponent += 1 << HeapNumber::kExponentShift; 4471 non_smi_exponent += 1 << HeapNumber::kExponentShift;
4477 __ mov(ip, Operand(HeapNumber::kSignMask | non_smi_exponent)); 4472 __ mov(ip, Operand(HeapNumber::kSignMask | non_smi_exponent));
4478 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kExponentOffset)); 4473 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kExponentOffset));
4479 __ mov(ip, Operand(0)); 4474 __ mov(ip, Operand(0));
4480 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset)); 4475 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset));
4481 __ Ret(); 4476 __ Ret();
4482 } 4477 }
4483 4478
4484 4479
4480 // Handle the case where the lhs and rhs are the same object.
4481 // Equality is almost reflexive (everything but NaN), so this is a test
4482 // for "identity and not NaN".
4483 static void EmitIdenticalObjectComparison(MacroAssembler* masm,
4484 Label* slow,
4485 Condition cc) {
4486 Label not_identical;
4487 __ cmp(r0, Operand(r1));
4488 __ b(ne, &not_identical);
4489
4490 Register exp_mask_reg = r5;
4491 __ mov(exp_mask_reg, Operand(HeapNumber::kExponentMask));
4492
4493 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
4494 // so we do the second best thing - test it ourselves.
4495 Label heap_number, return_equal;
4496 // They are both equal and they are not both Smis so both of them are not
4497 // Smis. If it's not a heap number, then return equal.
4498 if (cc == lt || cc == gt) {
4499 __ CompareObjectType(r0, r4, r4, FIRST_JS_OBJECT_TYPE);
4500 __ b(ge, slow);
4501 } else {
4502 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
4503 __ b(eq, &heap_number);
4504 // Comparing JS objects with <=, >= is complicated.
4505 if (cc != eq) {
4506 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
4507 __ b(ge, slow);
4508 }
4509 }
4510 __ bind(&return_equal);
4511 if (cc == lt) {
4512 __ mov(r0, Operand(GREATER)); // Things aren't less than themselves.
4513 } else if (cc == gt) {
4514 __ mov(r0, Operand(LESS)); // Things aren't greater than themselves.
4515 } else {
4516 __ mov(r0, Operand(0)); // Things are <=, >=, ==, === themselves.
4517 }
4518 __ mov(pc, Operand(lr)); // Return.
4519
4520 // For less and greater we don't have to check for NaN since the result of
4521 // x < x is false regardless. For the others here is some code to check
4522 // for NaN.
4523 if (cc != lt && cc != gt) {
4524 __ bind(&heap_number);
4525 // It is a heap number, so return non-equal if it's NaN and equal if it's
4526 // not NaN.
4527 // The representation of NaN values has all exponent bits (52..62) set,
4528 // and not all mantissa bits (0..51) clear.
4529 // Read top bits of double representation (second word of value).
4530 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
4531 // Test that exponent bits are all set.
4532 __ and_(r3, r2, Operand(exp_mask_reg));
4533 __ cmp(r3, Operand(exp_mask_reg));
4534 __ b(ne, &return_equal);
4535
4536 // Shift out flag and all exponent bits, retaining only mantissa.
4537 __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord));
4538 // Or with all low-bits of mantissa.
4539 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
4540 __ orr(r0, r3, Operand(r2), SetCC);
4541 // For equal we already have the right value in r0: Return zero (equal)
4542 // if all bits in mantissa are zero (it's an Infinity) and non-zero if not
4543 // (it's a NaN). For <= and >= we need to load r0 with the failing value
4544 // if it's a NaN.
4545 if (cc != eq) {
4546 // All-zero means Infinity means equal.
4547 __ mov(pc, Operand(lr), LeaveCC, eq); // Return equal
4548 if (cc == le) {
4549 __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail.
4550 } else {
4551 __ mov(r0, Operand(LESS)); // NaN >= NaN should fail.
4552 }
4553 }
4554 __ mov(pc, Operand(lr)); // Return.
4555 }
4556 // No fall through here.
4557
4558 __ bind(&not_identical);
4559 }
4560
4561
4562 // See comment at call site.
4563 static void EmitSmiNonsmiComparison(MacroAssembler* masm,
4564 Label* rhs_not_nan,
4565 Label* slow,
4566 bool strict) {
4567 Label lhs_is_smi;
4568 __ tst(r0, Operand(kSmiTagMask));
4569 __ b(eq, &lhs_is_smi);
4570
4571 // Rhs is a Smi. Check whether the non-smi is a heap number.
4572 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
4573 if (strict) {
4574 // If lhs was not a number and rhs was a Smi then strict equality cannot
4575 // succeed. Return non-equal (r0 is already not zero)
4576 __ mov(pc, Operand(lr), LeaveCC, ne); // Return.
4577 } else {
4578 // Smi compared non-strictly with a non-Smi non-heap-number. Call
4579 // the runtime.
4580 __ b(ne, slow);
4581 }
4582
4583 // Rhs is a smi, lhs is a number.
4584 __ push(lr);
4585 __ mov(r7, Operand(r1));
4586 ConvertToDoubleStub stub1(r3, r2, r7, r6);
4587 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET);
4588 // r3 and r2 are rhs as double.
4589 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize));
4590 __ ldr(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
4591 // We now have both loaded as doubles but we can skip the lhs nan check
4592 // since it's a Smi.
4593 __ pop(lr);
4594 __ jmp(rhs_not_nan);
4595
4596 __ bind(&lhs_is_smi);
4597 // Lhs is a Smi. Check whether the non-smi is a heap number.
4598 __ CompareObjectType(r1, r4, r4, HEAP_NUMBER_TYPE);
4599 if (strict) {
4600 // If lhs was not a number and rhs was a Smi then strict equality cannot
4601 // succeed. Return non-equal.
4602 __ mov(r0, Operand(1), LeaveCC, ne); // Non-zero indicates not equal.
4603 __ mov(pc, Operand(lr), LeaveCC, ne); // Return.
4604 } else {
4605 // Smi compared non-strictly with a non-Smi non-heap-number. Call
4606 // the runtime.
4607 __ b(ne, slow);
4608 }
4609
4610 // Lhs is a smi, rhs is a number.
4611 // r0 is Smi and r1 is heap number.
4612 __ push(lr);
4613 __ ldr(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
4614 __ ldr(r3, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize));
4615 __ mov(r7, Operand(r0));
4616 ConvertToDoubleStub stub2(r1, r0, r7, r6);
4617 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET);
4618 __ pop(lr);
4619 // Fall through to both_loaded_as_doubles.
4620 }
4621
4622
4623 void EmitNanCheck(MacroAssembler* masm, Label* rhs_not_nan, Condition cc) {
4624 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
4625 Register lhs_exponent = exp_first ? r0 : r1;
4626 Register rhs_exponent = exp_first ? r2 : r3;
4627 Register lhs_mantissa = exp_first ? r1 : r0;
4628 Register rhs_mantissa = exp_first ? r3 : r2;
4629 Label one_is_nan, neither_is_nan;
4630
4631 Register exp_mask_reg = r5;
4632
4633 __ mov(exp_mask_reg, Operand(HeapNumber::kExponentMask));
4634 __ and_(r4, rhs_exponent, Operand(exp_mask_reg));
4635 __ cmp(r4, Operand(exp_mask_reg));
4636 __ b(ne, rhs_not_nan);
4637 __ mov(r4,
4638 Operand(rhs_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord),
4639 SetCC);
4640 __ b(ne, &one_is_nan);
4641 __ cmp(rhs_mantissa, Operand(0));
4642 __ b(ne, &one_is_nan);
4643
4644 __ bind(rhs_not_nan);
4645 __ mov(exp_mask_reg, Operand(HeapNumber::kExponentMask));
4646 __ and_(r4, lhs_exponent, Operand(exp_mask_reg));
4647 __ cmp(r4, Operand(exp_mask_reg));
4648 __ b(ne, &neither_is_nan);
4649 __ mov(r4,
4650 Operand(lhs_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord),
4651 SetCC);
4652 __ b(ne, &one_is_nan);
4653 __ cmp(lhs_mantissa, Operand(0));
4654 __ b(eq, &neither_is_nan);
4655
4656 __ bind(&one_is_nan);
4657 // NaN comparisons always fail.
4658 // Load whatever we need in r0 to make the comparison fail.
4659 if (cc == lt || cc == le) {
4660 __ mov(r0, Operand(GREATER));
4661 } else {
4662 __ mov(r0, Operand(LESS));
4663 }
4664 __ mov(pc, Operand(lr)); // Return.
4665
4666 __ bind(&neither_is_nan);
4667 }
4668
4669
4670 // See comment at call site.
4671 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) {
4672 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset);
4673 Register lhs_exponent = exp_first ? r0 : r1;
4674 Register rhs_exponent = exp_first ? r2 : r3;
4675 Register lhs_mantissa = exp_first ? r1 : r0;
4676 Register rhs_mantissa = exp_first ? r3 : r2;
4677
4678 // r0, r1, r2, r3 have the two doubles. Neither is a NaN.
4679 if (cc == eq) {
4680 // Doubles are not equal unless they have the same bit pattern.
4681 // Exception: 0 and -0.
4682 __ cmp(lhs_mantissa, Operand(rhs_mantissa));
4683 __ orr(r0, lhs_mantissa, Operand(rhs_mantissa), LeaveCC, ne);
4684 // Return non-zero if the numbers are unequal.
4685 __ mov(pc, Operand(lr), LeaveCC, ne);
4686
4687 __ sub(r0, lhs_exponent, Operand(rhs_exponent), SetCC);
4688 // If exponents are equal then return 0.
4689 __ mov(pc, Operand(lr), LeaveCC, eq);
4690
4691 // Exponents are unequal. The only way we can return that the numbers
4692 // are equal is if one is -0 and the other is 0. We already dealt
4693 // with the case where both are -0 or both are 0.
4694 // We start by seeing if the mantissas (that are equal) or the bottom
4695 // 31 bits of the rhs exponent are non-zero. If so we return not
4696 // equal.
4697 __ orr(r4, rhs_mantissa, Operand(rhs_exponent, LSL, kSmiTagSize), SetCC);
4698 __ mov(r0, Operand(r4), LeaveCC, ne);
4699 __ mov(pc, Operand(lr), LeaveCC, ne); // Return conditionally.
4700 // Now they are equal if and only if the lhs exponent is zero in its
4701 // low 31 bits.
4702 __ mov(r0, Operand(lhs_exponent, LSL, kSmiTagSize));
4703 __ mov(pc, Operand(lr));
4704 } else {
4705 // Call a native function to do a comparison between two non-NaNs.
4706 // Call C routine that may not cause GC or other trouble.
4707 __ mov(r5, Operand(ExternalReference::compare_doubles()));
4708 __ Jump(r5); // Tail call.
4709 }
4710 }
4711
4712
4713 // See comment at call site.
4714 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm) {
4715 // If either operand is a JSObject or an oddball value, then they are
4716 // not equal since their pointers are different.
4717 // There is no test for undetectability in strict equality.
4718 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
4719 Label first_non_object;
4720 // Get the type of the first operand into r2 and compare it with
4721 // FIRST_JS_OBJECT_TYPE.
4722 __ CompareObjectType(r0, r2, r2, FIRST_JS_OBJECT_TYPE);
4723 __ b(lt, &first_non_object);
4724
4725 // Return non-zero (r0 is not zero)
4726 Label return_not_equal;
4727 __ bind(&return_not_equal);
4728 __ mov(pc, Operand(lr)); // Return.
4729
4730 __ bind(&first_non_object);
4731 // Check for oddballs: true, false, null, undefined.
4732 __ cmp(r2, Operand(ODDBALL_TYPE));
4733 __ b(eq, &return_not_equal);
4734
4735 __ CompareObjectType(r1, r3, r3, FIRST_JS_OBJECT_TYPE);
4736 __ b(ge, &return_not_equal);
4737
4738 // Check for oddballs: true, false, null, undefined.
4739 __ cmp(r3, Operand(ODDBALL_TYPE));
4740 __ b(eq, &return_not_equal);
4741 }
4742
4743
4744 // See comment at call site.
4745 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm,
4746 Label* both_loaded_as_doubles,
4747 Label* not_heap_numbers,
4748 Label* slow) {
4749 __ CompareObjectType(r0, r2, r2, HEAP_NUMBER_TYPE);
4750 __ b(ne, not_heap_numbers);
4751 __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE);
4752 __ b(ne, slow); // First was a heap number, second wasn't. Go slow case.
4753
4754 // Both are heap numbers. Load them up then jump to the code we have
4755 // for that.
4756 __ ldr(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
4757 __ ldr(r3, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize));
4758 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize));
4759 __ ldr(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
4760 __ jmp(both_loaded_as_doubles);
4761 }
4762
4763
4764 // Fast negative check for symbol-to-symbol equality.
4765 static void EmitCheckForSymbols(MacroAssembler* masm, Label* slow) {
4766 // r2 is object type of r0.
4767 __ tst(r2, Operand(kIsNotStringMask));
4768 __ b(ne, slow);
4769 __ tst(r2, Operand(kIsSymbolMask));
4770 __ b(eq, slow);
4771 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
4772 __ b(ge, slow);
4773 __ tst(r3, Operand(kIsSymbolMask));
4774 __ b(eq, slow);
4775
4776 // Both are symbols. We already checked they weren't the same pointer
4777 // so they are not equal.
4778 __ mov(r0, Operand(1)); // Non-zero indicates not equal.
4779 __ mov(pc, Operand(lr)); // Return.
4780 }
4781
4782
4783 // On entry r0 and r1 are the things to be compared. On exit r0 is 0,
4784 // positive or negative to indicate the result of the comparison.
4785 void CompareStub::Generate(MacroAssembler* masm) {
4786 Label slow; // Call builtin.
4787 Label not_smis, both_loaded_as_doubles, rhs_not_nan;
4788
4789 // NOTICE! This code is only reached after a smi-fast-case check, so
4790 // it is certain that at least one operand isn't a smi.
4791
4792 // Handle the case where the objects are identical. Either returns the answer
4793 // or goes to slow. Only falls through if the objects were not identical.
4794 EmitIdenticalObjectComparison(masm, &slow, cc_);
4795
4796 // If either is a Smi (we know that not both are), then they can only
4797 // be strictly equal if the other is a HeapNumber.
4798 ASSERT_EQ(0, kSmiTag);
4799 ASSERT_EQ(0, Smi::FromInt(0));
4800 __ and_(r2, r0, Operand(r1));
4801 __ tst(r2, Operand(kSmiTagMask));
4802 __ b(ne, &not_smis);
4803 // One operand is a smi. EmitSmiNonsmiComparison generates code that can:
4804 // 1) Return the answer.
4805 // 2) Go to slow.
4806 // 3) Fall through to both_loaded_as_doubles.
4807 // 4) Jump to rhs_not_nan.
4808 // In cases 3 and 4 we have found out we were dealing with a number-number
4809 // comparison and the numbers have been loaded into r0, r1, r2, r3 as doubles.
4810 EmitSmiNonsmiComparison(masm, &rhs_not_nan, &slow, strict_);
4811
4812 __ bind(&both_loaded_as_doubles);
4813 // r0, r1, r2, r3 are the double representations of the left hand side
4814 // and the right hand side.
4815
4816 // Checks for NaN in the doubles we have loaded. Can return the answer or
4817 // fall through if neither is a NaN. Also binds rhs_not_nan.
4818 EmitNanCheck(masm, &rhs_not_nan, cc_);
4819
4820 // Compares two doubles in r0, r1, r2, r3 that are not NaNs. Returns the
4821 // answer. Never falls through.
4822 EmitTwoNonNanDoubleComparison(masm, cc_);
4823
4824 __ bind(&not_smis);
4825 // At this point we know we are dealing with two different objects,
4826 // and neither of them is a Smi. The objects are in r0 and r1.
4827 if (strict_) {
4828 // This returns non-equal for some object types, or falls through if it
4829 // was not lucky.
4830 EmitStrictTwoHeapObjectCompare(masm);
4831 }
4832
4833 Label check_for_symbols;
4834 // Check for heap-number-heap-number comparison. Can jump to slow case,
4835 // or load both doubles into r0, r1, r2, r3 and jump to the code that handles
4836 // that case. If the inputs are not doubles then jumps to check_for_symbols.
4837 // In this case r2 will contain the type of r0.
4838 EmitCheckForTwoHeapNumbers(masm,
4839 &both_loaded_as_doubles,
4840 &check_for_symbols,
4841 &slow);
4842
4843 __ bind(&check_for_symbols);
4844 if (cc_ == eq) {
4845 // Either jumps to slow or returns the answer. Assumes that r2 is the type
4846 // of r0 on entry.
4847 EmitCheckForSymbols(masm, &slow);
4848 }
4849
4850 __ bind(&slow);
4851 __ push(lr);
4852 __ push(r1);
4853 __ push(r0);
4854 // Figure out which native to call and setup the arguments.
4855 Builtins::JavaScript native;
4856 int arg_count = 1; // Not counting receiver.
4857 if (cc_ == eq) {
4858 native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
4859 } else {
4860 native = Builtins::COMPARE;
4861 int ncr; // NaN compare result
4862 if (cc_ == lt || cc_ == le) {
4863 ncr = GREATER;
4864 } else {
4865 ASSERT(cc_ == gt || cc_ == ge); // remaining cases
4866 ncr = LESS;
4867 }
4868 arg_count++;
4869 __ mov(r0, Operand(Smi::FromInt(ncr)));
4870 __ push(r0);
4871 }
4872
4873 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
4874 // tagged as a small integer.
4875 __ mov(r0, Operand(arg_count));
4876 __ InvokeBuiltin(native, CALL_JS);
4877 __ cmp(r0, Operand(0));
4878 __ pop(pc);
4879 }
4880
4881
4485 // Allocates a heap number or jumps to the label if the young space is full and 4882 // Allocates a heap number or jumps to the label if the young space is full and
4486 // a scavenge is needed. 4883 // a scavenge is needed.
4487 static void AllocateHeapNumber( 4884 static void AllocateHeapNumber(
4488 MacroAssembler* masm, 4885 MacroAssembler* masm,
4489 Label* need_gc, // Jump here if young space is full. 4886 Label* need_gc, // Jump here if young space is full.
4490 Register result_reg, // The tagged address of the new heap number. 4887 Register result_reg, // The tagged address of the new heap number.
4491 Register allocation_top_addr_reg, // A scratch register. 4888 Register allocation_top_addr_reg, // A scratch register.
4492 Register scratch2) { // Another scratch register. 4889 Register scratch2) { // Another scratch register.
4493 ExternalReference allocation_top = 4890 ExternalReference allocation_top =
4494 ExternalReference::new_space_allocation_top_address(); 4891 ExternalReference::new_space_allocation_top_address();
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
4531 const Builtins::JavaScript& builtin, 4928 const Builtins::JavaScript& builtin,
4532 Token::Value operation, 4929 Token::Value operation,
4533 OverwriteMode mode) { 4930 OverwriteMode mode) {
4534 Label slow, slow_pop_2_first, do_the_call; 4931 Label slow, slow_pop_2_first, do_the_call;
4535 Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1; 4932 Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1;
4536 // Smi-smi case (overflow). 4933 // Smi-smi case (overflow).
4537 // Since both are Smis there is no heap number to overwrite, so allocate. 4934 // Since both are Smis there is no heap number to overwrite, so allocate.
4538 // The new heap number is in r5. r6 and r7 are scratch. 4935 // The new heap number is in r5. r6 and r7 are scratch.
4539 AllocateHeapNumber(masm, &slow, r5, r6, r7); 4936 AllocateHeapNumber(masm, &slow, r5, r6, r7);
4540 // Write Smi from r0 to r3 and r2 in double format. r6 is scratch. 4937 // Write Smi from r0 to r3 and r2 in double format. r6 is scratch.
4541 ConvertToDoubleStub stub1(r3, r2, r0, r6); 4938 __ mov(r7, Operand(r0));
4939 ConvertToDoubleStub stub1(r3, r2, r7, r6);
4542 __ push(lr); 4940 __ push(lr);
4543 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); 4941 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET);
4544 // Write Smi from r1 to r1 and r0 in double format. r6 is scratch. 4942 // Write Smi from r1 to r1 and r0 in double format. r6 is scratch.
4545 __ mov(r7, Operand(r1)); 4943 __ mov(r7, Operand(r1));
4546 ConvertToDoubleStub stub2(r1, r0, r7, r6); 4944 ConvertToDoubleStub stub2(r1, r0, r7, r6);
4547 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); 4945 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET);
4548 __ pop(lr); 4946 __ pop(lr);
4549 __ jmp(&do_the_call); // Tail call. No return. 4947 __ jmp(&do_the_call); // Tail call. No return.
4550 4948
4551 // We jump to here if something goes wrong (one param is not a number of any 4949 // We jump to here if something goes wrong (one param is not a number of any
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after
5008 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1); 5406 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
5009 __ bind(&within_limit); 5407 __ bind(&within_limit);
5010 5408
5011 __ StubReturn(1); 5409 __ StubReturn(1);
5012 } 5410 }
5013 5411
5014 5412
5015 void UnarySubStub::Generate(MacroAssembler* masm) { 5413 void UnarySubStub::Generate(MacroAssembler* masm) {
5016 Label undo; 5414 Label undo;
5017 Label slow; 5415 Label slow;
5018 Label done;
5019 Label not_smi; 5416 Label not_smi;
5020 5417
5021 // Enter runtime system if the value is not a smi. 5418 // Enter runtime system if the value is not a smi.
5022 __ tst(r0, Operand(kSmiTagMask)); 5419 __ tst(r0, Operand(kSmiTagMask));
5023 __ b(ne, &not_smi); 5420 __ b(ne, &not_smi);
5024 5421
5025 // Enter runtime system if the value of the expression is zero 5422 // Enter runtime system if the value of the expression is zero
5026 // to make sure that we switch between 0 and -0. 5423 // to make sure that we switch between 0 and -0.
5027 __ cmp(r0, Operand(0)); 5424 __ cmp(r0, Operand(0));
5028 __ b(eq, &slow); 5425 __ b(eq, &slow);
5029 5426
5030 // The value of the expression is a smi that is not zero. Try 5427 // The value of the expression is a smi that is not zero. Try
5031 // optimistic subtraction '0 - value'. 5428 // optimistic subtraction '0 - value'.
5032 __ rsb(r1, r0, Operand(0), SetCC); 5429 __ rsb(r1, r0, Operand(0), SetCC);
5033 __ b(vs, &slow); 5430 __ b(vs, &slow);
5034 5431
5035 __ mov(r0, Operand(r1)); // Set r0 to result. 5432 __ mov(r0, Operand(r1)); // Set r0 to result.
5036 __ StubReturn(1); 5433 __ StubReturn(1);
5037 5434
5038 // Enter runtime system. 5435 // Enter runtime system.
5039 __ bind(&slow); 5436 __ bind(&slow);
5040 __ push(r0); 5437 __ push(r0);
5041 __ mov(r0, Operand(0)); // Set number of arguments. 5438 __ mov(r0, Operand(0)); // Set number of arguments.
5042 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS); 5439 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS);
5043 5440
5044 __ bind(&done);
5045 __ StubReturn(1);
5046
5047 __ bind(&not_smi); 5441 __ bind(&not_smi);
5048 __ CompareObjectType(r0, r1, r1, HEAP_NUMBER_TYPE); 5442 __ CompareObjectType(r0, r1, r1, HEAP_NUMBER_TYPE);
5049 __ b(ne, &slow); 5443 __ b(ne, &slow);
5050 // r0 is a heap number. Get a new heap number in r1. 5444 // r0 is a heap number. Get a new heap number in r1.
5051 if (overwrite_) { 5445 if (overwrite_) {
5052 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); 5446 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
5053 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. 5447 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign.
5054 __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); 5448 __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
5055 } else { 5449 } else {
5056 AllocateHeapNumber(masm, &slow, r1, r2, r3); 5450 AllocateHeapNumber(masm, &slow, r1, r2, r3);
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
5196 __ mov(r0, Operand(r4)); 5590 __ mov(r0, Operand(r4));
5197 __ mov(r1, Operand(r6)); 5591 __ mov(r1, Operand(r6));
5198 5592
5199 // TODO(1242173): To let the GC traverse the return address of the exit 5593 // TODO(1242173): To let the GC traverse the return address of the exit
5200 // frames, we need to know where the return address is. Right now, 5594 // frames, we need to know where the return address is. Right now,
5201 // we push it on the stack to be able to find it again, but we never 5595 // we push it on the stack to be able to find it again, but we never
5202 // restore from it in case of changes, which makes it impossible to 5596 // restore from it in case of changes, which makes it impossible to
5203 // support moving the C entry code stub. This should be fixed, but currently 5597 // support moving the C entry code stub. This should be fixed, but currently
5204 // this is OK because the CEntryStub gets generated so early in the V8 boot 5598 // this is OK because the CEntryStub gets generated so early in the V8 boot
5205 // sequence that it is not moving ever. 5599 // sequence that it is not moving ever.
5206 __ add(lr, pc, Operand(4)); // compute return address: (pc + 8) + 4 5600 masm->add(lr, pc, Operand(4)); // compute return address: (pc + 8) + 4
5207 __ push(lr); 5601 masm->push(lr);
5208 __ Jump(r5); 5602 masm->Jump(r5);
5209 5603
5210 if (always_allocate) { 5604 if (always_allocate) {
5211 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1 5605 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1
5212 // though (contain the result). 5606 // though (contain the result).
5213 __ mov(r2, Operand(scope_depth)); 5607 __ mov(r2, Operand(scope_depth));
5214 __ ldr(r3, MemOperand(r2)); 5608 __ ldr(r3, MemOperand(r2));
5215 __ sub(r3, r3, Operand(1)); 5609 __ sub(r3, r3, Operand(1));
5216 __ str(r3, MemOperand(r2)); 5610 __ str(r3, MemOperand(r2));
5217 } 5611 }
5218 5612
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after
5622 // Slow-case: Non-function called. 6016 // Slow-case: Non-function called.
5623 __ bind(&slow); 6017 __ bind(&slow);
5624 __ mov(r0, Operand(argc_)); // Setup the number of arguments. 6018 __ mov(r0, Operand(argc_)); // Setup the number of arguments.
5625 __ mov(r2, Operand(0)); 6019 __ mov(r2, Operand(0));
5626 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); 6020 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
5627 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), 6021 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)),
5628 RelocInfo::CODE_TARGET); 6022 RelocInfo::CODE_TARGET);
5629 } 6023 }
5630 6024
5631 6025
6026 int CompareStub::MinorKey() {
6027 // Encode the two parameters in a unique 16 bit value.
6028 ASSERT(static_cast<unsigned>(cc_) >> 28 < (1 << 15));
6029 return (static_cast<unsigned>(cc_) >> 27) | (strict_ ? 1 : 0);
6030 }
6031
6032
5632 #undef __ 6033 #undef __
5633 6034
5634 } } // namespace v8::internal 6035 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/arm/codegen-arm.h ('k') | src/arm/simulator-arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698