OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 Loading... |
34 #include "regexp-macro-assembler.h" | 34 #include "regexp-macro-assembler.h" |
35 | 35 |
36 namespace v8 { | 36 namespace v8 { |
37 namespace internal { | 37 namespace internal { |
38 | 38 |
39 | 39 |
40 #define __ ACCESS_MASM(masm) | 40 #define __ ACCESS_MASM(masm) |
41 | 41 |
42 static void EmitIdenticalObjectComparison(MacroAssembler* masm, | 42 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
43 Label* slow, | 43 Label* slow, |
44 Condition cc, | 44 Condition cond, |
45 bool never_nan_nan); | 45 bool never_nan_nan); |
46 static void EmitSmiNonsmiComparison(MacroAssembler* masm, | 46 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
47 Register lhs, | 47 Register lhs, |
48 Register rhs, | 48 Register rhs, |
49 Label* lhs_not_nan, | 49 Label* lhs_not_nan, |
50 Label* slow, | 50 Label* slow, |
51 bool strict); | 51 bool strict); |
52 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc); | 52 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cond); |
53 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, | 53 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, |
54 Register lhs, | 54 Register lhs, |
55 Register rhs); | 55 Register rhs); |
56 | 56 |
57 | 57 |
58 void FastNewClosureStub::Generate(MacroAssembler* masm) { | 58 void FastNewClosureStub::Generate(MacroAssembler* masm) { |
59 // Create a new closure from the given function info in new | 59 // Create a new closure from the given function info in new |
60 // space. Set the context to the current context in cp. | 60 // space. Set the context to the current context in cp. |
61 Label gc; | 61 Label gc; |
62 | 62 |
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset)); | 537 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset)); |
538 __ Ret(); | 538 __ Ret(); |
539 } | 539 } |
540 | 540 |
541 | 541 |
542 // Handle the case where the lhs and rhs are the same object. | 542 // Handle the case where the lhs and rhs are the same object. |
543 // Equality is almost reflexive (everything but NaN), so this is a test | 543 // Equality is almost reflexive (everything but NaN), so this is a test |
544 // for "identity and not NaN". | 544 // for "identity and not NaN". |
545 static void EmitIdenticalObjectComparison(MacroAssembler* masm, | 545 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
546 Label* slow, | 546 Label* slow, |
547 Condition cc, | 547 Condition cond, |
548 bool never_nan_nan) { | 548 bool never_nan_nan) { |
549 Label not_identical; | 549 Label not_identical; |
550 Label heap_number, return_equal; | 550 Label heap_number, return_equal; |
551 __ cmp(r0, r1); | 551 __ cmp(r0, r1); |
552 __ b(ne, ¬_identical); | 552 __ b(ne, ¬_identical); |
553 | 553 |
554 // The two objects are identical. If we know that one of them isn't NaN then | 554 // The two objects are identical. If we know that one of them isn't NaN then |
555 // we now know they test equal. | 555 // we now know they test equal. |
556 if (cc != eq || !never_nan_nan) { | 556 if (cond != eq || !never_nan_nan) { |
557 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), | 557 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), |
558 // so we do the second best thing - test it ourselves. | 558 // so we do the second best thing - test it ourselves. |
559 // They are both equal and they are not both Smis so both of them are not | 559 // They are both equal and they are not both Smis so both of them are not |
560 // Smis. If it's not a heap number, then return equal. | 560 // Smis. If it's not a heap number, then return equal. |
561 if (cc == lt || cc == gt) { | 561 if (cond == lt || cond == gt) { |
562 __ CompareObjectType(r0, r4, r4, FIRST_JS_OBJECT_TYPE); | 562 __ CompareObjectType(r0, r4, r4, FIRST_JS_OBJECT_TYPE); |
563 __ b(ge, slow); | 563 __ b(ge, slow); |
564 } else { | 564 } else { |
565 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); | 565 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); |
566 __ b(eq, &heap_number); | 566 __ b(eq, &heap_number); |
567 // Comparing JS objects with <=, >= is complicated. | 567 // Comparing JS objects with <=, >= is complicated. |
568 if (cc != eq) { | 568 if (cond != eq) { |
569 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE)); | 569 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE)); |
570 __ b(ge, slow); | 570 __ b(ge, slow); |
571 // Normally here we fall through to return_equal, but undefined is | 571 // Normally here we fall through to return_equal, but undefined is |
572 // special: (undefined == undefined) == true, but | 572 // special: (undefined == undefined) == true, but |
573 // (undefined <= undefined) == false! See ECMAScript 11.8.5. | 573 // (undefined <= undefined) == false! See ECMAScript 11.8.5. |
574 if (cc == le || cc == ge) { | 574 if (cond == le || cond == ge) { |
575 __ cmp(r4, Operand(ODDBALL_TYPE)); | 575 __ cmp(r4, Operand(ODDBALL_TYPE)); |
576 __ b(ne, &return_equal); | 576 __ b(ne, &return_equal); |
577 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); | 577 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
578 __ cmp(r0, r2); | 578 __ cmp(r0, r2); |
579 __ b(ne, &return_equal); | 579 __ b(ne, &return_equal); |
580 if (cc == le) { | 580 if (cond == le) { |
581 // undefined <= undefined should fail. | 581 // undefined <= undefined should fail. |
582 __ mov(r0, Operand(GREATER)); | 582 __ mov(r0, Operand(GREATER)); |
583 } else { | 583 } else { |
584 // undefined >= undefined should fail. | 584 // undefined >= undefined should fail. |
585 __ mov(r0, Operand(LESS)); | 585 __ mov(r0, Operand(LESS)); |
586 } | 586 } |
587 __ Ret(); | 587 __ Ret(); |
588 } | 588 } |
589 } | 589 } |
590 } | 590 } |
591 } | 591 } |
592 | 592 |
593 __ bind(&return_equal); | 593 __ bind(&return_equal); |
594 if (cc == lt) { | 594 if (cond == lt) { |
595 __ mov(r0, Operand(GREATER)); // Things aren't less than themselves. | 595 __ mov(r0, Operand(GREATER)); // Things aren't less than themselves. |
596 } else if (cc == gt) { | 596 } else if (cond == gt) { |
597 __ mov(r0, Operand(LESS)); // Things aren't greater than themselves. | 597 __ mov(r0, Operand(LESS)); // Things aren't greater than themselves. |
598 } else { | 598 } else { |
599 __ mov(r0, Operand(EQUAL)); // Things are <=, >=, ==, === themselves. | 599 __ mov(r0, Operand(EQUAL)); // Things are <=, >=, ==, === themselves. |
600 } | 600 } |
601 __ Ret(); | 601 __ Ret(); |
602 | 602 |
603 if (cc != eq || !never_nan_nan) { | 603 if (cond != eq || !never_nan_nan) { |
604 // For less and greater we don't have to check for NaN since the result of | 604 // For less and greater we don't have to check for NaN since the result of |
605 // x < x is false regardless. For the others here is some code to check | 605 // x < x is false regardless. For the others here is some code to check |
606 // for NaN. | 606 // for NaN. |
607 if (cc != lt && cc != gt) { | 607 if (cond != lt && cond != gt) { |
608 __ bind(&heap_number); | 608 __ bind(&heap_number); |
609 // It is a heap number, so return non-equal if it's NaN and equal if it's | 609 // It is a heap number, so return non-equal if it's NaN and equal if it's |
610 // not NaN. | 610 // not NaN. |
611 | 611 |
612 // The representation of NaN values has all exponent bits (52..62) set, | 612 // The representation of NaN values has all exponent bits (52..62) set, |
613 // and not all mantissa bits (0..51) clear. | 613 // and not all mantissa bits (0..51) clear. |
614 // Read top bits of double representation (second word of value). | 614 // Read top bits of double representation (second word of value). |
615 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | 615 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
616 // Test that exponent bits are all set. | 616 // Test that exponent bits are all set. |
617 __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits); | 617 __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits); |
618 // NaNs have all-one exponents so they sign extend to -1. | 618 // NaNs have all-one exponents so they sign extend to -1. |
619 __ cmp(r3, Operand(-1)); | 619 __ cmp(r3, Operand(-1)); |
620 __ b(ne, &return_equal); | 620 __ b(ne, &return_equal); |
621 | 621 |
622 // Shift out flag and all exponent bits, retaining only mantissa. | 622 // Shift out flag and all exponent bits, retaining only mantissa. |
623 __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord)); | 623 __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord)); |
624 // Or with all low-bits of mantissa. | 624 // Or with all low-bits of mantissa. |
625 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); | 625 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); |
626 __ orr(r0, r3, Operand(r2), SetCC); | 626 __ orr(r0, r3, Operand(r2), SetCC); |
627 // For equal we already have the right value in r0: Return zero (equal) | 627 // For equal we already have the right value in r0: Return zero (equal) |
628 // if all bits in mantissa are zero (it's an Infinity) and non-zero if | 628 // if all bits in mantissa are zero (it's an Infinity) and non-zero if |
629 // not (it's a NaN). For <= and >= we need to load r0 with the failing | 629 // not (it's a NaN). For <= and >= we need to load r0 with the failing |
630 // value if it's a NaN. | 630 // value if it's a NaN. |
631 if (cc != eq) { | 631 if (cond != eq) { |
632 // All-zero means Infinity means equal. | 632 // All-zero means Infinity means equal. |
633 __ Ret(eq); | 633 __ Ret(eq); |
634 if (cc == le) { | 634 if (cond == le) { |
635 __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail. | 635 __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail. |
636 } else { | 636 } else { |
637 __ mov(r0, Operand(LESS)); // NaN >= NaN should fail. | 637 __ mov(r0, Operand(LESS)); // NaN >= NaN should fail. |
638 } | 638 } |
639 } | 639 } |
640 __ Ret(); | 640 __ Ret(); |
641 } | 641 } |
642 // No fall through here. | 642 // No fall through here. |
643 } | 643 } |
644 | 644 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
731 // Convert rhs to a double in r0, r1. | 731 // Convert rhs to a double in r0, r1. |
732 __ mov(r7, Operand(rhs)); | 732 __ mov(r7, Operand(rhs)); |
733 ConvertToDoubleStub stub2(r1, r0, r7, r6); | 733 ConvertToDoubleStub stub2(r1, r0, r7, r6); |
734 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); | 734 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); |
735 __ pop(lr); | 735 __ pop(lr); |
736 } | 736 } |
737 // Fall through to both_loaded_as_doubles. | 737 // Fall through to both_loaded_as_doubles. |
738 } | 738 } |
739 | 739 |
740 | 740 |
741 void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cc) { | 741 void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cond) { |
742 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); | 742 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); |
743 Register rhs_exponent = exp_first ? r0 : r1; | 743 Register rhs_exponent = exp_first ? r0 : r1; |
744 Register lhs_exponent = exp_first ? r2 : r3; | 744 Register lhs_exponent = exp_first ? r2 : r3; |
745 Register rhs_mantissa = exp_first ? r1 : r0; | 745 Register rhs_mantissa = exp_first ? r1 : r0; |
746 Register lhs_mantissa = exp_first ? r3 : r2; | 746 Register lhs_mantissa = exp_first ? r3 : r2; |
747 Label one_is_nan, neither_is_nan; | 747 Label one_is_nan, neither_is_nan; |
748 | 748 |
749 __ Sbfx(r4, | 749 __ Sbfx(r4, |
750 lhs_exponent, | 750 lhs_exponent, |
751 HeapNumber::kExponentShift, | 751 HeapNumber::kExponentShift, |
(...skipping 19 matching lines...) Expand all Loading... |
771 __ mov(r4, | 771 __ mov(r4, |
772 Operand(rhs_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord), | 772 Operand(rhs_exponent, LSL, HeapNumber::kNonMantissaBitsInTopWord), |
773 SetCC); | 773 SetCC); |
774 __ b(ne, &one_is_nan); | 774 __ b(ne, &one_is_nan); |
775 __ cmp(rhs_mantissa, Operand(0, RelocInfo::NONE)); | 775 __ cmp(rhs_mantissa, Operand(0, RelocInfo::NONE)); |
776 __ b(eq, &neither_is_nan); | 776 __ b(eq, &neither_is_nan); |
777 | 777 |
778 __ bind(&one_is_nan); | 778 __ bind(&one_is_nan); |
779 // NaN comparisons always fail. | 779 // NaN comparisons always fail. |
780 // Load whatever we need in r0 to make the comparison fail. | 780 // Load whatever we need in r0 to make the comparison fail. |
781 if (cc == lt || cc == le) { | 781 if (cond == lt || cond == le) { |
782 __ mov(r0, Operand(GREATER)); | 782 __ mov(r0, Operand(GREATER)); |
783 } else { | 783 } else { |
784 __ mov(r0, Operand(LESS)); | 784 __ mov(r0, Operand(LESS)); |
785 } | 785 } |
786 __ Ret(); | 786 __ Ret(); |
787 | 787 |
788 __ bind(&neither_is_nan); | 788 __ bind(&neither_is_nan); |
789 } | 789 } |
790 | 790 |
791 | 791 |
792 // See comment at call site. | 792 // See comment at call site. |
793 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) { | 793 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, |
| 794 Condition cond) { |
794 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); | 795 bool exp_first = (HeapNumber::kExponentOffset == HeapNumber::kValueOffset); |
795 Register rhs_exponent = exp_first ? r0 : r1; | 796 Register rhs_exponent = exp_first ? r0 : r1; |
796 Register lhs_exponent = exp_first ? r2 : r3; | 797 Register lhs_exponent = exp_first ? r2 : r3; |
797 Register rhs_mantissa = exp_first ? r1 : r0; | 798 Register rhs_mantissa = exp_first ? r1 : r0; |
798 Register lhs_mantissa = exp_first ? r3 : r2; | 799 Register lhs_mantissa = exp_first ? r3 : r2; |
799 | 800 |
800 // r0, r1, r2, r3 have the two doubles. Neither is a NaN. | 801 // r0, r1, r2, r3 have the two doubles. Neither is a NaN. |
801 if (cc == eq) { | 802 if (cond == eq) { |
802 // Doubles are not equal unless they have the same bit pattern. | 803 // Doubles are not equal unless they have the same bit pattern. |
803 // Exception: 0 and -0. | 804 // Exception: 0 and -0. |
804 __ cmp(rhs_mantissa, Operand(lhs_mantissa)); | 805 __ cmp(rhs_mantissa, Operand(lhs_mantissa)); |
805 __ orr(r0, rhs_mantissa, Operand(lhs_mantissa), LeaveCC, ne); | 806 __ orr(r0, rhs_mantissa, Operand(lhs_mantissa), LeaveCC, ne); |
806 // Return non-zero if the numbers are unequal. | 807 // Return non-zero if the numbers are unequal. |
807 __ Ret(ne); | 808 __ Ret(ne); |
808 | 809 |
809 __ sub(r0, rhs_exponent, Operand(lhs_exponent), SetCC); | 810 __ sub(r0, rhs_exponent, Operand(lhs_exponent), SetCC); |
810 // If exponents are equal then return 0. | 811 // If exponents are equal then return 0. |
811 __ Ret(eq); | 812 __ Ret(eq); |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1080 __ orr(r2, r1, r0); | 1081 __ orr(r2, r1, r0); |
1081 __ tst(r2, Operand(kSmiTagMask)); | 1082 __ tst(r2, Operand(kSmiTagMask)); |
1082 __ b(ne, ¬_two_smis); | 1083 __ b(ne, ¬_two_smis); |
1083 __ mov(r1, Operand(r1, ASR, 1)); | 1084 __ mov(r1, Operand(r1, ASR, 1)); |
1084 __ sub(r0, r1, Operand(r0, ASR, 1)); | 1085 __ sub(r0, r1, Operand(r0, ASR, 1)); |
1085 __ Ret(); | 1086 __ Ret(); |
1086 __ bind(¬_two_smis); | 1087 __ bind(¬_two_smis); |
1087 } else if (FLAG_debug_code) { | 1088 } else if (FLAG_debug_code) { |
1088 __ orr(r2, r1, r0); | 1089 __ orr(r2, r1, r0); |
1089 __ tst(r2, Operand(kSmiTagMask)); | 1090 __ tst(r2, Operand(kSmiTagMask)); |
1090 __ Assert(nz, "CompareStub: unexpected smi operands."); | 1091 __ Assert(ne, "CompareStub: unexpected smi operands."); |
1091 } | 1092 } |
1092 | 1093 |
1093 // NOTICE! This code is only reached after a smi-fast-case check, so | 1094 // NOTICE! This code is only reached after a smi-fast-case check, so |
1094 // it is certain that at least one operand isn't a smi. | 1095 // it is certain that at least one operand isn't a smi. |
1095 | 1096 |
1096 // Handle the case where the objects are identical. Either returns the answer | 1097 // Handle the case where the objects are identical. Either returns the answer |
1097 // or goes to slow. Only falls through if the objects were not identical. | 1098 // or goes to slow. Only falls through if the objects were not identical. |
1098 EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); | 1099 EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); |
1099 | 1100 |
1100 // If either is a Smi (we know that not both are), then they can only | 1101 // If either is a Smi (we know that not both are), then they can only |
(...skipping 2691 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3792 STATIC_ASSERT(kSmiTag == 0); | 3793 STATIC_ASSERT(kSmiTag == 0); |
3793 __ tst(r0, Operand(kSmiTagMask)); | 3794 __ tst(r0, Operand(kSmiTagMask)); |
3794 __ b(eq, &runtime); | 3795 __ b(eq, &runtime); |
3795 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); | 3796 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); |
3796 __ b(ne, &runtime); | 3797 __ b(ne, &runtime); |
3797 | 3798 |
3798 // Check that the RegExp has been compiled (data contains a fixed array). | 3799 // Check that the RegExp has been compiled (data contains a fixed array). |
3799 __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset)); | 3800 __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset)); |
3800 if (FLAG_debug_code) { | 3801 if (FLAG_debug_code) { |
3801 __ tst(regexp_data, Operand(kSmiTagMask)); | 3802 __ tst(regexp_data, Operand(kSmiTagMask)); |
3802 __ Check(nz, "Unexpected type for RegExp data, FixedArray expected"); | 3803 __ Check(ne, "Unexpected type for RegExp data, FixedArray expected"); |
3803 __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE); | 3804 __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE); |
3804 __ Check(eq, "Unexpected type for RegExp data, FixedArray expected"); | 3805 __ Check(eq, "Unexpected type for RegExp data, FixedArray expected"); |
3805 } | 3806 } |
3806 | 3807 |
3807 // regexp_data: RegExp data (FixedArray) | 3808 // regexp_data: RegExp data (FixedArray) |
3808 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | 3809 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |
3809 __ ldr(r0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); | 3810 __ ldr(r0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); |
3810 __ cmp(r0, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); | 3811 __ cmp(r0, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); |
3811 __ b(ne, &runtime); | 3812 __ b(ne, &runtime); |
3812 | 3813 |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3895 __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset)); | 3896 __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset)); |
3896 __ LoadRoot(r1, Heap::kEmptyStringRootIndex); | 3897 __ LoadRoot(r1, Heap::kEmptyStringRootIndex); |
3897 __ cmp(r0, r1); | 3898 __ cmp(r0, r1); |
3898 __ b(ne, &runtime); | 3899 __ b(ne, &runtime); |
3899 __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); | 3900 __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); |
3900 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); | 3901 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); |
3901 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); | 3902 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); |
3902 // Is first part a flat string? | 3903 // Is first part a flat string? |
3903 STATIC_ASSERT(kSeqStringTag == 0); | 3904 STATIC_ASSERT(kSeqStringTag == 0); |
3904 __ tst(r0, Operand(kStringRepresentationMask)); | 3905 __ tst(r0, Operand(kStringRepresentationMask)); |
3905 __ b(nz, &runtime); | 3906 __ b(ne, &runtime); |
3906 | 3907 |
3907 __ bind(&seq_string); | 3908 __ bind(&seq_string); |
3908 // subject: Subject string | 3909 // subject: Subject string |
3909 // regexp_data: RegExp data (FixedArray) | 3910 // regexp_data: RegExp data (FixedArray) |
3910 // r0: Instance type of subject string | 3911 // r0: Instance type of subject string |
3911 STATIC_ASSERT(4 == kAsciiStringTag); | 3912 STATIC_ASSERT(4 == kAsciiStringTag); |
3912 STATIC_ASSERT(kTwoByteStringTag == 0); | 3913 STATIC_ASSERT(kTwoByteStringTag == 0); |
3913 // Find the code object based on the assumptions above. | 3914 // Find the code object based on the assumptions above. |
3914 __ and_(r0, r0, Operand(kStringEncodingMask)); | 3915 __ and_(r0, r0, Operand(kStringEncodingMask)); |
3915 __ mov(r3, Operand(r0, ASR, 2), SetCC); | 3916 __ mov(r3, Operand(r0, ASR, 2), SetCC); |
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4343 __ LoadRoot(ip, Heap::kEmptyStringRootIndex); | 4344 __ LoadRoot(ip, Heap::kEmptyStringRootIndex); |
4344 __ cmp(result_, Operand(ip)); | 4345 __ cmp(result_, Operand(ip)); |
4345 __ b(ne, &call_runtime_); | 4346 __ b(ne, &call_runtime_); |
4346 // Get the first of the two strings and load its instance type. | 4347 // Get the first of the two strings and load its instance type. |
4347 __ ldr(object_, FieldMemOperand(object_, ConsString::kFirstOffset)); | 4348 __ ldr(object_, FieldMemOperand(object_, ConsString::kFirstOffset)); |
4348 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); | 4349 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
4349 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); | 4350 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
4350 // If the first cons component is also non-flat, then go to runtime. | 4351 // If the first cons component is also non-flat, then go to runtime. |
4351 STATIC_ASSERT(kSeqStringTag == 0); | 4352 STATIC_ASSERT(kSeqStringTag == 0); |
4352 __ tst(result_, Operand(kStringRepresentationMask)); | 4353 __ tst(result_, Operand(kStringRepresentationMask)); |
4353 __ b(nz, &call_runtime_); | 4354 __ b(ne, &call_runtime_); |
4354 | 4355 |
4355 // Check for 1-byte or 2-byte string. | 4356 // Check for 1-byte or 2-byte string. |
4356 __ bind(&flat_string); | 4357 __ bind(&flat_string); |
4357 STATIC_ASSERT(kAsciiStringTag != 0); | 4358 STATIC_ASSERT(kAsciiStringTag != 0); |
4358 __ tst(result_, Operand(kStringEncodingMask)); | 4359 __ tst(result_, Operand(kStringEncodingMask)); |
4359 __ b(nz, &ascii_string); | 4360 __ b(ne, &ascii_string); |
4360 | 4361 |
4361 // 2-byte string. | 4362 // 2-byte string. |
4362 // Load the 2-byte character code into the result register. We can | 4363 // Load the 2-byte character code into the result register. We can |
4363 // add without shifting since the smi tag size is the log2 of the | 4364 // add without shifting since the smi tag size is the log2 of the |
4364 // number of bytes in a two-byte character. | 4365 // number of bytes in a two-byte character. |
4365 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1 && kSmiShiftSize == 0); | 4366 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1 && kSmiShiftSize == 0); |
4366 __ add(scratch_, object_, Operand(scratch_)); | 4367 __ add(scratch_, object_, Operand(scratch_)); |
4367 __ ldrh(result_, FieldMemOperand(scratch_, SeqTwoByteString::kHeaderSize)); | 4368 __ ldrh(result_, FieldMemOperand(scratch_, SeqTwoByteString::kHeaderSize)); |
4368 __ jmp(&got_char_code); | 4369 __ jmp(&got_char_code); |
4369 | 4370 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4434 // StringCharFromCodeGenerator | 4435 // StringCharFromCodeGenerator |
4435 | 4436 |
4436 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { | 4437 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { |
4437 // Fast case of Heap::LookupSingleCharacterStringFromCode. | 4438 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
4438 STATIC_ASSERT(kSmiTag == 0); | 4439 STATIC_ASSERT(kSmiTag == 0); |
4439 STATIC_ASSERT(kSmiShiftSize == 0); | 4440 STATIC_ASSERT(kSmiShiftSize == 0); |
4440 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); | 4441 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
4441 __ tst(code_, | 4442 __ tst(code_, |
4442 Operand(kSmiTagMask | | 4443 Operand(kSmiTagMask | |
4443 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); | 4444 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
4444 __ b(nz, &slow_case_); | 4445 __ b(ne, &slow_case_); |
4445 | 4446 |
4446 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); | 4447 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); |
4447 // At this point code register contains smi tagged ascii char code. | 4448 // At this point code register contains smi tagged ascii char code. |
4448 STATIC_ASSERT(kSmiTag == 0); | 4449 STATIC_ASSERT(kSmiTag == 0); |
4449 __ add(result_, result_, Operand(code_, LSL, kPointerSizeLog2 - kSmiTagSize)); | 4450 __ add(result_, result_, Operand(code_, LSL, kPointerSizeLog2 - kSmiTagSize)); |
4450 __ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); | 4451 __ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); |
4451 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 4452 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
4452 __ cmp(result_, Operand(ip)); | 4453 __ cmp(result_, Operand(ip)); |
4453 __ b(eq, &slow_case_); | 4454 __ b(eq, &slow_case_); |
4454 __ bind(&exit_); | 4455 __ bind(&exit_); |
(...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4881 void StringHelper::GenerateHashGetHash(MacroAssembler* masm, | 4882 void StringHelper::GenerateHashGetHash(MacroAssembler* masm, |
4882 Register hash) { | 4883 Register hash) { |
4883 // hash += hash << 3; | 4884 // hash += hash << 3; |
4884 __ add(hash, hash, Operand(hash, LSL, 3)); | 4885 __ add(hash, hash, Operand(hash, LSL, 3)); |
4885 // hash ^= hash >> 11; | 4886 // hash ^= hash >> 11; |
4886 __ eor(hash, hash, Operand(hash, ASR, 11)); | 4887 __ eor(hash, hash, Operand(hash, ASR, 11)); |
4887 // hash += hash << 15; | 4888 // hash += hash << 15; |
4888 __ add(hash, hash, Operand(hash, LSL, 15), SetCC); | 4889 __ add(hash, hash, Operand(hash, LSL, 15), SetCC); |
4889 | 4890 |
4890 // if (hash == 0) hash = 27; | 4891 // if (hash == 0) hash = 27; |
4891 __ mov(hash, Operand(27), LeaveCC, nz); | 4892 __ mov(hash, Operand(27), LeaveCC, ne); |
4892 } | 4893 } |
4893 | 4894 |
4894 | 4895 |
4895 void SubStringStub::Generate(MacroAssembler* masm) { | 4896 void SubStringStub::Generate(MacroAssembler* masm) { |
4896 Label runtime; | 4897 Label runtime; |
4897 | 4898 |
4898 // Stack frame on entry. | 4899 // Stack frame on entry. |
4899 // lr: return address | 4900 // lr: return address |
4900 // sp[0]: to | 4901 // sp[0]: to |
4901 // sp[4]: from | 4902 // sp[4]: from |
(...skipping 718 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5620 __ pop(r1); | 5621 __ pop(r1); |
5621 __ Jump(r2); | 5622 __ Jump(r2); |
5622 } | 5623 } |
5623 | 5624 |
5624 | 5625 |
5625 #undef __ | 5626 #undef __ |
5626 | 5627 |
5627 } } // namespace v8::internal | 5628 } } // namespace v8::internal |
5628 | 5629 |
5629 #endif // V8_TARGET_ARCH_ARM | 5630 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |