| 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 |