OLD | NEW |
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 26 matching lines...) Expand all Loading... |
37 #include "scopes.h" | 37 #include "scopes.h" |
38 | 38 |
39 | 39 |
40 namespace v8 { | 40 namespace v8 { |
41 namespace internal { | 41 namespace internal { |
42 | 42 |
43 #define __ ACCESS_MASM(masm_) | 43 #define __ ACCESS_MASM(masm_) |
44 | 44 |
45 static void EmitIdenticalObjectComparison(MacroAssembler* masm, | 45 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
46 Label* slow, | 46 Label* slow, |
47 Condition cc); | 47 Condition cc, |
| 48 bool never_nan_nan); |
48 static void EmitSmiNonsmiComparison(MacroAssembler* masm, | 49 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
49 Label* rhs_not_nan, | 50 Label* rhs_not_nan, |
50 Label* slow, | 51 Label* slow, |
51 bool strict); | 52 bool strict); |
52 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc); | 53 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc); |
53 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm); | 54 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm); |
54 static void MultiplyByKnownInt(MacroAssembler* masm, | 55 static void MultiplyByKnownInt(MacroAssembler* masm, |
55 Register source, | 56 Register source, |
56 Register destination, | 57 Register destination, |
57 int known_int); | 58 int known_int); |
(...skipping 4533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4591 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset)); | 4592 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset)); |
4592 __ Ret(); | 4593 __ Ret(); |
4593 } | 4594 } |
4594 | 4595 |
4595 | 4596 |
4596 // Handle the case where the lhs and rhs are the same object. | 4597 // Handle the case where the lhs and rhs are the same object. |
4597 // Equality is almost reflexive (everything but NaN), so this is a test | 4598 // Equality is almost reflexive (everything but NaN), so this is a test |
4598 // for "identity and not NaN". | 4599 // for "identity and not NaN". |
4599 static void EmitIdenticalObjectComparison(MacroAssembler* masm, | 4600 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
4600 Label* slow, | 4601 Label* slow, |
4601 Condition cc) { | 4602 Condition cc, |
| 4603 bool never_nan_nan) { |
4602 Label not_identical; | 4604 Label not_identical; |
| 4605 Label heap_number, return_equal; |
| 4606 Register exp_mask_reg = r5; |
4603 __ cmp(r0, Operand(r1)); | 4607 __ cmp(r0, Operand(r1)); |
4604 __ b(ne, ¬_identical); | 4608 __ b(ne, ¬_identical); |
4605 | 4609 |
4606 Register exp_mask_reg = r5; | 4610 // The two objects are identical. If we know that one of them isn't NaN then |
4607 __ mov(exp_mask_reg, Operand(HeapNumber::kExponentMask)); | 4611 // we now know they test equal. |
| 4612 if (cc != eq || !never_nan_nan) { |
| 4613 __ mov(exp_mask_reg, Operand(HeapNumber::kExponentMask)); |
4608 | 4614 |
4609 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), | 4615 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), |
4610 // so we do the second best thing - test it ourselves. | 4616 // so we do the second best thing - test it ourselves. |
4611 Label heap_number, return_equal; | 4617 // They are both equal and they are not both Smis so both of them are not |
4612 // They are both equal and they are not both Smis so both of them are not | 4618 // Smis. If it's not a heap number, then return equal. |
4613 // Smis. If it's not a heap number, then return equal. | 4619 if (cc == lt || cc == gt) { |
4614 if (cc == lt || cc == gt) { | 4620 __ CompareObjectType(r0, r4, r4, FIRST_JS_OBJECT_TYPE); |
4615 __ CompareObjectType(r0, r4, r4, FIRST_JS_OBJECT_TYPE); | |
4616 __ b(ge, slow); | |
4617 } else { | |
4618 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); | |
4619 __ b(eq, &heap_number); | |
4620 // Comparing JS objects with <=, >= is complicated. | |
4621 if (cc != eq) { | |
4622 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE)); | |
4623 __ b(ge, slow); | 4621 __ b(ge, slow); |
4624 // Normally here we fall through to return_equal, but undefined is | 4622 } else { |
4625 // special: (undefined == undefined) == true, but (undefined <= undefined) | 4623 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); |
4626 // == false! See ECMAScript 11.8.5. | 4624 __ b(eq, &heap_number); |
4627 if (cc == le || cc == ge) { | 4625 // Comparing JS objects with <=, >= is complicated. |
4628 __ cmp(r4, Operand(ODDBALL_TYPE)); | 4626 if (cc != eq) { |
4629 __ b(ne, &return_equal); | 4627 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE)); |
4630 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); | 4628 __ b(ge, slow); |
4631 __ cmp(r0, Operand(r2)); | 4629 // Normally here we fall through to return_equal, but undefined is |
4632 __ b(ne, &return_equal); | 4630 // special: (undefined == undefined) == true, but |
4633 if (cc == le) { | 4631 // (undefined <= undefined) == false! See ECMAScript 11.8.5. |
4634 __ mov(r0, Operand(GREATER)); // undefined <= undefined should fail. | 4632 if (cc == le || cc == ge) { |
4635 } else { | 4633 __ cmp(r4, Operand(ODDBALL_TYPE)); |
4636 __ mov(r0, Operand(LESS)); // undefined >= undefined should fail. | 4634 __ b(ne, &return_equal); |
| 4635 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
| 4636 __ cmp(r0, Operand(r2)); |
| 4637 __ b(ne, &return_equal); |
| 4638 if (cc == le) { |
| 4639 // undefined <= undefined should fail. |
| 4640 __ mov(r0, Operand(GREATER)); |
| 4641 } else { |
| 4642 // undefined >= undefined should fail. |
| 4643 __ mov(r0, Operand(LESS)); |
| 4644 } |
| 4645 __ mov(pc, Operand(lr)); // Return. |
4637 } | 4646 } |
4638 __ mov(pc, Operand(lr)); // Return. | |
4639 } | 4647 } |
4640 } | 4648 } |
4641 } | 4649 } |
| 4650 |
4642 __ bind(&return_equal); | 4651 __ bind(&return_equal); |
4643 if (cc == lt) { | 4652 if (cc == lt) { |
4644 __ mov(r0, Operand(GREATER)); // Things aren't less than themselves. | 4653 __ mov(r0, Operand(GREATER)); // Things aren't less than themselves. |
4645 } else if (cc == gt) { | 4654 } else if (cc == gt) { |
4646 __ mov(r0, Operand(LESS)); // Things aren't greater than themselves. | 4655 __ mov(r0, Operand(LESS)); // Things aren't greater than themselves. |
4647 } else { | 4656 } else { |
4648 __ mov(r0, Operand(0)); // Things are <=, >=, ==, === themselves. | 4657 __ mov(r0, Operand(0)); // Things are <=, >=, ==, === themselves. |
4649 } | 4658 } |
4650 __ mov(pc, Operand(lr)); // Return. | 4659 __ mov(pc, Operand(lr)); // Return. |
4651 | 4660 |
4652 // For less and greater we don't have to check for NaN since the result of | 4661 if (cc != eq || !never_nan_nan) { |
4653 // x < x is false regardless. For the others here is some code to check | 4662 // For less and greater we don't have to check for NaN since the result of |
4654 // for NaN. | 4663 // x < x is false regardless. For the others here is some code to check |
4655 if (cc != lt && cc != gt) { | 4664 // for NaN. |
4656 __ bind(&heap_number); | 4665 if (cc != lt && cc != gt) { |
4657 // It is a heap number, so return non-equal if it's NaN and equal if it's | 4666 __ bind(&heap_number); |
4658 // not NaN. | 4667 // It is a heap number, so return non-equal if it's NaN and equal if it's |
4659 // The representation of NaN values has all exponent bits (52..62) set, | 4668 // not NaN. |
4660 // and not all mantissa bits (0..51) clear. | 4669 // The representation of NaN values has all exponent bits (52..62) set, |
4661 // Read top bits of double representation (second word of value). | 4670 // and not all mantissa bits (0..51) clear. |
4662 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | 4671 // Read top bits of double representation (second word of value). |
4663 // Test that exponent bits are all set. | 4672 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
4664 __ and_(r3, r2, Operand(exp_mask_reg)); | 4673 // Test that exponent bits are all set. |
4665 __ cmp(r3, Operand(exp_mask_reg)); | 4674 __ and_(r3, r2, Operand(exp_mask_reg)); |
4666 __ b(ne, &return_equal); | 4675 __ cmp(r3, Operand(exp_mask_reg)); |
| 4676 __ b(ne, &return_equal); |
4667 | 4677 |
4668 // Shift out flag and all exponent bits, retaining only mantissa. | 4678 // Shift out flag and all exponent bits, retaining only mantissa. |
4669 __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord)); | 4679 __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord)); |
4670 // Or with all low-bits of mantissa. | 4680 // Or with all low-bits of mantissa. |
4671 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); | 4681 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); |
4672 __ orr(r0, r3, Operand(r2), SetCC); | 4682 __ orr(r0, r3, Operand(r2), SetCC); |
4673 // For equal we already have the right value in r0: Return zero (equal) | 4683 // For equal we already have the right value in r0: Return zero (equal) |
4674 // if all bits in mantissa are zero (it's an Infinity) and non-zero if not | 4684 // if all bits in mantissa are zero (it's an Infinity) and non-zero if not |
4675 // (it's a NaN). For <= and >= we need to load r0 with the failing value | 4685 // (it's a NaN). For <= and >= we need to load r0 with the failing value |
4676 // if it's a NaN. | 4686 // if it's a NaN. |
4677 if (cc != eq) { | 4687 if (cc != eq) { |
4678 // All-zero means Infinity means equal. | 4688 // All-zero means Infinity means equal. |
4679 __ mov(pc, Operand(lr), LeaveCC, eq); // Return equal | 4689 __ mov(pc, Operand(lr), LeaveCC, eq); // Return equal |
4680 if (cc == le) { | 4690 if (cc == le) { |
4681 __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail. | 4691 __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail. |
4682 } else { | 4692 } else { |
4683 __ mov(r0, Operand(LESS)); // NaN >= NaN should fail. | 4693 __ mov(r0, Operand(LESS)); // NaN >= NaN should fail. |
| 4694 } |
4684 } | 4695 } |
| 4696 __ mov(pc, Operand(lr)); // Return. |
4685 } | 4697 } |
4686 __ mov(pc, Operand(lr)); // Return. | 4698 // No fall through here. |
4687 } | 4699 } |
4688 // No fall through here. | |
4689 | 4700 |
4690 __ bind(¬_identical); | 4701 __ bind(¬_identical); |
4691 } | 4702 } |
4692 | 4703 |
4693 | 4704 |
4694 // See comment at call site. | 4705 // See comment at call site. |
4695 static void EmitSmiNonsmiComparison(MacroAssembler* masm, | 4706 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
4696 Label* rhs_not_nan, | 4707 Label* rhs_not_nan, |
4697 Label* slow, | 4708 Label* slow, |
4698 bool strict) { | 4709 bool strict) { |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4904 __ ldr(r3, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize)); | 4915 __ ldr(r3, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize)); |
4905 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize)); | 4916 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize)); |
4906 __ ldr(r0, FieldMemOperand(r0, HeapNumber::kValueOffset)); | 4917 __ ldr(r0, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
4907 __ jmp(both_loaded_as_doubles); | 4918 __ jmp(both_loaded_as_doubles); |
4908 } | 4919 } |
4909 | 4920 |
4910 | 4921 |
4911 // Fast negative check for symbol-to-symbol equality. | 4922 // Fast negative check for symbol-to-symbol equality. |
4912 static void EmitCheckForSymbols(MacroAssembler* masm, Label* slow) { | 4923 static void EmitCheckForSymbols(MacroAssembler* masm, Label* slow) { |
4913 // r2 is object type of r0. | 4924 // r2 is object type of r0. |
4914 __ tst(r2, Operand(kIsNotStringMask)); | 4925 // Ensure that no non-strings have the symbol bit set. |
4915 __ b(ne, slow); | 4926 ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE); |
| 4927 ASSERT(kSymbolTag != 0); |
4916 __ tst(r2, Operand(kIsSymbolMask)); | 4928 __ tst(r2, Operand(kIsSymbolMask)); |
4917 __ b(eq, slow); | 4929 __ b(eq, slow); |
4918 __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE); | 4930 ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); |
4919 __ b(ge, slow); | 4931 ldrb(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); |
4920 __ tst(r3, Operand(kIsSymbolMask)); | 4932 __ tst(r3, Operand(kIsSymbolMask)); |
4921 __ b(eq, slow); | 4933 __ b(eq, slow); |
4922 | 4934 |
4923 // Both are symbols. We already checked they weren't the same pointer | 4935 // Both are symbols. We already checked they weren't the same pointer |
4924 // so they are not equal. | 4936 // so they are not equal. |
4925 __ mov(r0, Operand(1)); // Non-zero indicates not equal. | 4937 __ mov(r0, Operand(1)); // Non-zero indicates not equal. |
4926 __ mov(pc, Operand(lr)); // Return. | 4938 __ mov(pc, Operand(lr)); // Return. |
4927 } | 4939 } |
4928 | 4940 |
4929 | 4941 |
4930 // On entry r0 and r1 are the things to be compared. On exit r0 is 0, | 4942 // On entry r0 and r1 are the things to be compared. On exit r0 is 0, |
4931 // positive or negative to indicate the result of the comparison. | 4943 // positive or negative to indicate the result of the comparison. |
4932 void CompareStub::Generate(MacroAssembler* masm) { | 4944 void CompareStub::Generate(MacroAssembler* masm) { |
4933 Label slow; // Call builtin. | 4945 Label slow; // Call builtin. |
4934 Label not_smis, both_loaded_as_doubles, rhs_not_nan; | 4946 Label not_smis, both_loaded_as_doubles, rhs_not_nan; |
4935 | 4947 |
4936 // NOTICE! This code is only reached after a smi-fast-case check, so | 4948 // NOTICE! This code is only reached after a smi-fast-case check, so |
4937 // it is certain that at least one operand isn't a smi. | 4949 // it is certain that at least one operand isn't a smi. |
4938 | 4950 |
4939 // Handle the case where the objects are identical. Either returns the answer | 4951 // Handle the case where the objects are identical. Either returns the answer |
4940 // or goes to slow. Only falls through if the objects were not identical. | 4952 // or goes to slow. Only falls through if the objects were not identical. |
4941 EmitIdenticalObjectComparison(masm, &slow, cc_); | 4953 EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); |
4942 | 4954 |
4943 // If either is a Smi (we know that not both are), then they can only | 4955 // If either is a Smi (we know that not both are), then they can only |
4944 // be strictly equal if the other is a HeapNumber. | 4956 // be strictly equal if the other is a HeapNumber. |
4945 ASSERT_EQ(0, kSmiTag); | 4957 ASSERT_EQ(0, kSmiTag); |
4946 ASSERT_EQ(0, Smi::FromInt(0)); | 4958 ASSERT_EQ(0, Smi::FromInt(0)); |
4947 __ and_(r2, r0, Operand(r1)); | 4959 __ and_(r2, r0, Operand(r1)); |
4948 __ tst(r2, Operand(kSmiTagMask)); | 4960 __ tst(r2, Operand(kSmiTagMask)); |
4949 __ b(ne, ¬_smis); | 4961 __ b(ne, ¬_smis); |
4950 // One operand is a smi. EmitSmiNonsmiComparison generates code that can: | 4962 // One operand is a smi. EmitSmiNonsmiComparison generates code that can: |
4951 // 1) Return the answer. | 4963 // 1) Return the answer. |
(...skipping 1528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6480 // Slow-case: Non-function called. | 6492 // Slow-case: Non-function called. |
6481 __ bind(&slow); | 6493 __ bind(&slow); |
6482 __ mov(r0, Operand(argc_)); // Setup the number of arguments. | 6494 __ mov(r0, Operand(argc_)); // Setup the number of arguments. |
6483 __ mov(r2, Operand(0)); | 6495 __ mov(r2, Operand(0)); |
6484 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); | 6496 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); |
6485 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), | 6497 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), |
6486 RelocInfo::CODE_TARGET); | 6498 RelocInfo::CODE_TARGET); |
6487 } | 6499 } |
6488 | 6500 |
6489 | 6501 |
| 6502 const char* CompareStub::GetName() { |
| 6503 switch(cc_) { |
| 6504 case lt: return "CompareStub_LT"; |
| 6505 case gt: return "CompareStub_GT"; |
| 6506 case le: return "CompareStub_LE"; |
| 6507 case ge: return "CompareStub_GE"; |
| 6508 case ne: { |
| 6509 if (strict_) { |
| 6510 if (never_nan_nan_) { |
| 6511 return "CompareStub_NE_STRICT_NO_NAN"; |
| 6512 } else { |
| 6513 return "CompareStub_NE_STRICT"; |
| 6514 } |
| 6515 } else { |
| 6516 if (never_nan_nan_) { |
| 6517 return "CompareStub_NE_NO_NAN"; |
| 6518 } else { |
| 6519 return "CompareStub_NE"; |
| 6520 } |
| 6521 } |
| 6522 } |
| 6523 case eq: { |
| 6524 if (strict_) { |
| 6525 if (never_nan_nan_) { |
| 6526 return "CompareStub_EQ_STRICT_NO_NAN"; |
| 6527 } else { |
| 6528 return "CompareStub_EQ_STRICT"; |
| 6529 } |
| 6530 } else { |
| 6531 if (never_nan_nan_) { |
| 6532 return "CompareStub_EQ_NO_NAN"; |
| 6533 } else { |
| 6534 return "CompareStub_EQ"; |
| 6535 } |
| 6536 } |
| 6537 } |
| 6538 default: return "CompareStub"; |
| 6539 } |
| 6540 } |
| 6541 |
| 6542 |
6490 int CompareStub::MinorKey() { | 6543 int CompareStub::MinorKey() { |
6491 // Encode the two parameters in a unique 16 bit value. | 6544 // Encode the three parameters in a unique 16 bit value. |
6492 ASSERT(static_cast<unsigned>(cc_) >> 28 < (1 << 15)); | 6545 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); |
6493 return (static_cast<unsigned>(cc_) >> 27) | (strict_ ? 1 : 0); | 6546 int nnn_value = (never_nan_nan_ ? 2 : 0); |
| 6547 if (cc_ != eq) nnn_value = 0; // Avoid duplicate stubs. |
| 6548 return (static_cast<unsigned>(cc_) >> 26) | nnn_value | (strict_ ? 1 : 0); |
6494 } | 6549 } |
6495 | 6550 |
6496 | 6551 |
6497 #undef __ | 6552 #undef __ |
6498 | 6553 |
6499 } } // namespace v8::internal | 6554 } } // namespace v8::internal |
OLD | NEW |