OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 797 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
808 case Token::SUB: | 808 case Token::SUB: |
809 if (inline_smi) { | 809 if (inline_smi) { |
810 JumpTarget done; | 810 JumpTarget done; |
811 Register rhs = frame_->PopToRegister(); | 811 Register rhs = frame_->PopToRegister(); |
812 Register lhs = frame_->PopToRegister(rhs); | 812 Register lhs = frame_->PopToRegister(rhs); |
813 Register scratch = VirtualFrame::scratch0(); | 813 Register scratch = VirtualFrame::scratch0(); |
814 __ orr(scratch, rhs, Operand(lhs)); | 814 __ orr(scratch, rhs, Operand(lhs)); |
815 // Check they are both small and positive. | 815 // Check they are both small and positive. |
816 __ tst(scratch, Operand(kSmiTagMask | 0xc0000000)); | 816 __ tst(scratch, Operand(kSmiTagMask | 0xc0000000)); |
817 ASSERT(rhs.is(r0) || lhs.is(r0)); // r0 is free now. | 817 ASSERT(rhs.is(r0) || lhs.is(r0)); // r0 is free now. |
818 ASSERT_EQ(0, kSmiTag); | 818 STATIC_ASSERT(kSmiTag == 0); |
819 if (op == Token::ADD) { | 819 if (op == Token::ADD) { |
820 __ add(r0, lhs, Operand(rhs), LeaveCC, eq); | 820 __ add(r0, lhs, Operand(rhs), LeaveCC, eq); |
821 } else { | 821 } else { |
822 __ sub(r0, lhs, Operand(rhs), LeaveCC, eq); | 822 __ sub(r0, lhs, Operand(rhs), LeaveCC, eq); |
823 } | 823 } |
824 done.Branch(eq); | 824 done.Branch(eq); |
825 GenericBinaryOpStub stub(op, overwrite_mode, lhs, rhs, constant_rhs); | 825 GenericBinaryOpStub stub(op, overwrite_mode, lhs, rhs, constant_rhs); |
826 frame_->SpillAll(); | 826 frame_->SpillAll(); |
827 frame_->CallStub(&stub, 0); | 827 frame_->CallStub(&stub, 0); |
828 done.Bind(); | 828 done.Bind(); |
(...skipping 27 matching lines...) Expand all Loading... |
856 } else { | 856 } else { |
857 cond = al; | 857 cond = al; |
858 } | 858 } |
859 ASSERT(rhs.is(r0) || lhs.is(r0)); // r0 is free now. | 859 ASSERT(rhs.is(r0) || lhs.is(r0)); // r0 is free now. |
860 if (op == Token::BIT_OR) { | 860 if (op == Token::BIT_OR) { |
861 __ orr(r0, lhs, Operand(rhs), LeaveCC, cond); | 861 __ orr(r0, lhs, Operand(rhs), LeaveCC, cond); |
862 } else if (op == Token::BIT_AND) { | 862 } else if (op == Token::BIT_AND) { |
863 __ and_(r0, lhs, Operand(rhs), LeaveCC, cond); | 863 __ and_(r0, lhs, Operand(rhs), LeaveCC, cond); |
864 } else { | 864 } else { |
865 ASSERT(op == Token::BIT_XOR); | 865 ASSERT(op == Token::BIT_XOR); |
866 ASSERT_EQ(0, kSmiTag); | 866 STATIC_ASSERT(kSmiTag == 0); |
867 __ eor(r0, lhs, Operand(rhs), LeaveCC, cond); | 867 __ eor(r0, lhs, Operand(rhs), LeaveCC, cond); |
868 } | 868 } |
869 if (cond != al) { | 869 if (cond != al) { |
870 JumpTarget done; | 870 JumpTarget done; |
871 done.Branch(cond); | 871 done.Branch(cond); |
872 GenericBinaryOpStub stub(op, overwrite_mode, lhs, rhs, constant_rhs); | 872 GenericBinaryOpStub stub(op, overwrite_mode, lhs, rhs, constant_rhs); |
873 frame_->SpillAll(); | 873 frame_->SpillAll(); |
874 frame_->CallStub(&stub, 0); | 874 frame_->CallStub(&stub, 0); |
875 done.Bind(); | 875 done.Bind(); |
876 } | 876 } |
(...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1513 // sp[0]: receiver - in the receiver_reg register. | 1513 // sp[0]: receiver - in the receiver_reg register. |
1514 // sp[1]: applicand.apply | 1514 // sp[1]: applicand.apply |
1515 // sp[2]: applicand. | 1515 // sp[2]: applicand. |
1516 | 1516 |
1517 // Check that the receiver really is a JavaScript object. | 1517 // Check that the receiver really is a JavaScript object. |
1518 __ BranchOnSmi(receiver_reg, &build_args); | 1518 __ BranchOnSmi(receiver_reg, &build_args); |
1519 // We allow all JSObjects including JSFunctions. As long as | 1519 // We allow all JSObjects including JSFunctions. As long as |
1520 // JS_FUNCTION_TYPE is the last instance type and it is right | 1520 // JS_FUNCTION_TYPE is the last instance type and it is right |
1521 // after LAST_JS_OBJECT_TYPE, we do not have to check the upper | 1521 // after LAST_JS_OBJECT_TYPE, we do not have to check the upper |
1522 // bound. | 1522 // bound. |
1523 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 1523 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
1524 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | 1524 STATIC_ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); |
1525 __ CompareObjectType(receiver_reg, r2, r3, FIRST_JS_OBJECT_TYPE); | 1525 __ CompareObjectType(receiver_reg, r2, r3, FIRST_JS_OBJECT_TYPE); |
1526 __ b(lt, &build_args); | 1526 __ b(lt, &build_args); |
1527 | 1527 |
1528 // Check that applicand.apply is Function.prototype.apply. | 1528 // Check that applicand.apply is Function.prototype.apply. |
1529 __ ldr(r0, MemOperand(sp, kPointerSize)); | 1529 __ ldr(r0, MemOperand(sp, kPointerSize)); |
1530 __ BranchOnSmi(r0, &build_args); | 1530 __ BranchOnSmi(r0, &build_args); |
1531 __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE); | 1531 __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE); |
1532 __ b(ne, &build_args); | 1532 __ b(ne, &build_args); |
1533 __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset)); | 1533 __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset)); |
1534 Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply)); | 1534 Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply)); |
(...skipping 1068 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2603 function_return_is_shadowed_ = function_return_was_shadowed; | 2603 function_return_is_shadowed_ = function_return_was_shadowed; |
2604 | 2604 |
2605 // Get an external reference to the handler address. | 2605 // Get an external reference to the handler address. |
2606 ExternalReference handler_address(Top::k_handler_address); | 2606 ExternalReference handler_address(Top::k_handler_address); |
2607 | 2607 |
2608 // If we can fall off the end of the try block, unlink from try chain. | 2608 // If we can fall off the end of the try block, unlink from try chain. |
2609 if (has_valid_frame()) { | 2609 if (has_valid_frame()) { |
2610 // The next handler address is on top of the frame. Unlink from | 2610 // The next handler address is on top of the frame. Unlink from |
2611 // the handler list and drop the rest of this handler from the | 2611 // the handler list and drop the rest of this handler from the |
2612 // frame. | 2612 // frame. |
2613 ASSERT(StackHandlerConstants::kNextOffset == 0); | 2613 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
2614 frame_->EmitPop(r1); | 2614 frame_->EmitPop(r1); |
2615 __ mov(r3, Operand(handler_address)); | 2615 __ mov(r3, Operand(handler_address)); |
2616 __ str(r1, MemOperand(r3)); | 2616 __ str(r1, MemOperand(r3)); |
2617 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2617 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
2618 if (has_unlinks) { | 2618 if (has_unlinks) { |
2619 exit.Jump(); | 2619 exit.Jump(); |
2620 } | 2620 } |
2621 } | 2621 } |
2622 | 2622 |
2623 // Generate unlink code for the (formerly) shadowing labels that have been | 2623 // Generate unlink code for the (formerly) shadowing labels that have been |
2624 // jumped to. Deallocate each shadow target. | 2624 // jumped to. Deallocate each shadow target. |
2625 for (int i = 0; i < shadows.length(); i++) { | 2625 for (int i = 0; i < shadows.length(); i++) { |
2626 if (shadows[i]->is_linked()) { | 2626 if (shadows[i]->is_linked()) { |
2627 // Unlink from try chain; | 2627 // Unlink from try chain; |
2628 shadows[i]->Bind(); | 2628 shadows[i]->Bind(); |
2629 // Because we can be jumping here (to spilled code) from unspilled | 2629 // Because we can be jumping here (to spilled code) from unspilled |
2630 // code, we need to reestablish a spilled frame at this block. | 2630 // code, we need to reestablish a spilled frame at this block. |
2631 frame_->SpillAll(); | 2631 frame_->SpillAll(); |
2632 | 2632 |
2633 // Reload sp from the top handler, because some statements that we | 2633 // Reload sp from the top handler, because some statements that we |
2634 // break from (eg, for...in) may have left stuff on the stack. | 2634 // break from (eg, for...in) may have left stuff on the stack. |
2635 __ mov(r3, Operand(handler_address)); | 2635 __ mov(r3, Operand(handler_address)); |
2636 __ ldr(sp, MemOperand(r3)); | 2636 __ ldr(sp, MemOperand(r3)); |
2637 frame_->Forget(frame_->height() - handler_height); | 2637 frame_->Forget(frame_->height() - handler_height); |
2638 | 2638 |
2639 ASSERT(StackHandlerConstants::kNextOffset == 0); | 2639 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
2640 frame_->EmitPop(r1); | 2640 frame_->EmitPop(r1); |
2641 __ str(r1, MemOperand(r3)); | 2641 __ str(r1, MemOperand(r3)); |
2642 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2642 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
2643 | 2643 |
2644 if (!function_return_is_shadowed_ && i == kReturnShadowIndex) { | 2644 if (!function_return_is_shadowed_ && i == kReturnShadowIndex) { |
2645 frame_->PrepareForReturn(); | 2645 frame_->PrepareForReturn(); |
2646 } | 2646 } |
2647 shadows[i]->other_target()->Jump(); | 2647 shadows[i]->other_target()->Jump(); |
2648 } | 2648 } |
2649 } | 2649 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2716 } | 2716 } |
2717 function_return_is_shadowed_ = function_return_was_shadowed; | 2717 function_return_is_shadowed_ = function_return_was_shadowed; |
2718 | 2718 |
2719 // Get an external reference to the handler address. | 2719 // Get an external reference to the handler address. |
2720 ExternalReference handler_address(Top::k_handler_address); | 2720 ExternalReference handler_address(Top::k_handler_address); |
2721 | 2721 |
2722 // If we can fall off the end of the try block, unlink from the try | 2722 // If we can fall off the end of the try block, unlink from the try |
2723 // chain and set the state on the frame to FALLING. | 2723 // chain and set the state on the frame to FALLING. |
2724 if (has_valid_frame()) { | 2724 if (has_valid_frame()) { |
2725 // The next handler address is on top of the frame. | 2725 // The next handler address is on top of the frame. |
2726 ASSERT(StackHandlerConstants::kNextOffset == 0); | 2726 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
2727 frame_->EmitPop(r1); | 2727 frame_->EmitPop(r1); |
2728 __ mov(r3, Operand(handler_address)); | 2728 __ mov(r3, Operand(handler_address)); |
2729 __ str(r1, MemOperand(r3)); | 2729 __ str(r1, MemOperand(r3)); |
2730 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2730 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
2731 | 2731 |
2732 // Fake a top of stack value (unneeded when FALLING) and set the | 2732 // Fake a top of stack value (unneeded when FALLING) and set the |
2733 // state in r2, then jump around the unlink blocks if any. | 2733 // state in r2, then jump around the unlink blocks if any. |
2734 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 2734 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
2735 frame_->EmitPush(r0); | 2735 frame_->EmitPush(r0); |
2736 __ mov(r2, Operand(Smi::FromInt(FALLING))); | 2736 __ mov(r2, Operand(Smi::FromInt(FALLING))); |
(...skipping 18 matching lines...) Expand all Loading... |
2755 | 2755 |
2756 // Reload sp from the top handler, because some statements that | 2756 // Reload sp from the top handler, because some statements that |
2757 // we break from (eg, for...in) may have left stuff on the | 2757 // we break from (eg, for...in) may have left stuff on the |
2758 // stack. | 2758 // stack. |
2759 __ mov(r3, Operand(handler_address)); | 2759 __ mov(r3, Operand(handler_address)); |
2760 __ ldr(sp, MemOperand(r3)); | 2760 __ ldr(sp, MemOperand(r3)); |
2761 frame_->Forget(frame_->height() - handler_height); | 2761 frame_->Forget(frame_->height() - handler_height); |
2762 | 2762 |
2763 // Unlink this handler and drop it from the frame. The next | 2763 // Unlink this handler and drop it from the frame. The next |
2764 // handler address is currently on top of the frame. | 2764 // handler address is currently on top of the frame. |
2765 ASSERT(StackHandlerConstants::kNextOffset == 0); | 2765 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
2766 frame_->EmitPop(r1); | 2766 frame_->EmitPop(r1); |
2767 __ str(r1, MemOperand(r3)); | 2767 __ str(r1, MemOperand(r3)); |
2768 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2768 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
2769 | 2769 |
2770 if (i == kReturnShadowIndex) { | 2770 if (i == kReturnShadowIndex) { |
2771 // If this label shadowed the function return, materialize the | 2771 // If this label shadowed the function return, materialize the |
2772 // return value on the stack. | 2772 // return value on the stack. |
2773 frame_->EmitPush(r0); | 2773 frame_->EmitPush(r0); |
2774 } else { | 2774 } else { |
2775 // Fake TOS for targets that shadowed breaks and continues. | 2775 // Fake TOS for targets that shadowed breaks and continues. |
(...skipping 1398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4174 null.Branch(eq); | 4174 null.Branch(eq); |
4175 | 4175 |
4176 // Check that the object is a JS object but take special care of JS | 4176 // Check that the object is a JS object but take special care of JS |
4177 // functions to make sure they have 'Function' as their class. | 4177 // functions to make sure they have 'Function' as their class. |
4178 __ CompareObjectType(r0, r0, r1, FIRST_JS_OBJECT_TYPE); | 4178 __ CompareObjectType(r0, r0, r1, FIRST_JS_OBJECT_TYPE); |
4179 null.Branch(lt); | 4179 null.Branch(lt); |
4180 | 4180 |
4181 // As long as JS_FUNCTION_TYPE is the last instance type and it is | 4181 // As long as JS_FUNCTION_TYPE is the last instance type and it is |
4182 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for | 4182 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for |
4183 // LAST_JS_OBJECT_TYPE. | 4183 // LAST_JS_OBJECT_TYPE. |
4184 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 4184 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
4185 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | 4185 STATIC_ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); |
4186 __ cmp(r1, Operand(JS_FUNCTION_TYPE)); | 4186 __ cmp(r1, Operand(JS_FUNCTION_TYPE)); |
4187 function.Branch(eq); | 4187 function.Branch(eq); |
4188 | 4188 |
4189 // Check if the constructor in the map is a function. | 4189 // Check if the constructor in the map is a function. |
4190 __ ldr(r0, FieldMemOperand(r0, Map::kConstructorOffset)); | 4190 __ ldr(r0, FieldMemOperand(r0, Map::kConstructorOffset)); |
4191 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE); | 4191 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE); |
4192 non_function_constructor.Branch(ne); | 4192 non_function_constructor.Branch(ne); |
4193 | 4193 |
4194 // The r0 register now contains the constructor function. Grab the | 4194 // The r0 register now contains the constructor function. Grab the |
4195 // instance class name from there. | 4195 // instance class name from there. |
(...skipping 925 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5121 | 5121 |
5122 __ ldr(r1, ContextOperand(cp, Context::GLOBAL_INDEX)); | 5122 __ ldr(r1, ContextOperand(cp, Context::GLOBAL_INDEX)); |
5123 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalContextOffset)); | 5123 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalContextOffset)); |
5124 __ ldr(r1, ContextOperand(r1, Context::JSFUNCTION_RESULT_CACHES_INDEX)); | 5124 __ ldr(r1, ContextOperand(r1, Context::JSFUNCTION_RESULT_CACHES_INDEX)); |
5125 __ ldr(r1, FieldMemOperand(r1, FixedArray::OffsetOfElementAt(cache_id))); | 5125 __ ldr(r1, FieldMemOperand(r1, FixedArray::OffsetOfElementAt(cache_id))); |
5126 | 5126 |
5127 DeferredSearchCache* deferred = new DeferredSearchCache(r0, r1, r2); | 5127 DeferredSearchCache* deferred = new DeferredSearchCache(r0, r1, r2); |
5128 | 5128 |
5129 const int kFingerOffset = | 5129 const int kFingerOffset = |
5130 FixedArray::OffsetOfElementAt(JSFunctionResultCache::kFingerIndex); | 5130 FixedArray::OffsetOfElementAt(JSFunctionResultCache::kFingerIndex); |
5131 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 5131 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
5132 __ ldr(r0, FieldMemOperand(r1, kFingerOffset)); | 5132 __ ldr(r0, FieldMemOperand(r1, kFingerOffset)); |
5133 // r0 now holds finger offset as a smi. | 5133 // r0 now holds finger offset as a smi. |
5134 __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 5134 __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
5135 // r3 now points to the start of fixed array elements. | 5135 // r3 now points to the start of fixed array elements. |
5136 __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize, PreIndex)); | 5136 __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2 - kSmiTagSize, PreIndex)); |
5137 // Note side effect of PreIndex: r3 now points to the key of the pair. | 5137 // Note side effect of PreIndex: r3 now points to the key of the pair. |
5138 __ cmp(r2, r0); | 5138 __ cmp(r2, r0); |
5139 deferred->Branch(ne); | 5139 deferred->Branch(ne); |
5140 | 5140 |
5141 __ ldr(r0, MemOperand(r3, kPointerSize)); | 5141 __ ldr(r0, MemOperand(r3, kPointerSize)); |
(...skipping 1791 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6933 #else | 6933 #else |
6934 Register exponent = result2_; | 6934 Register exponent = result2_; |
6935 Register mantissa = result1_; | 6935 Register mantissa = result1_; |
6936 #endif | 6936 #endif |
6937 Label not_special; | 6937 Label not_special; |
6938 // Convert from Smi to integer. | 6938 // Convert from Smi to integer. |
6939 __ mov(source_, Operand(source_, ASR, kSmiTagSize)); | 6939 __ mov(source_, Operand(source_, ASR, kSmiTagSize)); |
6940 // Move sign bit from source to destination. This works because the sign bit | 6940 // Move sign bit from source to destination. This works because the sign bit |
6941 // in the exponent word of the double has the same position and polarity as | 6941 // in the exponent word of the double has the same position and polarity as |
6942 // the 2's complement sign bit in a Smi. | 6942 // the 2's complement sign bit in a Smi. |
6943 ASSERT(HeapNumber::kSignMask == 0x80000000u); | 6943 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u); |
6944 __ and_(exponent, source_, Operand(HeapNumber::kSignMask), SetCC); | 6944 __ and_(exponent, source_, Operand(HeapNumber::kSignMask), SetCC); |
6945 // Subtract from 0 if source was negative. | 6945 // Subtract from 0 if source was negative. |
6946 __ rsb(source_, source_, Operand(0), LeaveCC, ne); | 6946 __ rsb(source_, source_, Operand(0), LeaveCC, ne); |
6947 | 6947 |
6948 // We have -1, 0 or 1, which we treat specially. Register source_ contains | 6948 // We have -1, 0 or 1, which we treat specially. Register source_ contains |
6949 // absolute value: it is either equal to 1 (special case of -1 and 1), | 6949 // absolute value: it is either equal to 1 (special case of -1 and 1), |
6950 // greater than 1 (not a special case) or less than 1 (special case of 0). | 6950 // greater than 1 (not a special case) or less than 1 (special case of 0). |
6951 __ cmp(source_, Operand(1)); | 6951 __ cmp(source_, Operand(1)); |
6952 __ b(gt, ¬_special); | 6952 __ b(gt, ¬_special); |
6953 | 6953 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6986 __ Ret(); | 6986 __ Ret(); |
6987 } | 6987 } |
6988 | 6988 |
6989 | 6989 |
6990 // See comment for class. | 6990 // See comment for class. |
6991 void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) { | 6991 void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) { |
6992 Label max_negative_int; | 6992 Label max_negative_int; |
6993 // the_int_ has the answer which is a signed int32 but not a Smi. | 6993 // the_int_ has the answer which is a signed int32 but not a Smi. |
6994 // We test for the special value that has a different exponent. This test | 6994 // We test for the special value that has a different exponent. This test |
6995 // has the neat side effect of setting the flags according to the sign. | 6995 // has the neat side effect of setting the flags according to the sign. |
6996 ASSERT(HeapNumber::kSignMask == 0x80000000u); | 6996 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u); |
6997 __ cmp(the_int_, Operand(0x80000000u)); | 6997 __ cmp(the_int_, Operand(0x80000000u)); |
6998 __ b(eq, &max_negative_int); | 6998 __ b(eq, &max_negative_int); |
6999 // Set up the correct exponent in scratch_. All non-Smi int32s have the same. | 6999 // Set up the correct exponent in scratch_. All non-Smi int32s have the same. |
7000 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). | 7000 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). |
7001 uint32_t non_smi_exponent = | 7001 uint32_t non_smi_exponent = |
7002 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; | 7002 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; |
7003 __ mov(scratch_, Operand(non_smi_exponent)); | 7003 __ mov(scratch_, Operand(non_smi_exponent)); |
7004 // Set the sign bit in scratch_ if the value was negative. | 7004 // Set the sign bit in scratch_ if the value was negative. |
7005 __ orr(scratch_, scratch_, Operand(HeapNumber::kSignMask), LeaveCC, cs); | 7005 __ orr(scratch_, scratch_, Operand(HeapNumber::kSignMask), LeaveCC, cs); |
7006 // Subtract from 0 if the value was negative. | 7006 // Subtract from 0 if the value was negative. |
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7331 // See comment at call site. | 7331 // See comment at call site. |
7332 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, | 7332 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, |
7333 Register lhs, | 7333 Register lhs, |
7334 Register rhs) { | 7334 Register rhs) { |
7335 ASSERT((lhs.is(r0) && rhs.is(r1)) || | 7335 ASSERT((lhs.is(r0) && rhs.is(r1)) || |
7336 (lhs.is(r1) && rhs.is(r0))); | 7336 (lhs.is(r1) && rhs.is(r0))); |
7337 | 7337 |
7338 // If either operand is a JSObject or an oddball value, then they are | 7338 // If either operand is a JSObject or an oddball value, then they are |
7339 // not equal since their pointers are different. | 7339 // not equal since their pointers are different. |
7340 // There is no test for undetectability in strict equality. | 7340 // There is no test for undetectability in strict equality. |
7341 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 7341 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
7342 Label first_non_object; | 7342 Label first_non_object; |
7343 // Get the type of the first operand into r2 and compare it with | 7343 // Get the type of the first operand into r2 and compare it with |
7344 // FIRST_JS_OBJECT_TYPE. | 7344 // FIRST_JS_OBJECT_TYPE. |
7345 __ CompareObjectType(rhs, r2, r2, FIRST_JS_OBJECT_TYPE); | 7345 __ CompareObjectType(rhs, r2, r2, FIRST_JS_OBJECT_TYPE); |
7346 __ b(lt, &first_non_object); | 7346 __ b(lt, &first_non_object); |
7347 | 7347 |
7348 // Return non-zero (r0 is not zero) | 7348 // Return non-zero (r0 is not zero) |
7349 Label return_not_equal; | 7349 Label return_not_equal; |
7350 __ bind(&return_not_equal); | 7350 __ bind(&return_not_equal); |
7351 __ Ret(); | 7351 __ Ret(); |
7352 | 7352 |
7353 __ bind(&first_non_object); | 7353 __ bind(&first_non_object); |
7354 // Check for oddballs: true, false, null, undefined. | 7354 // Check for oddballs: true, false, null, undefined. |
7355 __ cmp(r2, Operand(ODDBALL_TYPE)); | 7355 __ cmp(r2, Operand(ODDBALL_TYPE)); |
7356 __ b(eq, &return_not_equal); | 7356 __ b(eq, &return_not_equal); |
7357 | 7357 |
7358 __ CompareObjectType(lhs, r3, r3, FIRST_JS_OBJECT_TYPE); | 7358 __ CompareObjectType(lhs, r3, r3, FIRST_JS_OBJECT_TYPE); |
7359 __ b(ge, &return_not_equal); | 7359 __ b(ge, &return_not_equal); |
7360 | 7360 |
7361 // Check for oddballs: true, false, null, undefined. | 7361 // Check for oddballs: true, false, null, undefined. |
7362 __ cmp(r3, Operand(ODDBALL_TYPE)); | 7362 __ cmp(r3, Operand(ODDBALL_TYPE)); |
7363 __ b(eq, &return_not_equal); | 7363 __ b(eq, &return_not_equal); |
7364 | 7364 |
7365 // Now that we have the types we might as well check for symbol-symbol. | 7365 // Now that we have the types we might as well check for symbol-symbol. |
7366 // Ensure that no non-strings have the symbol bit set. | 7366 // Ensure that no non-strings have the symbol bit set. |
7367 ASSERT(kNotStringTag + kIsSymbolMask > LAST_TYPE); | 7367 STATIC_ASSERT(LAST_TYPE < kNotStringTag + kIsSymbolMask); |
7368 ASSERT(kSymbolTag != 0); | 7368 STATIC_ASSERT(kSymbolTag != 0); |
7369 __ and_(r2, r2, Operand(r3)); | 7369 __ and_(r2, r2, Operand(r3)); |
7370 __ tst(r2, Operand(kIsSymbolMask)); | 7370 __ tst(r2, Operand(kIsSymbolMask)); |
7371 __ b(ne, &return_not_equal); | 7371 __ b(ne, &return_not_equal); |
7372 } | 7372 } |
7373 | 7373 |
7374 | 7374 |
7375 // See comment at call site. | 7375 // See comment at call site. |
7376 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, | 7376 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, |
7377 Register lhs, | 7377 Register lhs, |
7378 Register rhs, | 7378 Register rhs, |
(...skipping 30 matching lines...) Expand all Loading... |
7409 Register lhs, | 7409 Register lhs, |
7410 Register rhs, | 7410 Register rhs, |
7411 Label* possible_strings, | 7411 Label* possible_strings, |
7412 Label* not_both_strings) { | 7412 Label* not_both_strings) { |
7413 ASSERT((lhs.is(r0) && rhs.is(r1)) || | 7413 ASSERT((lhs.is(r0) && rhs.is(r1)) || |
7414 (lhs.is(r1) && rhs.is(r0))); | 7414 (lhs.is(r1) && rhs.is(r0))); |
7415 | 7415 |
7416 // r2 is object type of rhs. | 7416 // r2 is object type of rhs. |
7417 // Ensure that no non-strings have the symbol bit set. | 7417 // Ensure that no non-strings have the symbol bit set. |
7418 Label object_test; | 7418 Label object_test; |
7419 ASSERT(kSymbolTag != 0); | 7419 STATIC_ASSERT(kSymbolTag != 0); |
7420 __ tst(r2, Operand(kIsNotStringMask)); | 7420 __ tst(r2, Operand(kIsNotStringMask)); |
7421 __ b(ne, &object_test); | 7421 __ b(ne, &object_test); |
7422 __ tst(r2, Operand(kIsSymbolMask)); | 7422 __ tst(r2, Operand(kIsSymbolMask)); |
7423 __ b(eq, possible_strings); | 7423 __ b(eq, possible_strings); |
7424 __ CompareObjectType(lhs, r3, r3, FIRST_NONSTRING_TYPE); | 7424 __ CompareObjectType(lhs, r3, r3, FIRST_NONSTRING_TYPE); |
7425 __ b(ge, not_both_strings); | 7425 __ b(ge, not_both_strings); |
7426 __ tst(r3, Operand(kIsSymbolMask)); | 7426 __ tst(r3, Operand(kIsSymbolMask)); |
7427 __ b(eq, possible_strings); | 7427 __ b(eq, possible_strings); |
7428 | 7428 |
7429 // Both are symbols. We already checked they weren't the same pointer | 7429 // Both are symbols. We already checked they weren't the same pointer |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7480 if (!object_is_smi) { | 7480 if (!object_is_smi) { |
7481 __ BranchOnSmi(object, &is_smi); | 7481 __ BranchOnSmi(object, &is_smi); |
7482 if (CpuFeatures::IsSupported(VFP3)) { | 7482 if (CpuFeatures::IsSupported(VFP3)) { |
7483 CpuFeatures::Scope scope(VFP3); | 7483 CpuFeatures::Scope scope(VFP3); |
7484 __ CheckMap(object, | 7484 __ CheckMap(object, |
7485 scratch1, | 7485 scratch1, |
7486 Heap::kHeapNumberMapRootIndex, | 7486 Heap::kHeapNumberMapRootIndex, |
7487 not_found, | 7487 not_found, |
7488 true); | 7488 true); |
7489 | 7489 |
7490 ASSERT_EQ(8, kDoubleSize); | 7490 STATIC_ASSERT(8 == kDoubleSize); |
7491 __ add(scratch1, | 7491 __ add(scratch1, |
7492 object, | 7492 object, |
7493 Operand(HeapNumber::kValueOffset - kHeapObjectTag)); | 7493 Operand(HeapNumber::kValueOffset - kHeapObjectTag)); |
7494 __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit()); | 7494 __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit()); |
7495 __ eor(scratch1, scratch1, Operand(scratch2)); | 7495 __ eor(scratch1, scratch1, Operand(scratch2)); |
7496 __ and_(scratch1, scratch1, Operand(mask)); | 7496 __ and_(scratch1, scratch1, Operand(mask)); |
7497 | 7497 |
7498 // Calculate address of entry in string cache: each entry consists | 7498 // Calculate address of entry in string cache: each entry consists |
7499 // of two pointer sized fields. | 7499 // of two pointer sized fields. |
7500 __ add(scratch1, | 7500 __ add(scratch1, |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7579 | 7579 |
7580 // NOTICE! This code is only reached after a smi-fast-case check, so | 7580 // NOTICE! This code is only reached after a smi-fast-case check, so |
7581 // it is certain that at least one operand isn't a smi. | 7581 // it is certain that at least one operand isn't a smi. |
7582 | 7582 |
7583 // Handle the case where the objects are identical. Either returns the answer | 7583 // Handle the case where the objects are identical. Either returns the answer |
7584 // or goes to slow. Only falls through if the objects were not identical. | 7584 // or goes to slow. Only falls through if the objects were not identical. |
7585 EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); | 7585 EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); |
7586 | 7586 |
7587 // If either is a Smi (we know that not both are), then they can only | 7587 // If either is a Smi (we know that not both are), then they can only |
7588 // be strictly equal if the other is a HeapNumber. | 7588 // be strictly equal if the other is a HeapNumber. |
7589 ASSERT_EQ(0, kSmiTag); | 7589 STATIC_ASSERT(kSmiTag == 0); |
7590 ASSERT_EQ(0, Smi::FromInt(0)); | 7590 ASSERT_EQ(0, Smi::FromInt(0)); |
7591 __ and_(r2, lhs_, Operand(rhs_)); | 7591 __ and_(r2, lhs_, Operand(rhs_)); |
7592 __ tst(r2, Operand(kSmiTagMask)); | 7592 __ tst(r2, Operand(kSmiTagMask)); |
7593 __ b(ne, ¬_smis); | 7593 __ b(ne, ¬_smis); |
7594 // One operand is a smi. EmitSmiNonsmiComparison generates code that can: | 7594 // One operand is a smi. EmitSmiNonsmiComparison generates code that can: |
7595 // 1) Return the answer. | 7595 // 1) Return the answer. |
7596 // 2) Go to slow. | 7596 // 2) Go to slow. |
7597 // 3) Fall through to both_loaded_as_doubles. | 7597 // 3) Fall through to both_loaded_as_doubles. |
7598 // 4) Jump to lhs_not_nan. | 7598 // 4) Jump to lhs_not_nan. |
7599 // In cases 3 and 4 we have found out we were dealing with a number-number | 7599 // In cases 3 and 4 we have found out we were dealing with a number-number |
(...skipping 982 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8582 // smi_test_reg to tell us that. | 8582 // smi_test_reg to tell us that. |
8583 if (ShouldGenerateSmiCode()) { | 8583 if (ShouldGenerateSmiCode()) { |
8584 __ orr(smi_test_reg, lhs, Operand(rhs)); | 8584 __ orr(smi_test_reg, lhs, Operand(rhs)); |
8585 } | 8585 } |
8586 | 8586 |
8587 switch (op_) { | 8587 switch (op_) { |
8588 case Token::ADD: { | 8588 case Token::ADD: { |
8589 Label not_smi; | 8589 Label not_smi; |
8590 // Fast path. | 8590 // Fast path. |
8591 if (ShouldGenerateSmiCode()) { | 8591 if (ShouldGenerateSmiCode()) { |
8592 ASSERT(kSmiTag == 0); // Adjust code below. | 8592 STATIC_ASSERT(kSmiTag == 0); // Adjust code below. |
8593 __ tst(smi_test_reg, Operand(kSmiTagMask)); | 8593 __ tst(smi_test_reg, Operand(kSmiTagMask)); |
8594 __ b(ne, ¬_smi); | 8594 __ b(ne, ¬_smi); |
8595 __ add(r0, r1, Operand(r0), SetCC); // Add y optimistically. | 8595 __ add(r0, r1, Operand(r0), SetCC); // Add y optimistically. |
8596 // Return if no overflow. | 8596 // Return if no overflow. |
8597 __ Ret(vc); | 8597 __ Ret(vc); |
8598 __ sub(r0, r0, Operand(r1)); // Revert optimistic add. | 8598 __ sub(r0, r0, Operand(r1)); // Revert optimistic add. |
8599 } | 8599 } |
8600 HandleBinaryOpSlowCases(masm, ¬_smi, lhs, rhs, Builtins::ADD); | 8600 HandleBinaryOpSlowCases(masm, ¬_smi, lhs, rhs, Builtins::ADD); |
8601 break; | 8601 break; |
8602 } | 8602 } |
8603 | 8603 |
8604 case Token::SUB: { | 8604 case Token::SUB: { |
8605 Label not_smi; | 8605 Label not_smi; |
8606 // Fast path. | 8606 // Fast path. |
8607 if (ShouldGenerateSmiCode()) { | 8607 if (ShouldGenerateSmiCode()) { |
8608 ASSERT(kSmiTag == 0); // Adjust code below. | 8608 STATIC_ASSERT(kSmiTag == 0); // Adjust code below. |
8609 __ tst(smi_test_reg, Operand(kSmiTagMask)); | 8609 __ tst(smi_test_reg, Operand(kSmiTagMask)); |
8610 __ b(ne, ¬_smi); | 8610 __ b(ne, ¬_smi); |
8611 if (lhs.is(r1)) { | 8611 if (lhs.is(r1)) { |
8612 __ sub(r0, r1, Operand(r0), SetCC); // Subtract y optimistically. | 8612 __ sub(r0, r1, Operand(r0), SetCC); // Subtract y optimistically. |
8613 // Return if no overflow. | 8613 // Return if no overflow. |
8614 __ Ret(vc); | 8614 __ Ret(vc); |
8615 __ sub(r0, r1, Operand(r0)); // Revert optimistic subtract. | 8615 __ sub(r0, r1, Operand(r0)); // Revert optimistic subtract. |
8616 } else { | 8616 } else { |
8617 __ sub(r0, r0, Operand(r1), SetCC); // Subtract y optimistically. | 8617 __ sub(r0, r0, Operand(r1), SetCC); // Subtract y optimistically. |
8618 // Return if no overflow. | 8618 // Return if no overflow. |
8619 __ Ret(vc); | 8619 __ Ret(vc); |
8620 __ add(r0, r0, Operand(r1)); // Revert optimistic subtract. | 8620 __ add(r0, r0, Operand(r1)); // Revert optimistic subtract. |
8621 } | 8621 } |
8622 } | 8622 } |
8623 HandleBinaryOpSlowCases(masm, ¬_smi, lhs, rhs, Builtins::SUB); | 8623 HandleBinaryOpSlowCases(masm, ¬_smi, lhs, rhs, Builtins::SUB); |
8624 break; | 8624 break; |
8625 } | 8625 } |
8626 | 8626 |
8627 case Token::MUL: { | 8627 case Token::MUL: { |
8628 Label not_smi, slow; | 8628 Label not_smi, slow; |
8629 if (ShouldGenerateSmiCode()) { | 8629 if (ShouldGenerateSmiCode()) { |
8630 ASSERT(kSmiTag == 0); // adjust code below | 8630 STATIC_ASSERT(kSmiTag == 0); // adjust code below |
8631 __ tst(smi_test_reg, Operand(kSmiTagMask)); | 8631 __ tst(smi_test_reg, Operand(kSmiTagMask)); |
8632 Register scratch2 = smi_test_reg; | 8632 Register scratch2 = smi_test_reg; |
8633 smi_test_reg = no_reg; | 8633 smi_test_reg = no_reg; |
8634 __ b(ne, ¬_smi); | 8634 __ b(ne, ¬_smi); |
8635 // Remove tag from one operand (but keep sign), so that result is Smi. | 8635 // Remove tag from one operand (but keep sign), so that result is Smi. |
8636 __ mov(ip, Operand(rhs, ASR, kSmiTagSize)); | 8636 __ mov(ip, Operand(rhs, ASR, kSmiTagSize)); |
8637 // Do multiplication | 8637 // Do multiplication |
8638 // scratch = lower 32 bits of ip * lhs. | 8638 // scratch = lower 32 bits of ip * lhs. |
8639 __ smull(scratch, scratch2, lhs, ip); | 8639 __ smull(scratch, scratch2, lhs, ip); |
8640 // Go slow on overflows (overflow bit is not set). | 8640 // Go slow on overflows (overflow bit is not set). |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8756 // support for modulus checking for smis makes sense. We can handle | 8756 // support for modulus checking for smis makes sense. We can handle |
8757 // 1 to 25 times any power of 2. This covers over half the numbers from | 8757 // 1 to 25 times any power of 2. This covers over half the numbers from |
8758 // 1 to 100 including all of the first 25. (Actually the constants < 10 | 8758 // 1 to 100 including all of the first 25. (Actually the constants < 10 |
8759 // are handled above by reciprocal multiplication. We only get here for | 8759 // are handled above by reciprocal multiplication. We only get here for |
8760 // those cases if the right hand side is not a constant or for cases | 8760 // those cases if the right hand side is not a constant or for cases |
8761 // like 192 which is 3*2^6 and ends up in the 3 case in the integer mod | 8761 // like 192 which is 3*2^6 and ends up in the 3 case in the integer mod |
8762 // stub.) | 8762 // stub.) |
8763 Label slow; | 8763 Label slow; |
8764 Label not_power_of_2; | 8764 Label not_power_of_2; |
8765 ASSERT(!ShouldGenerateSmiCode()); | 8765 ASSERT(!ShouldGenerateSmiCode()); |
8766 ASSERT(kSmiTag == 0); // Adjust code below. | 8766 STATIC_ASSERT(kSmiTag == 0); // Adjust code below. |
8767 // Check for two positive smis. | 8767 // Check for two positive smis. |
8768 __ orr(smi_test_reg, lhs, Operand(rhs)); | 8768 __ orr(smi_test_reg, lhs, Operand(rhs)); |
8769 __ tst(smi_test_reg, Operand(0x80000000u | kSmiTagMask)); | 8769 __ tst(smi_test_reg, Operand(0x80000000u | kSmiTagMask)); |
8770 __ b(ne, &slow); | 8770 __ b(ne, &slow); |
8771 // Check that rhs is a power of two and not zero. | 8771 // Check that rhs is a power of two and not zero. |
8772 Register mask_bits = r3; | 8772 Register mask_bits = r3; |
8773 __ sub(scratch, rhs, Operand(1), SetCC); | 8773 __ sub(scratch, rhs, Operand(1), SetCC); |
8774 __ b(mi, &slow); | 8774 __ b(mi, &slow); |
8775 __ and_(mask_bits, rhs, Operand(scratch), SetCC); | 8775 __ and_(mask_bits, rhs, Operand(scratch), SetCC); |
8776 __ b(ne, ¬_power_of_2); | 8776 __ b(ne, ¬_power_of_2); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8816 break; | 8816 break; |
8817 } | 8817 } |
8818 | 8818 |
8819 case Token::BIT_OR: | 8819 case Token::BIT_OR: |
8820 case Token::BIT_AND: | 8820 case Token::BIT_AND: |
8821 case Token::BIT_XOR: | 8821 case Token::BIT_XOR: |
8822 case Token::SAR: | 8822 case Token::SAR: |
8823 case Token::SHR: | 8823 case Token::SHR: |
8824 case Token::SHL: { | 8824 case Token::SHL: { |
8825 Label slow; | 8825 Label slow; |
8826 ASSERT(kSmiTag == 0); // adjust code below | 8826 STATIC_ASSERT(kSmiTag == 0); // adjust code below |
8827 __ tst(smi_test_reg, Operand(kSmiTagMask)); | 8827 __ tst(smi_test_reg, Operand(kSmiTagMask)); |
8828 __ b(ne, &slow); | 8828 __ b(ne, &slow); |
8829 Register scratch2 = smi_test_reg; | 8829 Register scratch2 = smi_test_reg; |
8830 smi_test_reg = no_reg; | 8830 smi_test_reg = no_reg; |
8831 switch (op_) { | 8831 switch (op_) { |
8832 case Token::BIT_OR: __ orr(result, rhs, Operand(lhs)); break; | 8832 case Token::BIT_OR: __ orr(result, rhs, Operand(lhs)); break; |
8833 case Token::BIT_AND: __ and_(result, rhs, Operand(lhs)); break; | 8833 case Token::BIT_AND: __ and_(result, rhs, Operand(lhs)); break; |
8834 case Token::BIT_XOR: __ eor(result, rhs, Operand(lhs)); break; | 8834 case Token::BIT_XOR: __ eor(result, rhs, Operand(lhs)); break; |
8835 case Token::SAR: | 8835 case Token::SAR: |
8836 // Remove tags from right operand. | 8836 // Remove tags from right operand. |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9130 default: | 9130 default: |
9131 UNREACHABLE(); | 9131 UNREACHABLE(); |
9132 } | 9132 } |
9133 } | 9133 } |
9134 | 9134 |
9135 | 9135 |
9136 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { | 9136 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { |
9137 // r0 holds the exception. | 9137 // r0 holds the exception. |
9138 | 9138 |
9139 // Adjust this code if not the case. | 9139 // Adjust this code if not the case. |
9140 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); | 9140 STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); |
9141 | 9141 |
9142 // Drop the sp to the top of the handler. | 9142 // Drop the sp to the top of the handler. |
9143 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); | 9143 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
9144 __ ldr(sp, MemOperand(r3)); | 9144 __ ldr(sp, MemOperand(r3)); |
9145 | 9145 |
9146 // Restore the next handler and frame pointer, discard handler state. | 9146 // Restore the next handler and frame pointer, discard handler state. |
9147 ASSERT(StackHandlerConstants::kNextOffset == 0); | 9147 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
9148 __ pop(r2); | 9148 __ pop(r2); |
9149 __ str(r2, MemOperand(r3)); | 9149 __ str(r2, MemOperand(r3)); |
9150 ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); | 9150 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); |
9151 __ ldm(ia_w, sp, r3.bit() | fp.bit()); // r3: discarded state. | 9151 __ ldm(ia_w, sp, r3.bit() | fp.bit()); // r3: discarded state. |
9152 | 9152 |
9153 // Before returning we restore the context from the frame pointer if | 9153 // Before returning we restore the context from the frame pointer if |
9154 // not NULL. The frame pointer is NULL in the exception handler of a | 9154 // not NULL. The frame pointer is NULL in the exception handler of a |
9155 // JS entry frame. | 9155 // JS entry frame. |
9156 __ cmp(fp, Operand(0)); | 9156 __ cmp(fp, Operand(0)); |
9157 // Set cp to NULL if fp is NULL. | 9157 // Set cp to NULL if fp is NULL. |
9158 __ mov(cp, Operand(0), LeaveCC, eq); | 9158 __ mov(cp, Operand(0), LeaveCC, eq); |
9159 // Restore cp otherwise. | 9159 // Restore cp otherwise. |
9160 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); | 9160 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); |
9161 #ifdef DEBUG | 9161 #ifdef DEBUG |
9162 if (FLAG_debug_code) { | 9162 if (FLAG_debug_code) { |
9163 __ mov(lr, Operand(pc)); | 9163 __ mov(lr, Operand(pc)); |
9164 } | 9164 } |
9165 #endif | 9165 #endif |
9166 ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); | 9166 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); |
9167 __ pop(pc); | 9167 __ pop(pc); |
9168 } | 9168 } |
9169 | 9169 |
9170 | 9170 |
9171 void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, | 9171 void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, |
9172 UncatchableExceptionType type) { | 9172 UncatchableExceptionType type) { |
9173 // Adjust this code if not the case. | 9173 // Adjust this code if not the case. |
9174 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); | 9174 STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); |
9175 | 9175 |
9176 // Drop sp to the top stack handler. | 9176 // Drop sp to the top stack handler. |
9177 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); | 9177 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
9178 __ ldr(sp, MemOperand(r3)); | 9178 __ ldr(sp, MemOperand(r3)); |
9179 | 9179 |
9180 // Unwind the handlers until the ENTRY handler is found. | 9180 // Unwind the handlers until the ENTRY handler is found. |
9181 Label loop, done; | 9181 Label loop, done; |
9182 __ bind(&loop); | 9182 __ bind(&loop); |
9183 // Load the type of the current stack handler. | 9183 // Load the type of the current stack handler. |
9184 const int kStateOffset = StackHandlerConstants::kStateOffset; | 9184 const int kStateOffset = StackHandlerConstants::kStateOffset; |
9185 __ ldr(r2, MemOperand(sp, kStateOffset)); | 9185 __ ldr(r2, MemOperand(sp, kStateOffset)); |
9186 __ cmp(r2, Operand(StackHandler::ENTRY)); | 9186 __ cmp(r2, Operand(StackHandler::ENTRY)); |
9187 __ b(eq, &done); | 9187 __ b(eq, &done); |
9188 // Fetch the next handler in the list. | 9188 // Fetch the next handler in the list. |
9189 const int kNextOffset = StackHandlerConstants::kNextOffset; | 9189 const int kNextOffset = StackHandlerConstants::kNextOffset; |
9190 __ ldr(sp, MemOperand(sp, kNextOffset)); | 9190 __ ldr(sp, MemOperand(sp, kNextOffset)); |
9191 __ jmp(&loop); | 9191 __ jmp(&loop); |
9192 __ bind(&done); | 9192 __ bind(&done); |
9193 | 9193 |
9194 // Set the top handler address to next handler past the current ENTRY handler. | 9194 // Set the top handler address to next handler past the current ENTRY handler. |
9195 ASSERT(StackHandlerConstants::kNextOffset == 0); | 9195 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
9196 __ pop(r2); | 9196 __ pop(r2); |
9197 __ str(r2, MemOperand(r3)); | 9197 __ str(r2, MemOperand(r3)); |
9198 | 9198 |
9199 if (type == OUT_OF_MEMORY) { | 9199 if (type == OUT_OF_MEMORY) { |
9200 // Set external caught exception to false. | 9200 // Set external caught exception to false. |
9201 ExternalReference external_caught(Top::k_external_caught_exception_address); | 9201 ExternalReference external_caught(Top::k_external_caught_exception_address); |
9202 __ mov(r0, Operand(false)); | 9202 __ mov(r0, Operand(false)); |
9203 __ mov(r2, Operand(external_caught)); | 9203 __ mov(r2, Operand(external_caught)); |
9204 __ str(r0, MemOperand(r2)); | 9204 __ str(r0, MemOperand(r2)); |
9205 | 9205 |
9206 // Set pending exception and r0 to out of memory exception. | 9206 // Set pending exception and r0 to out of memory exception. |
9207 Failure* out_of_memory = Failure::OutOfMemoryException(); | 9207 Failure* out_of_memory = Failure::OutOfMemoryException(); |
9208 __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); | 9208 __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); |
9209 __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address))); | 9209 __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address))); |
9210 __ str(r0, MemOperand(r2)); | 9210 __ str(r0, MemOperand(r2)); |
9211 } | 9211 } |
9212 | 9212 |
9213 // Stack layout at this point. See also StackHandlerConstants. | 9213 // Stack layout at this point. See also StackHandlerConstants. |
9214 // sp -> state (ENTRY) | 9214 // sp -> state (ENTRY) |
9215 // fp | 9215 // fp |
9216 // lr | 9216 // lr |
9217 | 9217 |
9218 // Discard handler state (r2 is not used) and restore frame pointer. | 9218 // Discard handler state (r2 is not used) and restore frame pointer. |
9219 ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); | 9219 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); |
9220 __ ldm(ia_w, sp, r2.bit() | fp.bit()); // r2: discarded state. | 9220 __ ldm(ia_w, sp, r2.bit() | fp.bit()); // r2: discarded state. |
9221 // Before returning we restore the context from the frame pointer if | 9221 // Before returning we restore the context from the frame pointer if |
9222 // not NULL. The frame pointer is NULL in the exception handler of a | 9222 // not NULL. The frame pointer is NULL in the exception handler of a |
9223 // JS entry frame. | 9223 // JS entry frame. |
9224 __ cmp(fp, Operand(0)); | 9224 __ cmp(fp, Operand(0)); |
9225 // Set cp to NULL if fp is NULL. | 9225 // Set cp to NULL if fp is NULL. |
9226 __ mov(cp, Operand(0), LeaveCC, eq); | 9226 __ mov(cp, Operand(0), LeaveCC, eq); |
9227 // Restore cp otherwise. | 9227 // Restore cp otherwise. |
9228 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); | 9228 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); |
9229 #ifdef DEBUG | 9229 #ifdef DEBUG |
9230 if (FLAG_debug_code) { | 9230 if (FLAG_debug_code) { |
9231 __ mov(lr, Operand(pc)); | 9231 __ mov(lr, Operand(pc)); |
9232 } | 9232 } |
9233 #endif | 9233 #endif |
9234 ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); | 9234 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); |
9235 __ pop(pc); | 9235 __ pop(pc); |
9236 } | 9236 } |
9237 | 9237 |
9238 | 9238 |
9239 void CEntryStub::GenerateCore(MacroAssembler* masm, | 9239 void CEntryStub::GenerateCore(MacroAssembler* masm, |
9240 Label* throw_normal_exception, | 9240 Label* throw_normal_exception, |
9241 Label* throw_termination_exception, | 9241 Label* throw_termination_exception, |
9242 Label* throw_out_of_memory_exception, | 9242 Label* throw_out_of_memory_exception, |
9243 bool do_gc, | 9243 bool do_gc, |
9244 bool always_allocate, | 9244 bool always_allocate, |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9319 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1 | 9319 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1 |
9320 // though (contain the result). | 9320 // though (contain the result). |
9321 __ mov(r2, Operand(scope_depth)); | 9321 __ mov(r2, Operand(scope_depth)); |
9322 __ ldr(r3, MemOperand(r2)); | 9322 __ ldr(r3, MemOperand(r2)); |
9323 __ sub(r3, r3, Operand(1)); | 9323 __ sub(r3, r3, Operand(1)); |
9324 __ str(r3, MemOperand(r2)); | 9324 __ str(r3, MemOperand(r2)); |
9325 } | 9325 } |
9326 | 9326 |
9327 // check for failure result | 9327 // check for failure result |
9328 Label failure_returned; | 9328 Label failure_returned; |
9329 ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); | 9329 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); |
9330 // Lower 2 bits of r2 are 0 iff r0 has failure tag. | 9330 // Lower 2 bits of r2 are 0 iff r0 has failure tag. |
9331 __ add(r2, r0, Operand(1)); | 9331 __ add(r2, r0, Operand(1)); |
9332 __ tst(r2, Operand(kFailureTagMask)); | 9332 __ tst(r2, Operand(kFailureTagMask)); |
9333 __ b(eq, &failure_returned); | 9333 __ b(eq, &failure_returned); |
9334 | 9334 |
9335 // Exit C frame and return. | 9335 // Exit C frame and return. |
9336 // r0:r1: result | 9336 // r0:r1: result |
9337 // sp: stack pointer | 9337 // sp: stack pointer |
9338 // fp: frame pointer | 9338 // fp: frame pointer |
9339 __ LeaveExitFrame(mode_); | 9339 __ LeaveExitFrame(mode_); |
9340 | 9340 |
9341 // check if we should retry or throw exception | 9341 // check if we should retry or throw exception |
9342 Label retry; | 9342 Label retry; |
9343 __ bind(&failure_returned); | 9343 __ bind(&failure_returned); |
9344 ASSERT(Failure::RETRY_AFTER_GC == 0); | 9344 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); |
9345 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); | 9345 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); |
9346 __ b(eq, &retry); | 9346 __ b(eq, &retry); |
9347 | 9347 |
9348 // Special handling of out of memory exceptions. | 9348 // Special handling of out of memory exceptions. |
9349 Failure* out_of_memory = Failure::OutOfMemoryException(); | 9349 Failure* out_of_memory = Failure::OutOfMemoryException(); |
9350 __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); | 9350 __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); |
9351 __ b(eq, throw_out_of_memory_exception); | 9351 __ b(eq, throw_out_of_memory_exception); |
9352 | 9352 |
9353 // Retrieve the pending exception and clear the variable. | 9353 // Retrieve the pending exception and clear the variable. |
9354 __ mov(ip, Operand(ExternalReference::the_hole_value_location())); | 9354 __ mov(ip, Operand(ExternalReference::the_hole_value_location())); |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9737 __ ldr(r4, FieldMemOperand(r4, GlobalObject::kGlobalContextOffset)); | 9737 __ ldr(r4, FieldMemOperand(r4, GlobalObject::kGlobalContextOffset)); |
9738 __ ldr(r4, MemOperand(r4, offset)); | 9738 __ ldr(r4, MemOperand(r4, offset)); |
9739 | 9739 |
9740 // Copy the JS object part. | 9740 // Copy the JS object part. |
9741 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { | 9741 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |
9742 __ ldr(r3, FieldMemOperand(r4, i)); | 9742 __ ldr(r3, FieldMemOperand(r4, i)); |
9743 __ str(r3, FieldMemOperand(r0, i)); | 9743 __ str(r3, FieldMemOperand(r0, i)); |
9744 } | 9744 } |
9745 | 9745 |
9746 // Setup the callee in-object property. | 9746 // Setup the callee in-object property. |
9747 ASSERT(Heap::arguments_callee_index == 0); | 9747 STATIC_ASSERT(Heap::arguments_callee_index == 0); |
9748 __ ldr(r3, MemOperand(sp, 2 * kPointerSize)); | 9748 __ ldr(r3, MemOperand(sp, 2 * kPointerSize)); |
9749 __ str(r3, FieldMemOperand(r0, JSObject::kHeaderSize)); | 9749 __ str(r3, FieldMemOperand(r0, JSObject::kHeaderSize)); |
9750 | 9750 |
9751 // Get the length (smi tagged) and set that as an in-object property too. | 9751 // Get the length (smi tagged) and set that as an in-object property too. |
9752 ASSERT(Heap::arguments_length_index == 1); | 9752 STATIC_ASSERT(Heap::arguments_length_index == 1); |
9753 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); | 9753 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); |
9754 __ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize + kPointerSize)); | 9754 __ str(r1, FieldMemOperand(r0, JSObject::kHeaderSize + kPointerSize)); |
9755 | 9755 |
9756 // If there are no actual arguments, we're done. | 9756 // If there are no actual arguments, we're done. |
9757 Label done; | 9757 Label done; |
9758 __ cmp(r1, Operand(0)); | 9758 __ cmp(r1, Operand(0)); |
9759 __ b(eq, &done); | 9759 __ b(eq, &done); |
9760 | 9760 |
9761 // Get the parameters pointer from the stack. | 9761 // Get the parameters pointer from the stack. |
9762 __ ldr(r2, MemOperand(sp, 1 * kPointerSize)); | 9762 __ ldr(r2, MemOperand(sp, 1 * kPointerSize)); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9834 ExternalReference::address_of_regexp_stack_memory_address(); | 9834 ExternalReference::address_of_regexp_stack_memory_address(); |
9835 ExternalReference address_of_regexp_stack_memory_size = | 9835 ExternalReference address_of_regexp_stack_memory_size = |
9836 ExternalReference::address_of_regexp_stack_memory_size(); | 9836 ExternalReference::address_of_regexp_stack_memory_size(); |
9837 __ mov(r0, Operand(address_of_regexp_stack_memory_size)); | 9837 __ mov(r0, Operand(address_of_regexp_stack_memory_size)); |
9838 __ ldr(r0, MemOperand(r0, 0)); | 9838 __ ldr(r0, MemOperand(r0, 0)); |
9839 __ tst(r0, Operand(r0)); | 9839 __ tst(r0, Operand(r0)); |
9840 __ b(eq, &runtime); | 9840 __ b(eq, &runtime); |
9841 | 9841 |
9842 // Check that the first argument is a JSRegExp object. | 9842 // Check that the first argument is a JSRegExp object. |
9843 __ ldr(r0, MemOperand(sp, kJSRegExpOffset)); | 9843 __ ldr(r0, MemOperand(sp, kJSRegExpOffset)); |
9844 ASSERT_EQ(0, kSmiTag); | 9844 STATIC_ASSERT(kSmiTag == 0); |
9845 __ tst(r0, Operand(kSmiTagMask)); | 9845 __ tst(r0, Operand(kSmiTagMask)); |
9846 __ b(eq, &runtime); | 9846 __ b(eq, &runtime); |
9847 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); | 9847 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); |
9848 __ b(ne, &runtime); | 9848 __ b(ne, &runtime); |
9849 | 9849 |
9850 // Check that the RegExp has been compiled (data contains a fixed array). | 9850 // Check that the RegExp has been compiled (data contains a fixed array). |
9851 __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset)); | 9851 __ ldr(regexp_data, FieldMemOperand(r0, JSRegExp::kDataOffset)); |
9852 if (FLAG_debug_code) { | 9852 if (FLAG_debug_code) { |
9853 __ tst(regexp_data, Operand(kSmiTagMask)); | 9853 __ tst(regexp_data, Operand(kSmiTagMask)); |
9854 __ Check(nz, "Unexpected type for RegExp data, FixedArray expected"); | 9854 __ Check(nz, "Unexpected type for RegExp data, FixedArray expected"); |
9855 __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE); | 9855 __ CompareObjectType(regexp_data, r0, r0, FIXED_ARRAY_TYPE); |
9856 __ Check(eq, "Unexpected type for RegExp data, FixedArray expected"); | 9856 __ Check(eq, "Unexpected type for RegExp data, FixedArray expected"); |
9857 } | 9857 } |
9858 | 9858 |
9859 // regexp_data: RegExp data (FixedArray) | 9859 // regexp_data: RegExp data (FixedArray) |
9860 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. | 9860 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. |
9861 __ ldr(r0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); | 9861 __ ldr(r0, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset)); |
9862 __ cmp(r0, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); | 9862 __ cmp(r0, Operand(Smi::FromInt(JSRegExp::IRREGEXP))); |
9863 __ b(ne, &runtime); | 9863 __ b(ne, &runtime); |
9864 | 9864 |
9865 // regexp_data: RegExp data (FixedArray) | 9865 // regexp_data: RegExp data (FixedArray) |
9866 // Check that the number of captures fit in the static offsets vector buffer. | 9866 // Check that the number of captures fit in the static offsets vector buffer. |
9867 __ ldr(r2, | 9867 __ ldr(r2, |
9868 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); | 9868 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); |
9869 // Calculate number of capture registers (number_of_captures + 1) * 2. This | 9869 // Calculate number of capture registers (number_of_captures + 1) * 2. This |
9870 // uses the asumption that smis are 2 * their untagged value. | 9870 // uses the asumption that smis are 2 * their untagged value. |
9871 ASSERT_EQ(0, kSmiTag); | 9871 STATIC_ASSERT(kSmiTag == 0); |
9872 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 9872 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
9873 __ add(r2, r2, Operand(2)); // r2 was a smi. | 9873 __ add(r2, r2, Operand(2)); // r2 was a smi. |
9874 // Check that the static offsets vector buffer is large enough. | 9874 // Check that the static offsets vector buffer is large enough. |
9875 __ cmp(r2, Operand(OffsetsVector::kStaticOffsetsVectorSize)); | 9875 __ cmp(r2, Operand(OffsetsVector::kStaticOffsetsVectorSize)); |
9876 __ b(hi, &runtime); | 9876 __ b(hi, &runtime); |
9877 | 9877 |
9878 // r2: Number of capture registers | 9878 // r2: Number of capture registers |
9879 // regexp_data: RegExp data (FixedArray) | 9879 // regexp_data: RegExp data (FixedArray) |
9880 // Check that the second argument is a string. | 9880 // Check that the second argument is a string. |
9881 __ ldr(subject, MemOperand(sp, kSubjectOffset)); | 9881 __ ldr(subject, MemOperand(sp, kSubjectOffset)); |
9882 __ tst(subject, Operand(kSmiTagMask)); | 9882 __ tst(subject, Operand(kSmiTagMask)); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9923 __ b(gt, &runtime); | 9923 __ b(gt, &runtime); |
9924 | 9924 |
9925 // subject: Subject string | 9925 // subject: Subject string |
9926 // regexp_data: RegExp data (FixedArray) | 9926 // regexp_data: RegExp data (FixedArray) |
9927 // Check the representation and encoding of the subject string. | 9927 // Check the representation and encoding of the subject string. |
9928 Label seq_string; | 9928 Label seq_string; |
9929 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); | 9929 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); |
9930 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); | 9930 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); |
9931 // First check for flat string. | 9931 // First check for flat string. |
9932 __ tst(r0, Operand(kIsNotStringMask | kStringRepresentationMask)); | 9932 __ tst(r0, Operand(kIsNotStringMask | kStringRepresentationMask)); |
9933 ASSERT_EQ(0, kStringTag | kSeqStringTag); | 9933 STATIC_ASSERT((kStringTag | kSeqStringTag) == 0); |
9934 __ b(eq, &seq_string); | 9934 __ b(eq, &seq_string); |
9935 | 9935 |
9936 // subject: Subject string | 9936 // subject: Subject string |
9937 // regexp_data: RegExp data (FixedArray) | 9937 // regexp_data: RegExp data (FixedArray) |
9938 // Check for flat cons string. | 9938 // Check for flat cons string. |
9939 // A flat cons string is a cons string where the second part is the empty | 9939 // A flat cons string is a cons string where the second part is the empty |
9940 // string. In that case the subject string is just the first part of the cons | 9940 // string. In that case the subject string is just the first part of the cons |
9941 // string. Also in this case the first part of the cons string is known to be | 9941 // string. Also in this case the first part of the cons string is known to be |
9942 // a sequential string or an external string. | 9942 // a sequential string or an external string. |
9943 ASSERT(kExternalStringTag !=0); | 9943 STATIC_ASSERT(kExternalStringTag !=0); |
9944 ASSERT_EQ(0, kConsStringTag & kExternalStringTag); | 9944 STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); |
9945 __ tst(r0, Operand(kIsNotStringMask | kExternalStringTag)); | 9945 __ tst(r0, Operand(kIsNotStringMask | kExternalStringTag)); |
9946 __ b(ne, &runtime); | 9946 __ b(ne, &runtime); |
9947 __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset)); | 9947 __ ldr(r0, FieldMemOperand(subject, ConsString::kSecondOffset)); |
9948 __ LoadRoot(r1, Heap::kEmptyStringRootIndex); | 9948 __ LoadRoot(r1, Heap::kEmptyStringRootIndex); |
9949 __ cmp(r0, r1); | 9949 __ cmp(r0, r1); |
9950 __ b(ne, &runtime); | 9950 __ b(ne, &runtime); |
9951 __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); | 9951 __ ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset)); |
9952 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); | 9952 __ ldr(r0, FieldMemOperand(subject, HeapObject::kMapOffset)); |
9953 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); | 9953 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); |
9954 // Is first part a flat string? | 9954 // Is first part a flat string? |
9955 ASSERT_EQ(0, kSeqStringTag); | 9955 STATIC_ASSERT(kSeqStringTag == 0); |
9956 __ tst(r0, Operand(kStringRepresentationMask)); | 9956 __ tst(r0, Operand(kStringRepresentationMask)); |
9957 __ b(nz, &runtime); | 9957 __ b(nz, &runtime); |
9958 | 9958 |
9959 __ bind(&seq_string); | 9959 __ bind(&seq_string); |
9960 // subject: Subject string | 9960 // subject: Subject string |
9961 // regexp_data: RegExp data (FixedArray) | 9961 // regexp_data: RegExp data (FixedArray) |
9962 // r0: Instance type of subject string | 9962 // r0: Instance type of subject string |
9963 ASSERT_EQ(4, kAsciiStringTag); | 9963 STATIC_ASSERT(4 == kAsciiStringTag); |
9964 ASSERT_EQ(0, kTwoByteStringTag); | 9964 STATIC_ASSERT(kTwoByteStringTag == 0); |
9965 // Find the code object based on the assumptions above. | 9965 // Find the code object based on the assumptions above. |
9966 __ and_(r0, r0, Operand(kStringEncodingMask)); | 9966 __ and_(r0, r0, Operand(kStringEncodingMask)); |
9967 __ mov(r3, Operand(r0, ASR, 2), SetCC); | 9967 __ mov(r3, Operand(r0, ASR, 2), SetCC); |
9968 __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne); | 9968 __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataAsciiCodeOffset), ne); |
9969 __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq); | 9969 __ ldr(r7, FieldMemOperand(regexp_data, JSRegExp::kDataUC16CodeOffset), eq); |
9970 | 9970 |
9971 // Check that the irregexp code has been generated for the actual string | 9971 // Check that the irregexp code has been generated for the actual string |
9972 // encoding. If it has, the field contains a code object otherwise it contains | 9972 // encoding. If it has, the field contains a code object otherwise it contains |
9973 // the hole. | 9973 // the hole. |
9974 __ CompareObjectType(r7, r0, r0, CODE_TYPE); | 9974 __ CompareObjectType(r7, r0, r0, CODE_TYPE); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10008 __ str(r0, MemOperand(sp, 1 * kPointerSize)); | 10008 __ str(r0, MemOperand(sp, 1 * kPointerSize)); |
10009 | 10009 |
10010 // Argument 5 (sp[0]): static offsets vector buffer. | 10010 // Argument 5 (sp[0]): static offsets vector buffer. |
10011 __ mov(r0, Operand(ExternalReference::address_of_static_offsets_vector())); | 10011 __ mov(r0, Operand(ExternalReference::address_of_static_offsets_vector())); |
10012 __ str(r0, MemOperand(sp, 0 * kPointerSize)); | 10012 __ str(r0, MemOperand(sp, 0 * kPointerSize)); |
10013 | 10013 |
10014 // For arguments 4 and 3 get string length, calculate start of string data and | 10014 // For arguments 4 and 3 get string length, calculate start of string data and |
10015 // calculate the shift of the index (0 for ASCII and 1 for two byte). | 10015 // calculate the shift of the index (0 for ASCII and 1 for two byte). |
10016 __ ldr(r0, FieldMemOperand(subject, String::kLengthOffset)); | 10016 __ ldr(r0, FieldMemOperand(subject, String::kLengthOffset)); |
10017 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); | 10017 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); |
10018 ASSERT_EQ(SeqAsciiString::kHeaderSize, SeqTwoByteString::kHeaderSize); | 10018 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); |
10019 __ add(r9, subject, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 10019 __ add(r9, subject, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
10020 __ eor(r3, r3, Operand(1)); | 10020 __ eor(r3, r3, Operand(1)); |
10021 // Argument 4 (r3): End of string data | 10021 // Argument 4 (r3): End of string data |
10022 // Argument 3 (r2): Start of string data | 10022 // Argument 3 (r2): Start of string data |
10023 __ add(r2, r9, Operand(r1, LSL, r3)); | 10023 __ add(r2, r9, Operand(r1, LSL, r3)); |
10024 __ add(r3, r9, Operand(r0, LSL, r3)); | 10024 __ add(r3, r9, Operand(r0, LSL, r3)); |
10025 | 10025 |
10026 // Argument 2 (r1): Previous index. | 10026 // Argument 2 (r1): Previous index. |
10027 // Already there | 10027 // Already there |
10028 | 10028 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10063 // For failure and exception return null. | 10063 // For failure and exception return null. |
10064 __ mov(r0, Operand(Factory::null_value())); | 10064 __ mov(r0, Operand(Factory::null_value())); |
10065 __ add(sp, sp, Operand(4 * kPointerSize)); | 10065 __ add(sp, sp, Operand(4 * kPointerSize)); |
10066 __ Ret(); | 10066 __ Ret(); |
10067 | 10067 |
10068 // Process the result from the native regexp code. | 10068 // Process the result from the native regexp code. |
10069 __ bind(&success); | 10069 __ bind(&success); |
10070 __ ldr(r1, | 10070 __ ldr(r1, |
10071 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); | 10071 FieldMemOperand(regexp_data, JSRegExp::kIrregexpCaptureCountOffset)); |
10072 // Calculate number of capture registers (number_of_captures + 1) * 2. | 10072 // Calculate number of capture registers (number_of_captures + 1) * 2. |
10073 ASSERT_EQ(0, kSmiTag); | 10073 STATIC_ASSERT(kSmiTag == 0); |
10074 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 10074 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
10075 __ add(r1, r1, Operand(2)); // r1 was a smi. | 10075 __ add(r1, r1, Operand(2)); // r1 was a smi. |
10076 | 10076 |
10077 // r1: number of capture registers | 10077 // r1: number of capture registers |
10078 // r4: subject string | 10078 // r4: subject string |
10079 // Store the capture count. | 10079 // Store the capture count. |
10080 __ mov(r2, Operand(r1, LSL, kSmiTagSize + kSmiShiftSize)); // To smi. | 10080 __ mov(r2, Operand(r1, LSL, kSmiTagSize + kSmiShiftSize)); // To smi. |
10081 __ str(r2, FieldMemOperand(last_match_info_elements, | 10081 __ str(r2, FieldMemOperand(last_match_info_elements, |
10082 RegExpImpl::kLastCaptureCountOffset)); | 10082 RegExpImpl::kLastCaptureCountOffset)); |
10083 // Store last subject and last input. | 10083 // Store last subject and last input. |
10084 __ mov(r3, last_match_info_elements); // Moved up to reduce latency. | 10084 __ mov(r3, last_match_info_elements); // Moved up to reduce latency. |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10276 // Put smi-tagged index into scratch register. | 10276 // Put smi-tagged index into scratch register. |
10277 __ mov(scratch_, index_); | 10277 __ mov(scratch_, index_); |
10278 __ bind(&got_smi_index_); | 10278 __ bind(&got_smi_index_); |
10279 | 10279 |
10280 // Check for index out of range. | 10280 // Check for index out of range. |
10281 __ ldr(ip, FieldMemOperand(object_, String::kLengthOffset)); | 10281 __ ldr(ip, FieldMemOperand(object_, String::kLengthOffset)); |
10282 __ cmp(ip, Operand(scratch_)); | 10282 __ cmp(ip, Operand(scratch_)); |
10283 __ b(ls, index_out_of_range_); | 10283 __ b(ls, index_out_of_range_); |
10284 | 10284 |
10285 // We need special handling for non-flat strings. | 10285 // We need special handling for non-flat strings. |
10286 ASSERT(kSeqStringTag == 0); | 10286 STATIC_ASSERT(kSeqStringTag == 0); |
10287 __ tst(result_, Operand(kStringRepresentationMask)); | 10287 __ tst(result_, Operand(kStringRepresentationMask)); |
10288 __ b(eq, &flat_string); | 10288 __ b(eq, &flat_string); |
10289 | 10289 |
10290 // Handle non-flat strings. | 10290 // Handle non-flat strings. |
10291 __ tst(result_, Operand(kIsConsStringMask)); | 10291 __ tst(result_, Operand(kIsConsStringMask)); |
10292 __ b(eq, &call_runtime_); | 10292 __ b(eq, &call_runtime_); |
10293 | 10293 |
10294 // ConsString. | 10294 // ConsString. |
10295 // Check whether the right hand side is the empty string (i.e. if | 10295 // Check whether the right hand side is the empty string (i.e. if |
10296 // this is really a flat string in a cons string). If that is not | 10296 // this is really a flat string in a cons string). If that is not |
10297 // the case we would rather go to the runtime system now to flatten | 10297 // the case we would rather go to the runtime system now to flatten |
10298 // the string. | 10298 // the string. |
10299 __ ldr(result_, FieldMemOperand(object_, ConsString::kSecondOffset)); | 10299 __ ldr(result_, FieldMemOperand(object_, ConsString::kSecondOffset)); |
10300 __ LoadRoot(ip, Heap::kEmptyStringRootIndex); | 10300 __ LoadRoot(ip, Heap::kEmptyStringRootIndex); |
10301 __ cmp(result_, Operand(ip)); | 10301 __ cmp(result_, Operand(ip)); |
10302 __ b(ne, &call_runtime_); | 10302 __ b(ne, &call_runtime_); |
10303 // Get the first of the two strings and load its instance type. | 10303 // Get the first of the two strings and load its instance type. |
10304 __ ldr(object_, FieldMemOperand(object_, ConsString::kFirstOffset)); | 10304 __ ldr(object_, FieldMemOperand(object_, ConsString::kFirstOffset)); |
10305 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); | 10305 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
10306 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); | 10306 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
10307 // If the first cons component is also non-flat, then go to runtime. | 10307 // If the first cons component is also non-flat, then go to runtime. |
10308 ASSERT(kSeqStringTag == 0); | 10308 STATIC_ASSERT(kSeqStringTag == 0); |
10309 __ tst(result_, Operand(kStringRepresentationMask)); | 10309 __ tst(result_, Operand(kStringRepresentationMask)); |
10310 __ b(nz, &call_runtime_); | 10310 __ b(nz, &call_runtime_); |
10311 | 10311 |
10312 // Check for 1-byte or 2-byte string. | 10312 // Check for 1-byte or 2-byte string. |
10313 __ bind(&flat_string); | 10313 __ bind(&flat_string); |
10314 ASSERT(kAsciiStringTag != 0); | 10314 STATIC_ASSERT(kAsciiStringTag != 0); |
10315 __ tst(result_, Operand(kStringEncodingMask)); | 10315 __ tst(result_, Operand(kStringEncodingMask)); |
10316 __ b(nz, &ascii_string); | 10316 __ b(nz, &ascii_string); |
10317 | 10317 |
10318 // 2-byte string. | 10318 // 2-byte string. |
10319 // Load the 2-byte character code into the result register. We can | 10319 // Load the 2-byte character code into the result register. We can |
10320 // add without shifting since the smi tag size is the log2 of the | 10320 // add without shifting since the smi tag size is the log2 of the |
10321 // number of bytes in a two-byte character. | 10321 // number of bytes in a two-byte character. |
10322 ASSERT(kSmiTag == 0 && kSmiTagSize == 1 && kSmiShiftSize == 0); | 10322 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1 && kSmiShiftSize == 0); |
10323 __ add(scratch_, object_, Operand(scratch_)); | 10323 __ add(scratch_, object_, Operand(scratch_)); |
10324 __ ldrh(result_, FieldMemOperand(scratch_, SeqTwoByteString::kHeaderSize)); | 10324 __ ldrh(result_, FieldMemOperand(scratch_, SeqTwoByteString::kHeaderSize)); |
10325 __ jmp(&got_char_code); | 10325 __ jmp(&got_char_code); |
10326 | 10326 |
10327 // ASCII string. | 10327 // ASCII string. |
10328 // Load the byte into the result register. | 10328 // Load the byte into the result register. |
10329 __ bind(&ascii_string); | 10329 __ bind(&ascii_string); |
10330 __ add(scratch_, object_, Operand(scratch_, LSR, kSmiTagSize)); | 10330 __ add(scratch_, object_, Operand(scratch_, LSR, kSmiTagSize)); |
10331 __ ldrb(result_, FieldMemOperand(scratch_, SeqAsciiString::kHeaderSize)); | 10331 __ ldrb(result_, FieldMemOperand(scratch_, SeqAsciiString::kHeaderSize)); |
10332 | 10332 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10389 | 10389 |
10390 __ Abort("Unexpected fallthrough from CharCodeAt slow case"); | 10390 __ Abort("Unexpected fallthrough from CharCodeAt slow case"); |
10391 } | 10391 } |
10392 | 10392 |
10393 | 10393 |
10394 // ------------------------------------------------------------------------- | 10394 // ------------------------------------------------------------------------- |
10395 // StringCharFromCodeGenerator | 10395 // StringCharFromCodeGenerator |
10396 | 10396 |
10397 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { | 10397 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { |
10398 // Fast case of Heap::LookupSingleCharacterStringFromCode. | 10398 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
10399 ASSERT(kSmiTag == 0); | 10399 STATIC_ASSERT(kSmiTag == 0); |
10400 ASSERT(kSmiShiftSize == 0); | 10400 STATIC_ASSERT(kSmiShiftSize == 0); |
10401 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); | 10401 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
10402 __ tst(code_, | 10402 __ tst(code_, |
10403 Operand(kSmiTagMask | | 10403 Operand(kSmiTagMask | |
10404 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); | 10404 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
10405 __ b(nz, &slow_case_); | 10405 __ b(nz, &slow_case_); |
10406 | 10406 |
10407 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); | 10407 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); |
10408 // At this point code register contains smi tagged ascii char code. | 10408 // At this point code register contains smi tagged ascii char code. |
10409 ASSERT(kSmiTag == 0); | 10409 STATIC_ASSERT(kSmiTag == 0); |
10410 __ add(result_, result_, Operand(code_, LSL, kPointerSizeLog2 - kSmiTagSize)); | 10410 __ add(result_, result_, Operand(code_, LSL, kPointerSizeLog2 - kSmiTagSize)); |
10411 __ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); | 10411 __ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); |
10412 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 10412 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
10413 __ cmp(result_, Operand(ip)); | 10413 __ cmp(result_, Operand(ip)); |
10414 __ b(eq, &slow_case_); | 10414 __ b(eq, &slow_case_); |
10415 __ bind(&exit_); | 10415 __ bind(&exit_); |
10416 } | 10416 } |
10417 | 10417 |
10418 | 10418 |
10419 void StringCharFromCodeGenerator::GenerateSlow( | 10419 void StringCharFromCodeGenerator::GenerateSlow( |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10504 // that it is. | 10504 // that it is. |
10505 __ tst(dest, Operand(kPointerAlignmentMask)); | 10505 __ tst(dest, Operand(kPointerAlignmentMask)); |
10506 __ Check(eq, "Destination of copy not aligned."); | 10506 __ Check(eq, "Destination of copy not aligned."); |
10507 } | 10507 } |
10508 | 10508 |
10509 const int kReadAlignment = 4; | 10509 const int kReadAlignment = 4; |
10510 const int kReadAlignmentMask = kReadAlignment - 1; | 10510 const int kReadAlignmentMask = kReadAlignment - 1; |
10511 // Ensure that reading an entire aligned word containing the last character | 10511 // Ensure that reading an entire aligned word containing the last character |
10512 // of a string will not read outside the allocated area (because we pad up | 10512 // of a string will not read outside the allocated area (because we pad up |
10513 // to kObjectAlignment). | 10513 // to kObjectAlignment). |
10514 ASSERT(kObjectAlignment >= kReadAlignment); | 10514 STATIC_ASSERT(kObjectAlignment >= kReadAlignment); |
10515 // Assumes word reads and writes are little endian. | 10515 // Assumes word reads and writes are little endian. |
10516 // Nothing to do for zero characters. | 10516 // Nothing to do for zero characters. |
10517 Label done; | 10517 Label done; |
10518 if (!ascii) { | 10518 if (!ascii) { |
10519 __ add(count, count, Operand(count), SetCC); | 10519 __ add(count, count, Operand(count), SetCC); |
10520 } else { | 10520 } else { |
10521 __ cmp(count, Operand(0)); | 10521 __ cmp(count, Operand(0)); |
10522 } | 10522 } |
10523 __ b(eq, &done); | 10523 __ b(eq, &done); |
10524 | 10524 |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10708 // Calculate entry in symbol table. | 10708 // Calculate entry in symbol table. |
10709 if (i > 0) { | 10709 if (i > 0) { |
10710 __ add(candidate, hash, Operand(SymbolTable::GetProbeOffset(i))); | 10710 __ add(candidate, hash, Operand(SymbolTable::GetProbeOffset(i))); |
10711 } else { | 10711 } else { |
10712 __ mov(candidate, hash); | 10712 __ mov(candidate, hash); |
10713 } | 10713 } |
10714 | 10714 |
10715 __ and_(candidate, candidate, Operand(mask)); | 10715 __ and_(candidate, candidate, Operand(mask)); |
10716 | 10716 |
10717 // Load the entry from the symble table. | 10717 // Load the entry from the symble table. |
10718 ASSERT_EQ(1, SymbolTable::kEntrySize); | 10718 STATIC_ASSERT(SymbolTable::kEntrySize == 1); |
10719 __ ldr(candidate, | 10719 __ ldr(candidate, |
10720 MemOperand(first_symbol_table_element, | 10720 MemOperand(first_symbol_table_element, |
10721 candidate, | 10721 candidate, |
10722 LSL, | 10722 LSL, |
10723 kPointerSizeLog2)); | 10723 kPointerSizeLog2)); |
10724 | 10724 |
10725 // If entry is undefined no string with this hash can be found. | 10725 // If entry is undefined no string with this hash can be found. |
10726 __ cmp(candidate, undefined); | 10726 __ cmp(candidate, undefined); |
10727 __ b(eq, not_found); | 10727 __ b(eq, not_found); |
10728 | 10728 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10808 // If any of these assumptions fail, we call the runtime system. | 10808 // If any of these assumptions fail, we call the runtime system. |
10809 | 10809 |
10810 static const int kToOffset = 0 * kPointerSize; | 10810 static const int kToOffset = 0 * kPointerSize; |
10811 static const int kFromOffset = 1 * kPointerSize; | 10811 static const int kFromOffset = 1 * kPointerSize; |
10812 static const int kStringOffset = 2 * kPointerSize; | 10812 static const int kStringOffset = 2 * kPointerSize; |
10813 | 10813 |
10814 | 10814 |
10815 // Check bounds and smi-ness. | 10815 // Check bounds and smi-ness. |
10816 __ ldr(r7, MemOperand(sp, kToOffset)); | 10816 __ ldr(r7, MemOperand(sp, kToOffset)); |
10817 __ ldr(r6, MemOperand(sp, kFromOffset)); | 10817 __ ldr(r6, MemOperand(sp, kFromOffset)); |
10818 ASSERT_EQ(0, kSmiTag); | 10818 STATIC_ASSERT(kSmiTag == 0); |
10819 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 10819 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
10820 // I.e., arithmetic shift right by one un-smi-tags. | 10820 // I.e., arithmetic shift right by one un-smi-tags. |
10821 __ mov(r2, Operand(r7, ASR, 1), SetCC); | 10821 __ mov(r2, Operand(r7, ASR, 1), SetCC); |
10822 __ mov(r3, Operand(r6, ASR, 1), SetCC, cc); | 10822 __ mov(r3, Operand(r6, ASR, 1), SetCC, cc); |
10823 // If either r2 or r6 had the smi tag bit set, then carry is set now. | 10823 // If either r2 or r6 had the smi tag bit set, then carry is set now. |
10824 __ b(cs, &runtime); // Either "from" or "to" is not a smi. | 10824 __ b(cs, &runtime); // Either "from" or "to" is not a smi. |
10825 __ b(mi, &runtime); // From is negative. | 10825 __ b(mi, &runtime); // From is negative. |
10826 | 10826 |
10827 __ sub(r2, r2, Operand(r3), SetCC); | 10827 __ sub(r2, r2, Operand(r3), SetCC); |
10828 __ b(mi, &runtime); // Fail if from > to. | 10828 __ b(mi, &runtime); // Fail if from > to. |
10829 // Special handling of sub-strings of length 1 and 2. One character strings | 10829 // Special handling of sub-strings of length 1 and 2. One character strings |
10830 // are handled in the runtime system (looked up in the single character | 10830 // are handled in the runtime system (looked up in the single character |
10831 // cache). Two character strings are looked for in the symbol cache. | 10831 // cache). Two character strings are looked for in the symbol cache. |
10832 __ cmp(r2, Operand(2)); | 10832 __ cmp(r2, Operand(2)); |
10833 __ b(lt, &runtime); | 10833 __ b(lt, &runtime); |
10834 | 10834 |
10835 // r2: length | 10835 // r2: length |
10836 // r3: from index (untaged smi) | 10836 // r3: from index (untaged smi) |
10837 // r6: from (smi) | 10837 // r6: from (smi) |
10838 // r7: to (smi) | 10838 // r7: to (smi) |
10839 | 10839 |
10840 // Make sure first argument is a sequential (or flat) string. | 10840 // Make sure first argument is a sequential (or flat) string. |
10841 __ ldr(r5, MemOperand(sp, kStringOffset)); | 10841 __ ldr(r5, MemOperand(sp, kStringOffset)); |
10842 ASSERT_EQ(0, kSmiTag); | 10842 STATIC_ASSERT(kSmiTag == 0); |
10843 __ tst(r5, Operand(kSmiTagMask)); | 10843 __ tst(r5, Operand(kSmiTagMask)); |
10844 __ b(eq, &runtime); | 10844 __ b(eq, &runtime); |
10845 Condition is_string = masm->IsObjectStringType(r5, r1); | 10845 Condition is_string = masm->IsObjectStringType(r5, r1); |
10846 __ b(NegateCondition(is_string), &runtime); | 10846 __ b(NegateCondition(is_string), &runtime); |
10847 | 10847 |
10848 // r1: instance type | 10848 // r1: instance type |
10849 // r2: length | 10849 // r2: length |
10850 // r3: from index (untaged smi) | 10850 // r3: from index (untaged smi) |
10851 // r5: string | 10851 // r5: string |
10852 // r6: from (smi) | 10852 // r6: from (smi) |
10853 // r7: to (smi) | 10853 // r7: to (smi) |
10854 Label seq_string; | 10854 Label seq_string; |
10855 __ and_(r4, r1, Operand(kStringRepresentationMask)); | 10855 __ and_(r4, r1, Operand(kStringRepresentationMask)); |
10856 ASSERT(kSeqStringTag < kConsStringTag); | 10856 STATIC_ASSERT(kSeqStringTag < kConsStringTag); |
10857 ASSERT(kExternalStringTag > kConsStringTag); | 10857 STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
10858 __ cmp(r4, Operand(kConsStringTag)); | 10858 __ cmp(r4, Operand(kConsStringTag)); |
10859 __ b(gt, &runtime); // External strings go to runtime. | 10859 __ b(gt, &runtime); // External strings go to runtime. |
10860 __ b(lt, &seq_string); // Sequential strings are handled directly. | 10860 __ b(lt, &seq_string); // Sequential strings are handled directly. |
10861 | 10861 |
10862 // Cons string. Try to recurse (once) on the first substring. | 10862 // Cons string. Try to recurse (once) on the first substring. |
10863 // (This adds a little more generality than necessary to handle flattened | 10863 // (This adds a little more generality than necessary to handle flattened |
10864 // cons strings, but not much). | 10864 // cons strings, but not much). |
10865 __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset)); | 10865 __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset)); |
10866 __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); | 10866 __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); |
10867 __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 10867 __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
10868 __ tst(r1, Operand(kStringRepresentationMask)); | 10868 __ tst(r1, Operand(kStringRepresentationMask)); |
10869 ASSERT_EQ(0, kSeqStringTag); | 10869 STATIC_ASSERT(kSeqStringTag == 0); |
10870 __ b(ne, &runtime); // Cons and External strings go to runtime. | 10870 __ b(ne, &runtime); // Cons and External strings go to runtime. |
10871 | 10871 |
10872 // Definitly a sequential string. | 10872 // Definitly a sequential string. |
10873 __ bind(&seq_string); | 10873 __ bind(&seq_string); |
10874 | 10874 |
10875 // r1: instance type. | 10875 // r1: instance type. |
10876 // r2: length | 10876 // r2: length |
10877 // r3: from index (untaged smi) | 10877 // r3: from index (untaged smi) |
10878 // r5: string | 10878 // r5: string |
10879 // r6: from (smi) | 10879 // r6: from (smi) |
10880 // r7: to (smi) | 10880 // r7: to (smi) |
10881 __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset)); | 10881 __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset)); |
10882 __ cmp(r4, Operand(r7)); | 10882 __ cmp(r4, Operand(r7)); |
10883 __ b(lt, &runtime); // Fail if to > length. | 10883 __ b(lt, &runtime); // Fail if to > length. |
10884 | 10884 |
10885 // r1: instance type. | 10885 // r1: instance type. |
10886 // r2: result string length. | 10886 // r2: result string length. |
10887 // r3: from index (untaged smi) | 10887 // r3: from index (untaged smi) |
10888 // r5: string. | 10888 // r5: string. |
10889 // r6: from offset (smi) | 10889 // r6: from offset (smi) |
10890 // Check for flat ascii string. | 10890 // Check for flat ascii string. |
10891 Label non_ascii_flat; | 10891 Label non_ascii_flat; |
10892 __ tst(r1, Operand(kStringEncodingMask)); | 10892 __ tst(r1, Operand(kStringEncodingMask)); |
10893 ASSERT_EQ(0, kTwoByteStringTag); | 10893 STATIC_ASSERT(kTwoByteStringTag == 0); |
10894 __ b(eq, &non_ascii_flat); | 10894 __ b(eq, &non_ascii_flat); |
10895 | 10895 |
10896 Label result_longer_than_two; | 10896 Label result_longer_than_two; |
10897 __ cmp(r2, Operand(2)); | 10897 __ cmp(r2, Operand(2)); |
10898 __ b(gt, &result_longer_than_two); | 10898 __ b(gt, &result_longer_than_two); |
10899 | 10899 |
10900 // Sub string of length 2 requested. | 10900 // Sub string of length 2 requested. |
10901 // Get the two characters forming the sub string. | 10901 // Get the two characters forming the sub string. |
10902 __ add(r5, r5, Operand(r3)); | 10902 __ add(r5, r5, Operand(r3)); |
10903 __ ldrb(r3, FieldMemOperand(r5, SeqAsciiString::kHeaderSize)); | 10903 __ ldrb(r3, FieldMemOperand(r5, SeqAsciiString::kHeaderSize)); |
(...skipping 28 matching lines...) Expand all Loading... |
10932 // Locate first character of result. | 10932 // Locate first character of result. |
10933 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 10933 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
10934 // Locate 'from' character of string. | 10934 // Locate 'from' character of string. |
10935 __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 10935 __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
10936 __ add(r5, r5, Operand(r6, ASR, 1)); | 10936 __ add(r5, r5, Operand(r6, ASR, 1)); |
10937 | 10937 |
10938 // r0: result string. | 10938 // r0: result string. |
10939 // r1: first character of result string. | 10939 // r1: first character of result string. |
10940 // r2: result string length. | 10940 // r2: result string length. |
10941 // r5: first character of sub string to copy. | 10941 // r5: first character of sub string to copy. |
10942 ASSERT_EQ(0, SeqAsciiString::kHeaderSize & kObjectAlignmentMask); | 10942 STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); |
10943 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, | 10943 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, |
10944 COPY_ASCII | DEST_ALWAYS_ALIGNED); | 10944 COPY_ASCII | DEST_ALWAYS_ALIGNED); |
10945 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); | 10945 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
10946 __ add(sp, sp, Operand(3 * kPointerSize)); | 10946 __ add(sp, sp, Operand(3 * kPointerSize)); |
10947 __ Ret(); | 10947 __ Ret(); |
10948 | 10948 |
10949 __ bind(&non_ascii_flat); | 10949 __ bind(&non_ascii_flat); |
10950 // r2: result string length. | 10950 // r2: result string length. |
10951 // r5: string. | 10951 // r5: string. |
10952 // r6: from offset (smi) | 10952 // r6: from offset (smi) |
(...skipping 10 matching lines...) Expand all Loading... |
10963 // Locate 'from' character of string. | 10963 // Locate 'from' character of string. |
10964 __ add(r5, r5, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 10964 __ add(r5, r5, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
10965 // As "from" is a smi it is 2 times the value which matches the size of a two | 10965 // As "from" is a smi it is 2 times the value which matches the size of a two |
10966 // byte character. | 10966 // byte character. |
10967 __ add(r5, r5, Operand(r6)); | 10967 __ add(r5, r5, Operand(r6)); |
10968 | 10968 |
10969 // r0: result string. | 10969 // r0: result string. |
10970 // r1: first character of result. | 10970 // r1: first character of result. |
10971 // r2: result length. | 10971 // r2: result length. |
10972 // r5: first character of string to copy. | 10972 // r5: first character of string to copy. |
10973 ASSERT_EQ(0, SeqTwoByteString::kHeaderSize & kObjectAlignmentMask); | 10973 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); |
10974 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, | 10974 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, |
10975 DEST_ALWAYS_ALIGNED); | 10975 DEST_ALWAYS_ALIGNED); |
10976 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); | 10976 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
10977 __ add(sp, sp, Operand(3 * kPointerSize)); | 10977 __ add(sp, sp, Operand(3 * kPointerSize)); |
10978 __ Ret(); | 10978 __ Ret(); |
10979 | 10979 |
10980 // Just jump to runtime to create the sub string. | 10980 // Just jump to runtime to create the sub string. |
10981 __ bind(&runtime); | 10981 __ bind(&runtime); |
10982 __ TailCallRuntime(Runtime::kSubString, 3, 1); | 10982 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
10983 } | 10983 } |
10984 | 10984 |
10985 | 10985 |
10986 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 10986 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
10987 Register left, | 10987 Register left, |
10988 Register right, | 10988 Register right, |
10989 Register scratch1, | 10989 Register scratch1, |
10990 Register scratch2, | 10990 Register scratch2, |
10991 Register scratch3, | 10991 Register scratch3, |
10992 Register scratch4) { | 10992 Register scratch4) { |
10993 Label compare_lengths; | 10993 Label compare_lengths; |
10994 // Find minimum length and length difference. | 10994 // Find minimum length and length difference. |
10995 __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset)); | 10995 __ ldr(scratch1, FieldMemOperand(left, String::kLengthOffset)); |
10996 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); | 10996 __ ldr(scratch2, FieldMemOperand(right, String::kLengthOffset)); |
10997 __ sub(scratch3, scratch1, Operand(scratch2), SetCC); | 10997 __ sub(scratch3, scratch1, Operand(scratch2), SetCC); |
10998 Register length_delta = scratch3; | 10998 Register length_delta = scratch3; |
10999 __ mov(scratch1, scratch2, LeaveCC, gt); | 10999 __ mov(scratch1, scratch2, LeaveCC, gt); |
11000 Register min_length = scratch1; | 11000 Register min_length = scratch1; |
11001 ASSERT(kSmiTag == 0); | 11001 STATIC_ASSERT(kSmiTag == 0); |
11002 __ tst(min_length, Operand(min_length)); | 11002 __ tst(min_length, Operand(min_length)); |
11003 __ b(eq, &compare_lengths); | 11003 __ b(eq, &compare_lengths); |
11004 | 11004 |
11005 // Untag smi. | 11005 // Untag smi. |
11006 __ mov(min_length, Operand(min_length, ASR, kSmiTagSize)); | 11006 __ mov(min_length, Operand(min_length, ASR, kSmiTagSize)); |
11007 | 11007 |
11008 // Setup registers so that we only need to increment one register | 11008 // Setup registers so that we only need to increment one register |
11009 // in the loop. | 11009 // in the loop. |
11010 __ add(scratch2, min_length, | 11010 __ add(scratch2, min_length, |
11011 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 11011 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11047 | 11047 |
11048 // Stack frame on entry. | 11048 // Stack frame on entry. |
11049 // sp[0]: right string | 11049 // sp[0]: right string |
11050 // sp[4]: left string | 11050 // sp[4]: left string |
11051 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // left | 11051 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // left |
11052 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // right | 11052 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // right |
11053 | 11053 |
11054 Label not_same; | 11054 Label not_same; |
11055 __ cmp(r0, r1); | 11055 __ cmp(r0, r1); |
11056 __ b(ne, ¬_same); | 11056 __ b(ne, ¬_same); |
11057 ASSERT_EQ(0, EQUAL); | 11057 STATIC_ASSERT(EQUAL == 0); |
11058 ASSERT_EQ(0, kSmiTag); | 11058 STATIC_ASSERT(kSmiTag == 0); |
11059 __ mov(r0, Operand(Smi::FromInt(EQUAL))); | 11059 __ mov(r0, Operand(Smi::FromInt(EQUAL))); |
11060 __ IncrementCounter(&Counters::string_compare_native, 1, r1, r2); | 11060 __ IncrementCounter(&Counters::string_compare_native, 1, r1, r2); |
11061 __ add(sp, sp, Operand(2 * kPointerSize)); | 11061 __ add(sp, sp, Operand(2 * kPointerSize)); |
11062 __ Ret(); | 11062 __ Ret(); |
11063 | 11063 |
11064 __ bind(¬_same); | 11064 __ bind(¬_same); |
11065 | 11065 |
11066 // Check that both objects are sequential ascii strings. | 11066 // Check that both objects are sequential ascii strings. |
11067 __ JumpIfNotBothSequentialAsciiStrings(r0, r1, r2, r3, &runtime); | 11067 __ JumpIfNotBothSequentialAsciiStrings(r0, r1, r2, r3, &runtime); |
11068 | 11068 |
(...skipping 14 matching lines...) Expand all Loading... |
11083 // Stack on entry: | 11083 // Stack on entry: |
11084 // sp[0]: second argument. | 11084 // sp[0]: second argument. |
11085 // sp[4]: first argument. | 11085 // sp[4]: first argument. |
11086 | 11086 |
11087 // Load the two arguments. | 11087 // Load the two arguments. |
11088 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument. | 11088 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument. |
11089 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument. | 11089 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument. |
11090 | 11090 |
11091 // Make sure that both arguments are strings if not known in advance. | 11091 // Make sure that both arguments are strings if not known in advance. |
11092 if (string_check_) { | 11092 if (string_check_) { |
11093 ASSERT_EQ(0, kSmiTag); | 11093 STATIC_ASSERT(kSmiTag == 0); |
11094 __ JumpIfEitherSmi(r0, r1, &string_add_runtime); | 11094 __ JumpIfEitherSmi(r0, r1, &string_add_runtime); |
11095 // Load instance types. | 11095 // Load instance types. |
11096 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | 11096 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
11097 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | 11097 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
11098 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 11098 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
11099 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | 11099 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
11100 ASSERT_EQ(0, kStringTag); | 11100 STATIC_ASSERT(kStringTag == 0); |
11101 // If either is not a string, go to runtime. | 11101 // If either is not a string, go to runtime. |
11102 __ tst(r4, Operand(kIsNotStringMask)); | 11102 __ tst(r4, Operand(kIsNotStringMask)); |
11103 __ tst(r5, Operand(kIsNotStringMask), eq); | 11103 __ tst(r5, Operand(kIsNotStringMask), eq); |
11104 __ b(ne, &string_add_runtime); | 11104 __ b(ne, &string_add_runtime); |
11105 } | 11105 } |
11106 | 11106 |
11107 // Both arguments are strings. | 11107 // Both arguments are strings. |
11108 // r0: first string | 11108 // r0: first string |
11109 // r1: second string | 11109 // r1: second string |
11110 // r4: first string instance type (if string_check_) | 11110 // r4: first string instance type (if string_check_) |
11111 // r5: second string instance type (if string_check_) | 11111 // r5: second string instance type (if string_check_) |
11112 { | 11112 { |
11113 Label strings_not_empty; | 11113 Label strings_not_empty; |
11114 // Check if either of the strings are empty. In that case return the other. | 11114 // Check if either of the strings are empty. In that case return the other. |
11115 __ ldr(r2, FieldMemOperand(r0, String::kLengthOffset)); | 11115 __ ldr(r2, FieldMemOperand(r0, String::kLengthOffset)); |
11116 __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset)); | 11116 __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset)); |
11117 ASSERT(kSmiTag == 0); | 11117 STATIC_ASSERT(kSmiTag == 0); |
11118 __ cmp(r2, Operand(Smi::FromInt(0))); // Test if first string is empty. | 11118 __ cmp(r2, Operand(Smi::FromInt(0))); // Test if first string is empty. |
11119 __ mov(r0, Operand(r1), LeaveCC, eq); // If first is empty, return second. | 11119 __ mov(r0, Operand(r1), LeaveCC, eq); // If first is empty, return second. |
11120 ASSERT(kSmiTag == 0); | 11120 STATIC_ASSERT(kSmiTag == 0); |
11121 // Else test if second string is empty. | 11121 // Else test if second string is empty. |
11122 __ cmp(r3, Operand(Smi::FromInt(0)), ne); | 11122 __ cmp(r3, Operand(Smi::FromInt(0)), ne); |
11123 __ b(ne, &strings_not_empty); // If either string was empty, return r0. | 11123 __ b(ne, &strings_not_empty); // If either string was empty, return r0. |
11124 | 11124 |
11125 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); | 11125 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
11126 __ add(sp, sp, Operand(2 * kPointerSize)); | 11126 __ add(sp, sp, Operand(2 * kPointerSize)); |
11127 __ Ret(); | 11127 __ Ret(); |
11128 | 11128 |
11129 __ bind(&strings_not_empty); | 11129 __ bind(&strings_not_empty); |
11130 } | 11130 } |
11131 | 11131 |
11132 __ mov(r2, Operand(r2, ASR, kSmiTagSize)); | 11132 __ mov(r2, Operand(r2, ASR, kSmiTagSize)); |
11133 __ mov(r3, Operand(r3, ASR, kSmiTagSize)); | 11133 __ mov(r3, Operand(r3, ASR, kSmiTagSize)); |
11134 // Both strings are non-empty. | 11134 // Both strings are non-empty. |
11135 // r0: first string | 11135 // r0: first string |
11136 // r1: second string | 11136 // r1: second string |
11137 // r2: length of first string | 11137 // r2: length of first string |
11138 // r3: length of second string | 11138 // r3: length of second string |
11139 // r4: first string instance type (if string_check_) | 11139 // r4: first string instance type (if string_check_) |
11140 // r5: second string instance type (if string_check_) | 11140 // r5: second string instance type (if string_check_) |
11141 // Look at the length of the result of adding the two strings. | 11141 // Look at the length of the result of adding the two strings. |
11142 Label string_add_flat_result, longer_than_two; | 11142 Label string_add_flat_result, longer_than_two; |
11143 // Adding two lengths can't overflow. | 11143 // Adding two lengths can't overflow. |
11144 ASSERT(String::kMaxLength * 2 > String::kMaxLength); | 11144 STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2); |
11145 __ add(r6, r2, Operand(r3)); | 11145 __ add(r6, r2, Operand(r3)); |
11146 // Use the runtime system when adding two one character strings, as it | 11146 // Use the runtime system when adding two one character strings, as it |
11147 // contains optimizations for this specific case using the symbol table. | 11147 // contains optimizations for this specific case using the symbol table. |
11148 __ cmp(r6, Operand(2)); | 11148 __ cmp(r6, Operand(2)); |
11149 __ b(ne, &longer_than_two); | 11149 __ b(ne, &longer_than_two); |
11150 | 11150 |
11151 // Check that both strings are non-external ascii strings. | 11151 // Check that both strings are non-external ascii strings. |
11152 if (!string_check_) { | 11152 if (!string_check_) { |
11153 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | 11153 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
11154 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | 11154 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
(...skipping 27 matching lines...) Expand all Loading... |
11182 __ strh(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); | 11182 __ strh(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
11183 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); | 11183 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
11184 __ add(sp, sp, Operand(2 * kPointerSize)); | 11184 __ add(sp, sp, Operand(2 * kPointerSize)); |
11185 __ Ret(); | 11185 __ Ret(); |
11186 | 11186 |
11187 __ bind(&longer_than_two); | 11187 __ bind(&longer_than_two); |
11188 // Check if resulting string will be flat. | 11188 // Check if resulting string will be flat. |
11189 __ cmp(r6, Operand(String::kMinNonFlatLength)); | 11189 __ cmp(r6, Operand(String::kMinNonFlatLength)); |
11190 __ b(lt, &string_add_flat_result); | 11190 __ b(lt, &string_add_flat_result); |
11191 // Handle exceptionally long strings in the runtime system. | 11191 // Handle exceptionally long strings in the runtime system. |
11192 ASSERT((String::kMaxLength & 0x80000000) == 0); | 11192 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); |
11193 ASSERT(IsPowerOf2(String::kMaxLength + 1)); | 11193 ASSERT(IsPowerOf2(String::kMaxLength + 1)); |
11194 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. | 11194 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. |
11195 __ cmp(r6, Operand(String::kMaxLength + 1)); | 11195 __ cmp(r6, Operand(String::kMaxLength + 1)); |
11196 __ b(hs, &string_add_runtime); | 11196 __ b(hs, &string_add_runtime); |
11197 | 11197 |
11198 // If result is not supposed to be flat, allocate a cons string object. | 11198 // If result is not supposed to be flat, allocate a cons string object. |
11199 // If both strings are ascii the result is an ascii cons string. | 11199 // If both strings are ascii the result is an ascii cons string. |
11200 if (!string_check_) { | 11200 if (!string_check_) { |
11201 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | 11201 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
11202 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | 11202 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
11203 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 11203 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
11204 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | 11204 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
11205 } | 11205 } |
11206 Label non_ascii, allocated, ascii_data; | 11206 Label non_ascii, allocated, ascii_data; |
11207 ASSERT_EQ(0, kTwoByteStringTag); | 11207 STATIC_ASSERT(kTwoByteStringTag == 0); |
11208 __ tst(r4, Operand(kStringEncodingMask)); | 11208 __ tst(r4, Operand(kStringEncodingMask)); |
11209 __ tst(r5, Operand(kStringEncodingMask), ne); | 11209 __ tst(r5, Operand(kStringEncodingMask), ne); |
11210 __ b(eq, &non_ascii); | 11210 __ b(eq, &non_ascii); |
11211 | 11211 |
11212 // Allocate an ASCII cons string. | 11212 // Allocate an ASCII cons string. |
11213 __ bind(&ascii_data); | 11213 __ bind(&ascii_data); |
11214 __ AllocateAsciiConsString(r7, r6, r4, r5, &string_add_runtime); | 11214 __ AllocateAsciiConsString(r7, r6, r4, r5, &string_add_runtime); |
11215 __ bind(&allocated); | 11215 __ bind(&allocated); |
11216 // Fill the fields of the cons string. | 11216 // Fill the fields of the cons string. |
11217 __ str(r0, FieldMemOperand(r7, ConsString::kFirstOffset)); | 11217 __ str(r0, FieldMemOperand(r7, ConsString::kFirstOffset)); |
11218 __ str(r1, FieldMemOperand(r7, ConsString::kSecondOffset)); | 11218 __ str(r1, FieldMemOperand(r7, ConsString::kSecondOffset)); |
11219 __ mov(r0, Operand(r7)); | 11219 __ mov(r0, Operand(r7)); |
11220 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); | 11220 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
11221 __ add(sp, sp, Operand(2 * kPointerSize)); | 11221 __ add(sp, sp, Operand(2 * kPointerSize)); |
11222 __ Ret(); | 11222 __ Ret(); |
11223 | 11223 |
11224 __ bind(&non_ascii); | 11224 __ bind(&non_ascii); |
11225 // At least one of the strings is two-byte. Check whether it happens | 11225 // At least one of the strings is two-byte. Check whether it happens |
11226 // to contain only ascii characters. | 11226 // to contain only ascii characters. |
11227 // r4: first instance type. | 11227 // r4: first instance type. |
11228 // r5: second instance type. | 11228 // r5: second instance type. |
11229 __ tst(r4, Operand(kAsciiDataHintMask)); | 11229 __ tst(r4, Operand(kAsciiDataHintMask)); |
11230 __ tst(r5, Operand(kAsciiDataHintMask), ne); | 11230 __ tst(r5, Operand(kAsciiDataHintMask), ne); |
11231 __ b(ne, &ascii_data); | 11231 __ b(ne, &ascii_data); |
11232 __ eor(r4, r4, Operand(r5)); | 11232 __ eor(r4, r4, Operand(r5)); |
11233 ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); | 11233 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); |
11234 __ and_(r4, r4, Operand(kAsciiStringTag | kAsciiDataHintTag)); | 11234 __ and_(r4, r4, Operand(kAsciiStringTag | kAsciiDataHintTag)); |
11235 __ cmp(r4, Operand(kAsciiStringTag | kAsciiDataHintTag)); | 11235 __ cmp(r4, Operand(kAsciiStringTag | kAsciiDataHintTag)); |
11236 __ b(eq, &ascii_data); | 11236 __ b(eq, &ascii_data); |
11237 | 11237 |
11238 // Allocate a two byte cons string. | 11238 // Allocate a two byte cons string. |
11239 __ AllocateTwoByteConsString(r7, r6, r4, r5, &string_add_runtime); | 11239 __ AllocateTwoByteConsString(r7, r6, r4, r5, &string_add_runtime); |
11240 __ jmp(&allocated); | 11240 __ jmp(&allocated); |
11241 | 11241 |
11242 // Handle creating a flat result. First check that both strings are | 11242 // Handle creating a flat result. First check that both strings are |
11243 // sequential and that they have the same encoding. | 11243 // sequential and that they have the same encoding. |
11244 // r0: first string | 11244 // r0: first string |
11245 // r1: second string | 11245 // r1: second string |
11246 // r2: length of first string | 11246 // r2: length of first string |
11247 // r3: length of second string | 11247 // r3: length of second string |
11248 // r4: first string instance type (if string_check_) | 11248 // r4: first string instance type (if string_check_) |
11249 // r5: second string instance type (if string_check_) | 11249 // r5: second string instance type (if string_check_) |
11250 // r6: sum of lengths. | 11250 // r6: sum of lengths. |
11251 __ bind(&string_add_flat_result); | 11251 __ bind(&string_add_flat_result); |
11252 if (!string_check_) { | 11252 if (!string_check_) { |
11253 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | 11253 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
11254 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | 11254 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
11255 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 11255 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
11256 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | 11256 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
11257 } | 11257 } |
11258 // Check that both strings are sequential. | 11258 // Check that both strings are sequential. |
11259 ASSERT_EQ(0, kSeqStringTag); | 11259 STATIC_ASSERT(kSeqStringTag == 0); |
11260 __ tst(r4, Operand(kStringRepresentationMask)); | 11260 __ tst(r4, Operand(kStringRepresentationMask)); |
11261 __ tst(r5, Operand(kStringRepresentationMask), eq); | 11261 __ tst(r5, Operand(kStringRepresentationMask), eq); |
11262 __ b(ne, &string_add_runtime); | 11262 __ b(ne, &string_add_runtime); |
11263 // Now check if both strings have the same encoding (ASCII/Two-byte). | 11263 // Now check if both strings have the same encoding (ASCII/Two-byte). |
11264 // r0: first string. | 11264 // r0: first string. |
11265 // r1: second string. | 11265 // r1: second string. |
11266 // r2: length of first string. | 11266 // r2: length of first string. |
11267 // r3: length of second string. | 11267 // r3: length of second string. |
11268 // r6: sum of lengths.. | 11268 // r6: sum of lengths.. |
11269 Label non_ascii_string_add_flat_result; | 11269 Label non_ascii_string_add_flat_result; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11348 __ bind(&string_add_runtime); | 11348 __ bind(&string_add_runtime); |
11349 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 11349 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
11350 } | 11350 } |
11351 | 11351 |
11352 | 11352 |
11353 #undef __ | 11353 #undef __ |
11354 | 11354 |
11355 } } // namespace v8::internal | 11355 } } // namespace v8::internal |
11356 | 11356 |
11357 #endif // V8_TARGET_ARCH_ARM | 11357 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |