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