| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 #include "src/code-stub-assembler.h" | 4 #include "src/code-stub-assembler.h" |
| 5 #include "src/code-factory.h" | 5 #include "src/code-factory.h" |
| 6 #include "src/frames-inl.h" | 6 #include "src/frames-inl.h" |
| 7 #include "src/frames.h" | 7 #include "src/frames.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 1547 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1558 Node* CodeStubAssembler::AllocateHeapNumberWithValue(Node* value, | 1558 Node* CodeStubAssembler::AllocateHeapNumberWithValue(Node* value, |
| 1559 MutableMode mode) { | 1559 MutableMode mode) { |
| 1560 Node* result = AllocateHeapNumber(mode); | 1560 Node* result = AllocateHeapNumber(mode); |
| 1561 StoreHeapNumberValue(result, value); | 1561 StoreHeapNumberValue(result, value); |
| 1562 return result; | 1562 return result; |
| 1563 } | 1563 } |
| 1564 | 1564 |
| 1565 Node* CodeStubAssembler::AllocateSeqOneByteString(int length, | 1565 Node* CodeStubAssembler::AllocateSeqOneByteString(int length, |
| 1566 AllocationFlags flags) { | 1566 AllocationFlags flags) { |
| 1567 Comment("AllocateSeqOneByteString"); | 1567 Comment("AllocateSeqOneByteString"); |
| 1568 if (length == 0) { | |
| 1569 return LoadRoot(Heap::kempty_stringRootIndex); | |
| 1570 } | |
| 1571 Node* result = Allocate(SeqOneByteString::SizeFor(length), flags); | 1568 Node* result = Allocate(SeqOneByteString::SizeFor(length), flags); |
| 1572 DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex)); | 1569 DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex)); |
| 1573 StoreMapNoWriteBarrier(result, Heap::kOneByteStringMapRootIndex); | 1570 StoreMapNoWriteBarrier(result, Heap::kOneByteStringMapRootIndex); |
| 1574 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset, | 1571 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset, |
| 1575 SmiConstant(Smi::FromInt(length))); | 1572 SmiConstant(Smi::FromInt(length))); |
| 1576 // Initialize both used and unused parts of hash field slot at once. | 1573 // Initialize both used and unused parts of hash field slot at once. |
| 1577 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldSlot, | 1574 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldSlot, |
| 1578 IntPtrConstant(String::kEmptyHashField), | 1575 IntPtrConstant(String::kEmptyHashField), |
| 1579 MachineType::PointerRepresentation()); | 1576 MachineType::PointerRepresentation()); |
| 1580 return result; | 1577 return result; |
| 1581 } | 1578 } |
| 1582 | 1579 |
| 1583 Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length, | 1580 Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length, |
| 1584 ParameterMode mode, | 1581 ParameterMode mode, |
| 1585 AllocationFlags flags) { | 1582 AllocationFlags flags) { |
| 1586 Comment("AllocateSeqOneByteString"); | 1583 Comment("AllocateSeqOneByteString"); |
| 1587 Variable var_result(this, MachineRepresentation::kTagged); | 1584 Variable var_result(this, MachineRepresentation::kTagged); |
| 1588 | 1585 |
| 1589 // Compute the SeqOneByteString size and check if it fits into new space. | 1586 // Compute the SeqOneByteString size and check if it fits into new space. |
| 1590 Label if_lengthiszero(this), if_sizeissmall(this), | 1587 Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), |
| 1591 if_notsizeissmall(this, Label::kDeferred), if_join(this); | 1588 if_join(this); |
| 1592 GotoIf(WordEqual(length, IntPtrOrSmiConstant(0, mode)), &if_lengthiszero); | |
| 1593 | |
| 1594 Node* raw_size = GetArrayAllocationSize( | 1589 Node* raw_size = GetArrayAllocationSize( |
| 1595 length, UINT8_ELEMENTS, mode, | 1590 length, UINT8_ELEMENTS, mode, |
| 1596 SeqOneByteString::kHeaderSize + kObjectAlignmentMask); | 1591 SeqOneByteString::kHeaderSize + kObjectAlignmentMask); |
| 1597 Node* size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); | 1592 Node* size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); |
| 1598 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), | 1593 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), |
| 1599 &if_sizeissmall, &if_notsizeissmall); | 1594 &if_sizeissmall, &if_notsizeissmall); |
| 1600 | 1595 |
| 1601 Bind(&if_sizeissmall); | 1596 Bind(&if_sizeissmall); |
| 1602 { | 1597 { |
| 1603 // Just allocate the SeqOneByteString in new space. | 1598 // Just allocate the SeqOneByteString in new space. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1616 | 1611 |
| 1617 Bind(&if_notsizeissmall); | 1612 Bind(&if_notsizeissmall); |
| 1618 { | 1613 { |
| 1619 // We might need to allocate in large object space, go to the runtime. | 1614 // We might need to allocate in large object space, go to the runtime. |
| 1620 Node* result = CallRuntime(Runtime::kAllocateSeqOneByteString, context, | 1615 Node* result = CallRuntime(Runtime::kAllocateSeqOneByteString, context, |
| 1621 ParameterToTagged(length, mode)); | 1616 ParameterToTagged(length, mode)); |
| 1622 var_result.Bind(result); | 1617 var_result.Bind(result); |
| 1623 Goto(&if_join); | 1618 Goto(&if_join); |
| 1624 } | 1619 } |
| 1625 | 1620 |
| 1626 Bind(&if_lengthiszero); | |
| 1627 { | |
| 1628 var_result.Bind(LoadRoot(Heap::kempty_stringRootIndex)); | |
| 1629 Goto(&if_join); | |
| 1630 } | |
| 1631 | |
| 1632 Bind(&if_join); | 1621 Bind(&if_join); |
| 1633 return var_result.value(); | 1622 return var_result.value(); |
| 1634 } | 1623 } |
| 1635 | 1624 |
| 1636 Node* CodeStubAssembler::AllocateSeqTwoByteString(int length, | 1625 Node* CodeStubAssembler::AllocateSeqTwoByteString(int length, |
| 1637 AllocationFlags flags) { | 1626 AllocationFlags flags) { |
| 1638 Comment("AllocateSeqTwoByteString"); | 1627 Comment("AllocateSeqTwoByteString"); |
| 1639 if (length == 0) { | |
| 1640 return LoadRoot(Heap::kempty_stringRootIndex); | |
| 1641 } | |
| 1642 Node* result = Allocate(SeqTwoByteString::SizeFor(length), flags); | 1628 Node* result = Allocate(SeqTwoByteString::SizeFor(length), flags); |
| 1643 DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex)); | 1629 DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex)); |
| 1644 StoreMapNoWriteBarrier(result, Heap::kStringMapRootIndex); | 1630 StoreMapNoWriteBarrier(result, Heap::kStringMapRootIndex); |
| 1645 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset, | 1631 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset, |
| 1646 SmiConstant(Smi::FromInt(length))); | 1632 SmiConstant(Smi::FromInt(length))); |
| 1647 // Initialize both used and unused parts of hash field slot at once. | 1633 // Initialize both used and unused parts of hash field slot at once. |
| 1648 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldSlot, | 1634 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldSlot, |
| 1649 IntPtrConstant(String::kEmptyHashField), | 1635 IntPtrConstant(String::kEmptyHashField), |
| 1650 MachineType::PointerRepresentation()); | 1636 MachineType::PointerRepresentation()); |
| 1651 return result; | 1637 return result; |
| 1652 } | 1638 } |
| 1653 | 1639 |
| 1654 Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length, | 1640 Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length, |
| 1655 ParameterMode mode, | 1641 ParameterMode mode, |
| 1656 AllocationFlags flags) { | 1642 AllocationFlags flags) { |
| 1657 Comment("AllocateSeqTwoByteString"); | 1643 Comment("AllocateSeqTwoByteString"); |
| 1658 Variable var_result(this, MachineRepresentation::kTagged); | 1644 Variable var_result(this, MachineRepresentation::kTagged); |
| 1659 | 1645 |
| 1660 // Compute the SeqTwoByteString size and check if it fits into new space. | 1646 // Compute the SeqTwoByteString size and check if it fits into new space. |
| 1661 Label if_lengthiszero(this), if_sizeissmall(this), | 1647 Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), |
| 1662 if_notsizeissmall(this, Label::kDeferred), if_join(this); | 1648 if_join(this); |
| 1663 GotoIf(WordEqual(length, IntPtrOrSmiConstant(0, mode)), &if_lengthiszero); | |
| 1664 | |
| 1665 Node* raw_size = GetArrayAllocationSize( | 1649 Node* raw_size = GetArrayAllocationSize( |
| 1666 length, UINT16_ELEMENTS, mode, | 1650 length, UINT16_ELEMENTS, mode, |
| 1667 SeqOneByteString::kHeaderSize + kObjectAlignmentMask); | 1651 SeqOneByteString::kHeaderSize + kObjectAlignmentMask); |
| 1668 Node* size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); | 1652 Node* size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); |
| 1669 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), | 1653 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), |
| 1670 &if_sizeissmall, &if_notsizeissmall); | 1654 &if_sizeissmall, &if_notsizeissmall); |
| 1671 | 1655 |
| 1672 Bind(&if_sizeissmall); | 1656 Bind(&if_sizeissmall); |
| 1673 { | 1657 { |
| 1674 // Just allocate the SeqTwoByteString in new space. | 1658 // Just allocate the SeqTwoByteString in new space. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1689 Bind(&if_notsizeissmall); | 1673 Bind(&if_notsizeissmall); |
| 1690 { | 1674 { |
| 1691 // We might need to allocate in large object space, go to the runtime. | 1675 // We might need to allocate in large object space, go to the runtime. |
| 1692 Node* result = | 1676 Node* result = |
| 1693 CallRuntime(Runtime::kAllocateSeqTwoByteString, context, | 1677 CallRuntime(Runtime::kAllocateSeqTwoByteString, context, |
| 1694 mode == SMI_PARAMETERS ? length : SmiFromWord(length)); | 1678 mode == SMI_PARAMETERS ? length : SmiFromWord(length)); |
| 1695 var_result.Bind(result); | 1679 var_result.Bind(result); |
| 1696 Goto(&if_join); | 1680 Goto(&if_join); |
| 1697 } | 1681 } |
| 1698 | 1682 |
| 1699 Bind(&if_lengthiszero); | |
| 1700 { | |
| 1701 var_result.Bind(LoadRoot(Heap::kempty_stringRootIndex)); | |
| 1702 Goto(&if_join); | |
| 1703 } | |
| 1704 | |
| 1705 Bind(&if_join); | 1683 Bind(&if_join); |
| 1706 return var_result.value(); | 1684 return var_result.value(); |
| 1707 } | 1685 } |
| 1708 | 1686 |
| 1709 Node* CodeStubAssembler::AllocateSlicedString( | 1687 Node* CodeStubAssembler::AllocateSlicedString( |
| 1710 Heap::RootListIndex map_root_index, Node* length, Node* parent, | 1688 Heap::RootListIndex map_root_index, Node* length, Node* parent, |
| 1711 Node* offset) { | 1689 Node* offset) { |
| 1712 CSA_ASSERT(this, TaggedIsSmi(length)); | 1690 CSA_ASSERT(this, TaggedIsSmi(length)); |
| 1713 Node* result = Allocate(SlicedString::kSize); | 1691 Node* result = Allocate(SlicedString::kSize); |
| 1714 DCHECK(Heap::RootIsImmortalImmovable(map_root_index)); | 1692 DCHECK(Heap::RootIsImmortalImmovable(map_root_index)); |
| (...skipping 1282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2997 Node* CodeStubAssembler::IsJSFunction(Node* object) { | 2975 Node* CodeStubAssembler::IsJSFunction(Node* object) { |
| 2998 return HasInstanceType(object, JS_FUNCTION_TYPE); | 2976 return HasInstanceType(object, JS_FUNCTION_TYPE); |
| 2999 } | 2977 } |
| 3000 | 2978 |
| 3001 Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index, | 2979 Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index, |
| 3002 ParameterMode parameter_mode) { | 2980 ParameterMode parameter_mode) { |
| 3003 CSA_ASSERT(this, IsString(string)); | 2981 CSA_ASSERT(this, IsString(string)); |
| 3004 // Translate the {index} into a Word. | 2982 // Translate the {index} into a Word. |
| 3005 index = ParameterToWord(index, parameter_mode); | 2983 index = ParameterToWord(index, parameter_mode); |
| 3006 | 2984 |
| 3007 // We may need to loop in case of cons, thin, or sliced strings. | 2985 // We may need to loop in case of cons or sliced strings. |
| 3008 Variable var_index(this, MachineType::PointerRepresentation()); | 2986 Variable var_index(this, MachineType::PointerRepresentation()); |
| 3009 Variable var_result(this, MachineRepresentation::kWord32); | 2987 Variable var_result(this, MachineRepresentation::kWord32); |
| 3010 Variable var_string(this, MachineRepresentation::kTagged); | 2988 Variable var_string(this, MachineRepresentation::kTagged); |
| 3011 Variable* loop_vars[] = {&var_index, &var_string}; | 2989 Variable* loop_vars[] = {&var_index, &var_string}; |
| 3012 Label done_loop(this, &var_result), loop(this, 2, loop_vars); | 2990 Label done_loop(this, &var_result), loop(this, 2, loop_vars); |
| 3013 var_string.Bind(string); | 2991 var_string.Bind(string); |
| 3014 var_index.Bind(index); | 2992 var_index.Bind(index); |
| 3015 Goto(&loop); | 2993 Goto(&loop); |
| 3016 Bind(&loop); | 2994 Bind(&loop); |
| 3017 { | 2995 { |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3149 // The {string} might be compressed, call the runtime. | 3127 // The {string} might be compressed, call the runtime. |
| 3150 var_result.Bind(SmiToWord32( | 3128 var_result.Bind(SmiToWord32( |
| 3151 CallRuntime(Runtime::kExternalStringGetChar, | 3129 CallRuntime(Runtime::kExternalStringGetChar, |
| 3152 NoContextConstant(), string, SmiTag(index)))); | 3130 NoContextConstant(), string, SmiTag(index)))); |
| 3153 Goto(&done_loop); | 3131 Goto(&done_loop); |
| 3154 } | 3132 } |
| 3155 } | 3133 } |
| 3156 | 3134 |
| 3157 Bind(&if_stringisnotexternal); | 3135 Bind(&if_stringisnotexternal); |
| 3158 { | 3136 { |
| 3159 Label if_stringissliced(this), if_stringisthin(this); | 3137 // The {string} is a SlicedString, continue with its parent. |
| 3160 Branch( | 3138 Node* string_offset = |
| 3161 Word32Equal(Word32And(string_instance_type, | 3139 LoadAndUntagObjectField(string, SlicedString::kOffsetOffset); |
| 3162 Int32Constant(kStringRepresentationMask)), | 3140 Node* string_parent = |
| 3163 Int32Constant(kSlicedStringTag)), | 3141 LoadObjectField(string, SlicedString::kParentOffset); |
| 3164 &if_stringissliced, &if_stringisthin); | 3142 var_index.Bind(IntPtrAdd(index, string_offset)); |
| 3165 Bind(&if_stringissliced); | 3143 var_string.Bind(string_parent); |
| 3166 { | 3144 Goto(&loop); |
| 3167 // The {string} is a SlicedString, continue with its parent. | |
| 3168 Node* string_offset = | |
| 3169 LoadAndUntagObjectField(string, SlicedString::kOffsetOffset); | |
| 3170 Node* string_parent = | |
| 3171 LoadObjectField(string, SlicedString::kParentOffset); | |
| 3172 var_index.Bind(IntPtrAdd(index, string_offset)); | |
| 3173 var_string.Bind(string_parent); | |
| 3174 Goto(&loop); | |
| 3175 } | |
| 3176 Bind(&if_stringisthin); | |
| 3177 { | |
| 3178 // The {string} is a ThinString, continue with its actual value. | |
| 3179 var_string.Bind(LoadObjectField(string, ThinString::kActualOffset)); | |
| 3180 Goto(&loop); | |
| 3181 } | |
| 3182 } | 3145 } |
| 3183 } | 3146 } |
| 3184 } | 3147 } |
| 3185 } | 3148 } |
| 3186 | 3149 |
| 3187 Bind(&done_loop); | 3150 Bind(&done_loop); |
| 3188 return var_result.value(); | 3151 return var_result.value(); |
| 3189 } | 3152 } |
| 3190 | 3153 |
| 3191 Node* CodeStubAssembler::StringFromCharCode(Node* code) { | 3154 Node* CodeStubAssembler::StringFromCharCode(Node* code) { |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3302 } | 3265 } |
| 3303 | 3266 |
| 3304 } // namespace | 3267 } // namespace |
| 3305 | 3268 |
| 3306 Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, | 3269 Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| 3307 Node* to) { | 3270 Node* to) { |
| 3308 Label end(this); | 3271 Label end(this); |
| 3309 Label runtime(this); | 3272 Label runtime(this); |
| 3310 | 3273 |
| 3311 Variable var_instance_type(this, MachineRepresentation::kWord32); // Int32. | 3274 Variable var_instance_type(this, MachineRepresentation::kWord32); // Int32. |
| 3312 Variable var_representation(this, MachineRepresentation::kWord32); // Int32. | |
| 3313 Variable var_result(this, MachineRepresentation::kTagged); // String. | 3275 Variable var_result(this, MachineRepresentation::kTagged); // String. |
| 3314 Variable var_from(this, MachineRepresentation::kTagged); // Smi. | 3276 Variable var_from(this, MachineRepresentation::kTagged); // Smi. |
| 3315 Variable var_string(this, MachineRepresentation::kTagged); // String. | 3277 Variable var_string(this, MachineRepresentation::kTagged); // String. |
| 3316 | 3278 |
| 3317 var_instance_type.Bind(Int32Constant(0)); | 3279 var_instance_type.Bind(Int32Constant(0)); |
| 3318 var_representation.Bind(Int32Constant(0)); | |
| 3319 var_string.Bind(string); | 3280 var_string.Bind(string); |
| 3320 var_from.Bind(from); | 3281 var_from.Bind(from); |
| 3321 | 3282 |
| 3322 // Make sure first argument is a string. | 3283 // Make sure first argument is a string. |
| 3323 | 3284 |
| 3324 // Bailout if receiver is a Smi. | 3285 // Bailout if receiver is a Smi. |
| 3325 GotoIf(TaggedIsSmi(string), &runtime); | 3286 GotoIf(TaggedIsSmi(string), &runtime); |
| 3326 | 3287 |
| 3327 // Load the instance type of the {string}. | 3288 // Load the instance type of the {string}. |
| 3328 Node* const instance_type = LoadInstanceType(string); | 3289 Node* const instance_type = LoadInstanceType(string); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 3349 | 3310 |
| 3350 Label single_char(this); | 3311 Label single_char(this); |
| 3351 GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char); | 3312 GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char); |
| 3352 | 3313 |
| 3353 // TODO(jgruber): Add an additional case for substring of length == 0? | 3314 // TODO(jgruber): Add an additional case for substring of length == 0? |
| 3354 | 3315 |
| 3355 // Deal with different string types: update the index if necessary | 3316 // Deal with different string types: update the index if necessary |
| 3356 // and put the underlying string into var_string. | 3317 // and put the underlying string into var_string. |
| 3357 | 3318 |
| 3358 // If the string is not indirect, it can only be sequential or external. | 3319 // If the string is not indirect, it can only be sequential or external. |
| 3359 STATIC_ASSERT(kIsIndirectStringMask == | 3320 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); |
| 3360 (kSlicedStringTag & kConsStringTag & kThinStringTag)); | |
| 3361 STATIC_ASSERT(kIsIndirectStringMask != 0); | 3321 STATIC_ASSERT(kIsIndirectStringMask != 0); |
| 3362 Label underlying_unpacked(this); | 3322 Label underlying_unpacked(this); |
| 3363 GotoIf(Word32Equal( | 3323 GotoIf(Word32Equal( |
| 3364 Word32And(instance_type, Int32Constant(kIsIndirectStringMask)), | 3324 Word32And(instance_type, Int32Constant(kIsIndirectStringMask)), |
| 3365 Int32Constant(0)), | 3325 Int32Constant(0)), |
| 3366 &underlying_unpacked); | 3326 &underlying_unpacked); |
| 3367 | 3327 |
| 3368 // The subject string is a sliced, cons, or thin string. | 3328 // The subject string is either a sliced or cons string. |
| 3369 | 3329 |
| 3370 Label sliced_string(this), thin_or_sliced(this); | 3330 Label sliced_string(this); |
| 3371 var_representation.Bind( | 3331 GotoIf(Word32NotEqual( |
| 3372 Word32And(instance_type, Int32Constant(kStringRepresentationMask))); | 3332 Word32And(instance_type, Int32Constant(kSlicedNotConsMask)), |
| 3373 GotoIf( | 3333 Int32Constant(0)), |
| 3374 Word32NotEqual(var_representation.value(), Int32Constant(kConsStringTag)), | 3334 &sliced_string); |
| 3375 &thin_or_sliced); | |
| 3376 | 3335 |
| 3377 // Cons string. Check whether it is flat, then fetch first part. | 3336 // Cons string. Check whether it is flat, then fetch first part. |
| 3378 // Flat cons strings have an empty second part. | 3337 // Flat cons strings have an empty second part. |
| 3379 { | 3338 { |
| 3380 GotoIf(WordNotEqual(LoadObjectField(string, ConsString::kSecondOffset), | 3339 GotoIf(WordNotEqual(LoadObjectField(string, ConsString::kSecondOffset), |
| 3381 EmptyStringConstant()), | 3340 EmptyStringConstant()), |
| 3382 &runtime); | 3341 &runtime); |
| 3383 | 3342 |
| 3384 Node* first_string_part = LoadObjectField(string, ConsString::kFirstOffset); | 3343 Node* first_string_part = LoadObjectField(string, ConsString::kFirstOffset); |
| 3385 var_string.Bind(first_string_part); | 3344 var_string.Bind(first_string_part); |
| 3386 var_instance_type.Bind(LoadInstanceType(first_string_part)); | 3345 var_instance_type.Bind(LoadInstanceType(first_string_part)); |
| 3387 var_representation.Bind(Word32And( | |
| 3388 var_instance_type.value(), Int32Constant(kStringRepresentationMask))); | |
| 3389 | 3346 |
| 3390 // The loaded first part might be a thin string. | |
| 3391 Branch(Word32Equal(Word32And(var_instance_type.value(), | |
| 3392 Int32Constant(kIsIndirectStringMask)), | |
| 3393 Int32Constant(0)), | |
| 3394 &underlying_unpacked, &thin_or_sliced); | |
| 3395 } | |
| 3396 | |
| 3397 Bind(&thin_or_sliced); | |
| 3398 { | |
| 3399 GotoIf(Word32Equal(var_representation.value(), | |
| 3400 Int32Constant(kSlicedStringTag)), | |
| 3401 &sliced_string); | |
| 3402 Node* actual_string = | |
| 3403 LoadObjectField(var_string.value(), ThinString::kActualOffset); | |
| 3404 var_string.Bind(actual_string); | |
| 3405 var_instance_type.Bind(LoadInstanceType(actual_string)); | |
| 3406 Goto(&underlying_unpacked); | 3347 Goto(&underlying_unpacked); |
| 3407 } | 3348 } |
| 3408 | 3349 |
| 3409 Bind(&sliced_string); | 3350 Bind(&sliced_string); |
| 3410 { | 3351 { |
| 3411 // Fetch parent and correct start index by offset. | 3352 // Fetch parent and correct start index by offset. |
| 3412 Node* sliced_offset = | 3353 Node* sliced_offset = LoadObjectField(string, SlicedString::kOffsetOffset); |
| 3413 LoadObjectField(var_string.value(), SlicedString::kOffsetOffset); | |
| 3414 var_from.Bind(SmiAdd(from, sliced_offset)); | 3354 var_from.Bind(SmiAdd(from, sliced_offset)); |
| 3415 | 3355 |
| 3416 Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); | 3356 Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); |
| 3417 var_string.Bind(slice_parent); | 3357 var_string.Bind(slice_parent); |
| 3418 | 3358 |
| 3419 Node* slice_parent_instance_type = LoadInstanceType(slice_parent); | 3359 Node* slice_parent_instance_type = LoadInstanceType(slice_parent); |
| 3420 var_instance_type.Bind(slice_parent_instance_type); | 3360 var_instance_type.Bind(slice_parent_instance_type); |
| 3421 | 3361 |
| 3422 Goto(&underlying_unpacked); | 3362 Goto(&underlying_unpacked); |
| 3423 } | 3363 } |
| (...skipping 752 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4176 Bind(&runtime); | 4116 Bind(&runtime); |
| 4177 { | 4117 { |
| 4178 result.Bind(CallRuntime(Runtime::kToString, context, input)); | 4118 result.Bind(CallRuntime(Runtime::kToString, context, input)); |
| 4179 Goto(&done); | 4119 Goto(&done); |
| 4180 } | 4120 } |
| 4181 | 4121 |
| 4182 Bind(&done); | 4122 Bind(&done); |
| 4183 return result.value(); | 4123 return result.value(); |
| 4184 } | 4124 } |
| 4185 | 4125 |
| 4126 Node* CodeStubAssembler::FlattenString(Node* string) { |
| 4127 CSA_ASSERT(this, IsString(string)); |
| 4128 Variable var_result(this, MachineRepresentation::kTagged); |
| 4129 var_result.Bind(string); |
| 4130 |
| 4131 Node* instance_type = LoadInstanceType(string); |
| 4132 |
| 4133 // Check if the {string} is not a ConsString (i.e. already flat). |
| 4134 Label is_cons(this, Label::kDeferred), is_flat_in_cons(this), end(this); |
| 4135 { |
| 4136 GotoUnless(Word32Equal(Word32And(instance_type, |
| 4137 Int32Constant(kStringRepresentationMask)), |
| 4138 Int32Constant(kConsStringTag)), |
| 4139 &end); |
| 4140 |
| 4141 // Check whether the right hand side is the empty string (i.e. if |
| 4142 // this is really a flat string in a cons string). |
| 4143 Node* rhs = LoadObjectField(string, ConsString::kSecondOffset); |
| 4144 Branch(WordEqual(rhs, EmptyStringConstant()), &is_flat_in_cons, &is_cons); |
| 4145 } |
| 4146 |
| 4147 // Bail out to the runtime. |
| 4148 Bind(&is_cons); |
| 4149 { |
| 4150 var_result.Bind( |
| 4151 CallRuntime(Runtime::kFlattenString, NoContextConstant(), string)); |
| 4152 Goto(&end); |
| 4153 } |
| 4154 |
| 4155 Bind(&is_flat_in_cons); |
| 4156 { |
| 4157 var_result.Bind(LoadObjectField(string, ConsString::kFirstOffset)); |
| 4158 Goto(&end); |
| 4159 } |
| 4160 |
| 4161 Bind(&end); |
| 4162 return var_result.value(); |
| 4163 } |
| 4164 |
| 4186 Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) { | 4165 Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) { |
| 4187 Label if_isreceiver(this, Label::kDeferred), if_isnotreceiver(this); | 4166 Label if_isreceiver(this, Label::kDeferred), if_isnotreceiver(this); |
| 4188 Variable result(this, MachineRepresentation::kTagged); | 4167 Variable result(this, MachineRepresentation::kTagged); |
| 4189 Label done(this, &result); | 4168 Label done(this, &result); |
| 4190 | 4169 |
| 4191 BranchIfJSReceiver(input, &if_isreceiver, &if_isnotreceiver); | 4170 BranchIfJSReceiver(input, &if_isreceiver, &if_isnotreceiver); |
| 4192 | 4171 |
| 4193 Bind(&if_isreceiver); | 4172 Bind(&if_isreceiver); |
| 4194 { | 4173 { |
| 4195 // Convert {input} to a primitive first passing Number hint. | 4174 // Convert {input} to a primitive first passing Number hint. |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4317 variable.Bind( | 4296 variable.Bind( |
| 4318 IntPtrOrSmiAdd(variable.value(), IntPtrOrSmiConstant(value, mode), mode)); | 4297 IntPtrOrSmiAdd(variable.value(), IntPtrOrSmiConstant(value, mode), mode)); |
| 4319 } | 4298 } |
| 4320 | 4299 |
| 4321 void CodeStubAssembler::Use(Label* label) { | 4300 void CodeStubAssembler::Use(Label* label) { |
| 4322 GotoIf(Word32Equal(Int32Constant(0), Int32Constant(1)), label); | 4301 GotoIf(Word32Equal(Int32Constant(0), Int32Constant(1)), label); |
| 4323 } | 4302 } |
| 4324 | 4303 |
| 4325 void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, | 4304 void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, |
| 4326 Variable* var_index, Label* if_keyisunique, | 4305 Variable* var_index, Label* if_keyisunique, |
| 4327 Variable* var_unique, Label* if_bailout) { | 4306 Label* if_bailout) { |
| 4328 DCHECK_EQ(MachineType::PointerRepresentation(), var_index->rep()); | 4307 DCHECK_EQ(MachineType::PointerRepresentation(), var_index->rep()); |
| 4329 DCHECK_EQ(MachineRepresentation::kTagged, var_unique->rep()); | |
| 4330 Comment("TryToName"); | 4308 Comment("TryToName"); |
| 4331 | 4309 |
| 4332 Label if_hascachedindex(this), if_keyisnotindex(this), if_thinstring(this); | 4310 Label if_hascachedindex(this), if_keyisnotindex(this); |
| 4333 // Handle Smi and HeapNumber keys. | 4311 // Handle Smi and HeapNumber keys. |
| 4334 var_index->Bind(TryToIntptr(key, &if_keyisnotindex)); | 4312 var_index->Bind(TryToIntptr(key, &if_keyisnotindex)); |
| 4335 Goto(if_keyisindex); | 4313 Goto(if_keyisindex); |
| 4336 | 4314 |
| 4337 Bind(&if_keyisnotindex); | 4315 Bind(&if_keyisnotindex); |
| 4338 Node* key_map = LoadMap(key); | 4316 Node* key_map = LoadMap(key); |
| 4339 var_unique->Bind(key); | |
| 4340 // Symbols are unique. | 4317 // Symbols are unique. |
| 4341 GotoIf(IsSymbolMap(key_map), if_keyisunique); | 4318 GotoIf(IsSymbolMap(key_map), if_keyisunique); |
| 4342 Node* key_instance_type = LoadMapInstanceType(key_map); | 4319 Node* key_instance_type = LoadMapInstanceType(key_map); |
| 4343 // Miss if |key| is not a String. | 4320 // Miss if |key| is not a String. |
| 4344 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); | 4321 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); |
| 4345 GotoUnless(IsStringInstanceType(key_instance_type), if_bailout); | 4322 GotoUnless(IsStringInstanceType(key_instance_type), if_bailout); |
| 4346 // |key| is a String. Check if it has a cached array index. | 4323 // |key| is a String. Check if it has a cached array index. |
| 4347 Node* hash = LoadNameHashField(key); | 4324 Node* hash = LoadNameHashField(key); |
| 4348 Node* contains_index = | 4325 Node* contains_index = |
| 4349 Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); | 4326 Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); |
| 4350 GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_hascachedindex); | 4327 GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_hascachedindex); |
| 4351 // No cached array index. If the string knows that it contains an index, | 4328 // No cached array index. If the string knows that it contains an index, |
| 4352 // then it must be an uncacheable index. Handle this case in the runtime. | 4329 // then it must be an uncacheable index. Handle this case in the runtime. |
| 4353 Node* not_an_index = | 4330 Node* not_an_index = |
| 4354 Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); | 4331 Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); |
| 4355 GotoIf(Word32Equal(not_an_index, Int32Constant(0)), if_bailout); | 4332 GotoIf(Word32Equal(not_an_index, Int32Constant(0)), if_bailout); |
| 4356 // Check if we have a ThinString. | |
| 4357 GotoIf(Word32Equal(key_instance_type, Int32Constant(THIN_STRING_TYPE)), | |
| 4358 &if_thinstring); | |
| 4359 GotoIf( | |
| 4360 Word32Equal(key_instance_type, Int32Constant(THIN_ONE_BYTE_STRING_TYPE)), | |
| 4361 &if_thinstring); | |
| 4362 // Finally, check if |key| is internalized. | 4333 // Finally, check if |key| is internalized. |
| 4363 STATIC_ASSERT(kNotInternalizedTag != 0); | 4334 STATIC_ASSERT(kNotInternalizedTag != 0); |
| 4364 Node* not_internalized = | 4335 Node* not_internalized = |
| 4365 Word32And(key_instance_type, Int32Constant(kIsNotInternalizedMask)); | 4336 Word32And(key_instance_type, Int32Constant(kIsNotInternalizedMask)); |
| 4366 GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)), if_bailout); | 4337 GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)), if_bailout); |
| 4367 Goto(if_keyisunique); | 4338 Goto(if_keyisunique); |
| 4368 | 4339 |
| 4369 Bind(&if_thinstring); | |
| 4370 var_unique->Bind(LoadObjectField(key, ThinString::kActualOffset)); | |
| 4371 Goto(if_keyisunique); | |
| 4372 | |
| 4373 Bind(&if_hascachedindex); | 4340 Bind(&if_hascachedindex); |
| 4374 var_index->Bind(DecodeWordFromWord32<Name::ArrayIndexValueBits>(hash)); | 4341 var_index->Bind(DecodeWordFromWord32<Name::ArrayIndexValueBits>(hash)); |
| 4375 Goto(if_keyisindex); | 4342 Goto(if_keyisindex); |
| 4376 } | 4343 } |
| 4377 | 4344 |
| 4378 template <typename Dictionary> | 4345 template <typename Dictionary> |
| 4379 Node* CodeStubAssembler::EntryToIndex(Node* entry, int field_index) { | 4346 Node* CodeStubAssembler::EntryToIndex(Node* entry, int field_index) { |
| 4380 Node* entry_index = IntPtrMul(entry, IntPtrConstant(Dictionary::kEntrySize)); | 4347 Node* entry_index = IntPtrMul(entry, IntPtrConstant(Dictionary::kEntrySize)); |
| 4381 return IntPtrAdd(entry_index, IntPtrConstant(Dictionary::kElementsStartIndex + | 4348 return IntPtrAdd(entry_index, IntPtrConstant(Dictionary::kElementsStartIndex + |
| 4382 field_index)); | 4349 field_index)); |
| (...skipping 829 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5212 Label if_objectisreceiver(this); | 5179 Label if_objectisreceiver(this); |
| 5213 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | 5180 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
| 5214 STATIC_ASSERT(FIRST_JS_RECEIVER_TYPE == JS_PROXY_TYPE); | 5181 STATIC_ASSERT(FIRST_JS_RECEIVER_TYPE == JS_PROXY_TYPE); |
| 5215 Branch( | 5182 Branch( |
| 5216 Int32GreaterThan(instance_type, Int32Constant(FIRST_JS_RECEIVER_TYPE)), | 5183 Int32GreaterThan(instance_type, Int32Constant(FIRST_JS_RECEIVER_TYPE)), |
| 5217 &if_objectisreceiver, if_bailout); | 5184 &if_objectisreceiver, if_bailout); |
| 5218 Bind(&if_objectisreceiver); | 5185 Bind(&if_objectisreceiver); |
| 5219 } | 5186 } |
| 5220 | 5187 |
| 5221 Variable var_index(this, MachineType::PointerRepresentation()); | 5188 Variable var_index(this, MachineType::PointerRepresentation()); |
| 5222 Variable var_unique(this, MachineRepresentation::kTagged); | |
| 5223 | 5189 |
| 5224 Label if_keyisindex(this), if_iskeyunique(this); | 5190 Label if_keyisindex(this), if_iskeyunique(this); |
| 5225 TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, &var_unique, | 5191 TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, if_bailout); |
| 5226 if_bailout); | |
| 5227 | 5192 |
| 5228 Bind(&if_iskeyunique); | 5193 Bind(&if_iskeyunique); |
| 5229 { | 5194 { |
| 5230 Variable var_holder(this, MachineRepresentation::kTagged); | 5195 Variable var_holder(this, MachineRepresentation::kTagged); |
| 5231 Variable var_holder_map(this, MachineRepresentation::kTagged); | 5196 Variable var_holder_map(this, MachineRepresentation::kTagged); |
| 5232 Variable var_holder_instance_type(this, MachineRepresentation::kWord32); | 5197 Variable var_holder_instance_type(this, MachineRepresentation::kWord32); |
| 5233 | 5198 |
| 5234 Variable* merged_variables[] = {&var_holder, &var_holder_map, | 5199 Variable* merged_variables[] = {&var_holder, &var_holder_map, |
| 5235 &var_holder_instance_type}; | 5200 &var_holder_instance_type}; |
| 5236 Label loop(this, arraysize(merged_variables), merged_variables); | 5201 Label loop(this, arraysize(merged_variables), merged_variables); |
| 5237 var_holder.Bind(receiver); | 5202 var_holder.Bind(receiver); |
| 5238 var_holder_map.Bind(map); | 5203 var_holder_map.Bind(map); |
| 5239 var_holder_instance_type.Bind(instance_type); | 5204 var_holder_instance_type.Bind(instance_type); |
| 5240 Goto(&loop); | 5205 Goto(&loop); |
| 5241 Bind(&loop); | 5206 Bind(&loop); |
| 5242 { | 5207 { |
| 5243 Node* holder_map = var_holder_map.value(); | 5208 Node* holder_map = var_holder_map.value(); |
| 5244 Node* holder_instance_type = var_holder_instance_type.value(); | 5209 Node* holder_instance_type = var_holder_instance_type.value(); |
| 5245 | 5210 |
| 5246 Label next_proto(this); | 5211 Label next_proto(this); |
| 5247 lookup_property_in_holder(receiver, var_holder.value(), holder_map, | 5212 lookup_property_in_holder(receiver, var_holder.value(), holder_map, |
| 5248 holder_instance_type, var_unique.value(), | 5213 holder_instance_type, key, &next_proto, |
| 5249 &next_proto, if_bailout); | 5214 if_bailout); |
| 5250 Bind(&next_proto); | 5215 Bind(&next_proto); |
| 5251 | 5216 |
| 5252 // Bailout if it can be an integer indexed exotic case. | 5217 // Bailout if it can be an integer indexed exotic case. |
| 5253 GotoIf( | 5218 GotoIf( |
| 5254 Word32Equal(holder_instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)), | 5219 Word32Equal(holder_instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)), |
| 5255 if_bailout); | 5220 if_bailout); |
| 5256 | 5221 |
| 5257 Node* proto = LoadMapPrototype(holder_map); | 5222 Node* proto = LoadMapPrototype(holder_map); |
| 5258 | 5223 |
| 5259 Label if_not_null(this); | 5224 Label if_not_null(this); |
| (...skipping 3012 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8272 StoreObjectFieldNoWriteBarrier(result, | 8237 StoreObjectFieldNoWriteBarrier(result, |
| 8273 PromiseReactionJobInfo::kDebugNameOffset, | 8238 PromiseReactionJobInfo::kDebugNameOffset, |
| 8274 SmiConstant(kDebugNotActive)); | 8239 SmiConstant(kDebugNotActive)); |
| 8275 StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kContextOffset, | 8240 StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kContextOffset, |
| 8276 context); | 8241 context); |
| 8277 return result; | 8242 return result; |
| 8278 } | 8243 } |
| 8279 | 8244 |
| 8280 } // namespace internal | 8245 } // namespace internal |
| 8281 } // namespace v8 | 8246 } // namespace v8 |
| OLD | NEW |