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 |