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 1286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3008 Node* CodeStubAssembler::IsJSFunction(Node* object) { | 2986 Node* CodeStubAssembler::IsJSFunction(Node* object) { |
3009 return HasInstanceType(object, JS_FUNCTION_TYPE); | 2987 return HasInstanceType(object, JS_FUNCTION_TYPE); |
3010 } | 2988 } |
3011 | 2989 |
3012 Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index, | 2990 Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index, |
3013 ParameterMode parameter_mode) { | 2991 ParameterMode parameter_mode) { |
3014 CSA_ASSERT(this, IsString(string)); | 2992 CSA_ASSERT(this, IsString(string)); |
3015 // Translate the {index} into a Word. | 2993 // Translate the {index} into a Word. |
3016 index = ParameterToWord(index, parameter_mode); | 2994 index = ParameterToWord(index, parameter_mode); |
3017 | 2995 |
3018 // We may need to loop in case of cons, thin, or sliced strings. | 2996 // We may need to loop in case of cons or sliced strings. |
3019 Variable var_index(this, MachineType::PointerRepresentation()); | 2997 Variable var_index(this, MachineType::PointerRepresentation()); |
3020 Variable var_result(this, MachineRepresentation::kWord32); | 2998 Variable var_result(this, MachineRepresentation::kWord32); |
3021 Variable var_string(this, MachineRepresentation::kTagged); | 2999 Variable var_string(this, MachineRepresentation::kTagged); |
3022 Variable* loop_vars[] = {&var_index, &var_string}; | 3000 Variable* loop_vars[] = {&var_index, &var_string}; |
3023 Label done_loop(this, &var_result), loop(this, 2, loop_vars); | 3001 Label done_loop(this, &var_result), loop(this, 2, loop_vars); |
3024 var_string.Bind(string); | 3002 var_string.Bind(string); |
3025 var_index.Bind(index); | 3003 var_index.Bind(index); |
3026 Goto(&loop); | 3004 Goto(&loop); |
3027 Bind(&loop); | 3005 Bind(&loop); |
3028 { | 3006 { |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3160 // The {string} might be compressed, call the runtime. | 3138 // The {string} might be compressed, call the runtime. |
3161 var_result.Bind(SmiToWord32( | 3139 var_result.Bind(SmiToWord32( |
3162 CallRuntime(Runtime::kExternalStringGetChar, | 3140 CallRuntime(Runtime::kExternalStringGetChar, |
3163 NoContextConstant(), string, SmiTag(index)))); | 3141 NoContextConstant(), string, SmiTag(index)))); |
3164 Goto(&done_loop); | 3142 Goto(&done_loop); |
3165 } | 3143 } |
3166 } | 3144 } |
3167 | 3145 |
3168 Bind(&if_stringisnotexternal); | 3146 Bind(&if_stringisnotexternal); |
3169 { | 3147 { |
3170 Label if_stringissliced(this), if_stringisthin(this); | 3148 // The {string} is a SlicedString, continue with its parent. |
3171 Branch( | 3149 Node* string_offset = |
3172 Word32Equal(Word32And(string_instance_type, | 3150 LoadAndUntagObjectField(string, SlicedString::kOffsetOffset); |
3173 Int32Constant(kStringRepresentationMask)), | 3151 Node* string_parent = |
3174 Int32Constant(kSlicedStringTag)), | 3152 LoadObjectField(string, SlicedString::kParentOffset); |
3175 &if_stringissliced, &if_stringisthin); | 3153 var_index.Bind(IntPtrAdd(index, string_offset)); |
3176 Bind(&if_stringissliced); | 3154 var_string.Bind(string_parent); |
3177 { | 3155 Goto(&loop); |
3178 // The {string} is a SlicedString, continue with its parent. | |
3179 Node* string_offset = | |
3180 LoadAndUntagObjectField(string, SlicedString::kOffsetOffset); | |
3181 Node* string_parent = | |
3182 LoadObjectField(string, SlicedString::kParentOffset); | |
3183 var_index.Bind(IntPtrAdd(index, string_offset)); | |
3184 var_string.Bind(string_parent); | |
3185 Goto(&loop); | |
3186 } | |
3187 Bind(&if_stringisthin); | |
3188 { | |
3189 // The {string} is a ThinString, continue with its actual value. | |
3190 var_string.Bind(LoadObjectField(string, ThinString::kActualOffset)); | |
3191 Goto(&loop); | |
3192 } | |
3193 } | 3156 } |
3194 } | 3157 } |
3195 } | 3158 } |
3196 } | 3159 } |
3197 | 3160 |
3198 Bind(&done_loop); | 3161 Bind(&done_loop); |
3199 return var_result.value(); | 3162 return var_result.value(); |
3200 } | 3163 } |
3201 | 3164 |
3202 Node* CodeStubAssembler::StringFromCharCode(Node* code) { | 3165 Node* CodeStubAssembler::StringFromCharCode(Node* code) { |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3313 } | 3276 } |
3314 | 3277 |
3315 } // namespace | 3278 } // namespace |
3316 | 3279 |
3317 Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, | 3280 Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
3318 Node* to) { | 3281 Node* to) { |
3319 Label end(this); | 3282 Label end(this); |
3320 Label runtime(this); | 3283 Label runtime(this); |
3321 | 3284 |
3322 Variable var_instance_type(this, MachineRepresentation::kWord32); // Int32. | 3285 Variable var_instance_type(this, MachineRepresentation::kWord32); // Int32. |
3323 Variable var_representation(this, MachineRepresentation::kWord32); // Int32. | |
3324 Variable var_result(this, MachineRepresentation::kTagged); // String. | 3286 Variable var_result(this, MachineRepresentation::kTagged); // String. |
3325 Variable var_from(this, MachineRepresentation::kTagged); // Smi. | 3287 Variable var_from(this, MachineRepresentation::kTagged); // Smi. |
3326 Variable var_string(this, MachineRepresentation::kTagged); // String. | 3288 Variable var_string(this, MachineRepresentation::kTagged); // String. |
3327 | 3289 |
3328 var_instance_type.Bind(Int32Constant(0)); | 3290 var_instance_type.Bind(Int32Constant(0)); |
3329 var_representation.Bind(Int32Constant(0)); | |
3330 var_string.Bind(string); | 3291 var_string.Bind(string); |
3331 var_from.Bind(from); | 3292 var_from.Bind(from); |
3332 | 3293 |
3333 // Make sure first argument is a string. | 3294 // Make sure first argument is a string. |
3334 | 3295 |
3335 // Bailout if receiver is a Smi. | 3296 // Bailout if receiver is a Smi. |
3336 GotoIf(TaggedIsSmi(string), &runtime); | 3297 GotoIf(TaggedIsSmi(string), &runtime); |
3337 | 3298 |
3338 // Load the instance type of the {string}. | 3299 // Load the instance type of the {string}. |
3339 Node* const instance_type = LoadInstanceType(string); | 3300 Node* const instance_type = LoadInstanceType(string); |
(...skipping 20 matching lines...) Expand all Loading... |
3360 | 3321 |
3361 Label single_char(this); | 3322 Label single_char(this); |
3362 GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char); | 3323 GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char); |
3363 | 3324 |
3364 // TODO(jgruber): Add an additional case for substring of length == 0? | 3325 // TODO(jgruber): Add an additional case for substring of length == 0? |
3365 | 3326 |
3366 // Deal with different string types: update the index if necessary | 3327 // Deal with different string types: update the index if necessary |
3367 // and put the underlying string into var_string. | 3328 // and put the underlying string into var_string. |
3368 | 3329 |
3369 // If the string is not indirect, it can only be sequential or external. | 3330 // If the string is not indirect, it can only be sequential or external. |
3370 STATIC_ASSERT(kIsIndirectStringMask == | 3331 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); |
3371 (kSlicedStringTag & kConsStringTag & kThinStringTag)); | |
3372 STATIC_ASSERT(kIsIndirectStringMask != 0); | 3332 STATIC_ASSERT(kIsIndirectStringMask != 0); |
3373 Label underlying_unpacked(this); | 3333 Label underlying_unpacked(this); |
3374 GotoIf(Word32Equal( | 3334 GotoIf(Word32Equal( |
3375 Word32And(instance_type, Int32Constant(kIsIndirectStringMask)), | 3335 Word32And(instance_type, Int32Constant(kIsIndirectStringMask)), |
3376 Int32Constant(0)), | 3336 Int32Constant(0)), |
3377 &underlying_unpacked); | 3337 &underlying_unpacked); |
3378 | 3338 |
3379 // The subject string is a sliced, cons, or thin string. | 3339 // The subject string is either a sliced or cons string. |
3380 | 3340 |
3381 Label sliced_string(this), thin_or_sliced(this); | 3341 Label sliced_string(this); |
3382 var_representation.Bind( | 3342 GotoIf(Word32NotEqual( |
3383 Word32And(instance_type, Int32Constant(kStringRepresentationMask))); | 3343 Word32And(instance_type, Int32Constant(kSlicedNotConsMask)), |
3384 GotoIf( | 3344 Int32Constant(0)), |
3385 Word32NotEqual(var_representation.value(), Int32Constant(kConsStringTag)), | 3345 &sliced_string); |
3386 &thin_or_sliced); | |
3387 | 3346 |
3388 // Cons string. Check whether it is flat, then fetch first part. | 3347 // Cons string. Check whether it is flat, then fetch first part. |
3389 // Flat cons strings have an empty second part. | 3348 // Flat cons strings have an empty second part. |
3390 { | 3349 { |
3391 GotoIf(WordNotEqual(LoadObjectField(string, ConsString::kSecondOffset), | 3350 GotoIf(WordNotEqual(LoadObjectField(string, ConsString::kSecondOffset), |
3392 EmptyStringConstant()), | 3351 EmptyStringConstant()), |
3393 &runtime); | 3352 &runtime); |
3394 | 3353 |
3395 Node* first_string_part = LoadObjectField(string, ConsString::kFirstOffset); | 3354 Node* first_string_part = LoadObjectField(string, ConsString::kFirstOffset); |
3396 var_string.Bind(first_string_part); | 3355 var_string.Bind(first_string_part); |
3397 var_instance_type.Bind(LoadInstanceType(first_string_part)); | 3356 var_instance_type.Bind(LoadInstanceType(first_string_part)); |
3398 var_representation.Bind(Word32And( | |
3399 var_instance_type.value(), Int32Constant(kStringRepresentationMask))); | |
3400 | 3357 |
3401 // The loaded first part might be a thin string. | |
3402 Branch(Word32Equal(Word32And(var_instance_type.value(), | |
3403 Int32Constant(kIsIndirectStringMask)), | |
3404 Int32Constant(0)), | |
3405 &underlying_unpacked, &thin_or_sliced); | |
3406 } | |
3407 | |
3408 Bind(&thin_or_sliced); | |
3409 { | |
3410 GotoIf(Word32Equal(var_representation.value(), | |
3411 Int32Constant(kSlicedStringTag)), | |
3412 &sliced_string); | |
3413 Node* actual_string = | |
3414 LoadObjectField(var_string.value(), ThinString::kActualOffset); | |
3415 var_string.Bind(actual_string); | |
3416 var_instance_type.Bind(LoadInstanceType(actual_string)); | |
3417 Goto(&underlying_unpacked); | 3358 Goto(&underlying_unpacked); |
3418 } | 3359 } |
3419 | 3360 |
3420 Bind(&sliced_string); | 3361 Bind(&sliced_string); |
3421 { | 3362 { |
3422 // Fetch parent and correct start index by offset. | 3363 // Fetch parent and correct start index by offset. |
3423 Node* sliced_offset = | 3364 Node* sliced_offset = LoadObjectField(string, SlicedString::kOffsetOffset); |
3424 LoadObjectField(var_string.value(), SlicedString::kOffsetOffset); | |
3425 var_from.Bind(SmiAdd(from, sliced_offset)); | 3365 var_from.Bind(SmiAdd(from, sliced_offset)); |
3426 | 3366 |
3427 Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); | 3367 Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); |
3428 var_string.Bind(slice_parent); | 3368 var_string.Bind(slice_parent); |
3429 | 3369 |
3430 Node* slice_parent_instance_type = LoadInstanceType(slice_parent); | 3370 Node* slice_parent_instance_type = LoadInstanceType(slice_parent); |
3431 var_instance_type.Bind(slice_parent_instance_type); | 3371 var_instance_type.Bind(slice_parent_instance_type); |
3432 | 3372 |
3433 Goto(&underlying_unpacked); | 3373 Goto(&underlying_unpacked); |
3434 } | 3374 } |
(...skipping 752 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4187 Bind(&runtime); | 4127 Bind(&runtime); |
4188 { | 4128 { |
4189 result.Bind(CallRuntime(Runtime::kToString, context, input)); | 4129 result.Bind(CallRuntime(Runtime::kToString, context, input)); |
4190 Goto(&done); | 4130 Goto(&done); |
4191 } | 4131 } |
4192 | 4132 |
4193 Bind(&done); | 4133 Bind(&done); |
4194 return result.value(); | 4134 return result.value(); |
4195 } | 4135 } |
4196 | 4136 |
| 4137 Node* CodeStubAssembler::FlattenString(Node* string) { |
| 4138 CSA_ASSERT(this, IsString(string)); |
| 4139 Variable var_result(this, MachineRepresentation::kTagged); |
| 4140 var_result.Bind(string); |
| 4141 |
| 4142 Node* instance_type = LoadInstanceType(string); |
| 4143 |
| 4144 // Check if the {string} is not a ConsString (i.e. already flat). |
| 4145 Label is_cons(this, Label::kDeferred), is_flat_in_cons(this), end(this); |
| 4146 { |
| 4147 GotoUnless(Word32Equal(Word32And(instance_type, |
| 4148 Int32Constant(kStringRepresentationMask)), |
| 4149 Int32Constant(kConsStringTag)), |
| 4150 &end); |
| 4151 |
| 4152 // Check whether the right hand side is the empty string (i.e. if |
| 4153 // this is really a flat string in a cons string). |
| 4154 Node* rhs = LoadObjectField(string, ConsString::kSecondOffset); |
| 4155 Branch(WordEqual(rhs, EmptyStringConstant()), &is_flat_in_cons, &is_cons); |
| 4156 } |
| 4157 |
| 4158 // Bail out to the runtime. |
| 4159 Bind(&is_cons); |
| 4160 { |
| 4161 var_result.Bind( |
| 4162 CallRuntime(Runtime::kFlattenString, NoContextConstant(), string)); |
| 4163 Goto(&end); |
| 4164 } |
| 4165 |
| 4166 Bind(&is_flat_in_cons); |
| 4167 { |
| 4168 var_result.Bind(LoadObjectField(string, ConsString::kFirstOffset)); |
| 4169 Goto(&end); |
| 4170 } |
| 4171 |
| 4172 Bind(&end); |
| 4173 return var_result.value(); |
| 4174 } |
| 4175 |
4197 Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) { | 4176 Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) { |
4198 Label if_isreceiver(this, Label::kDeferred), if_isnotreceiver(this); | 4177 Label if_isreceiver(this, Label::kDeferred), if_isnotreceiver(this); |
4199 Variable result(this, MachineRepresentation::kTagged); | 4178 Variable result(this, MachineRepresentation::kTagged); |
4200 Label done(this, &result); | 4179 Label done(this, &result); |
4201 | 4180 |
4202 BranchIfJSReceiver(input, &if_isreceiver, &if_isnotreceiver); | 4181 BranchIfJSReceiver(input, &if_isreceiver, &if_isnotreceiver); |
4203 | 4182 |
4204 Bind(&if_isreceiver); | 4183 Bind(&if_isreceiver); |
4205 { | 4184 { |
4206 // Convert {input} to a primitive first passing Number hint. | 4185 // Convert {input} to a primitive first passing Number hint. |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4328 variable.Bind( | 4307 variable.Bind( |
4329 IntPtrOrSmiAdd(variable.value(), IntPtrOrSmiConstant(value, mode), mode)); | 4308 IntPtrOrSmiAdd(variable.value(), IntPtrOrSmiConstant(value, mode), mode)); |
4330 } | 4309 } |
4331 | 4310 |
4332 void CodeStubAssembler::Use(Label* label) { | 4311 void CodeStubAssembler::Use(Label* label) { |
4333 GotoIf(Word32Equal(Int32Constant(0), Int32Constant(1)), label); | 4312 GotoIf(Word32Equal(Int32Constant(0), Int32Constant(1)), label); |
4334 } | 4313 } |
4335 | 4314 |
4336 void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, | 4315 void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, |
4337 Variable* var_index, Label* if_keyisunique, | 4316 Variable* var_index, Label* if_keyisunique, |
4338 Variable* var_unique, Label* if_bailout) { | 4317 Label* if_bailout) { |
4339 DCHECK_EQ(MachineType::PointerRepresentation(), var_index->rep()); | 4318 DCHECK_EQ(MachineType::PointerRepresentation(), var_index->rep()); |
4340 DCHECK_EQ(MachineRepresentation::kTagged, var_unique->rep()); | |
4341 Comment("TryToName"); | 4319 Comment("TryToName"); |
4342 | 4320 |
4343 Label if_hascachedindex(this), if_keyisnotindex(this), if_thinstring(this); | 4321 Label if_hascachedindex(this), if_keyisnotindex(this); |
4344 // Handle Smi and HeapNumber keys. | 4322 // Handle Smi and HeapNumber keys. |
4345 var_index->Bind(TryToIntptr(key, &if_keyisnotindex)); | 4323 var_index->Bind(TryToIntptr(key, &if_keyisnotindex)); |
4346 Goto(if_keyisindex); | 4324 Goto(if_keyisindex); |
4347 | 4325 |
4348 Bind(&if_keyisnotindex); | 4326 Bind(&if_keyisnotindex); |
4349 Node* key_map = LoadMap(key); | 4327 Node* key_map = LoadMap(key); |
4350 var_unique->Bind(key); | |
4351 // Symbols are unique. | 4328 // Symbols are unique. |
4352 GotoIf(IsSymbolMap(key_map), if_keyisunique); | 4329 GotoIf(IsSymbolMap(key_map), if_keyisunique); |
4353 Node* key_instance_type = LoadMapInstanceType(key_map); | 4330 Node* key_instance_type = LoadMapInstanceType(key_map); |
4354 // Miss if |key| is not a String. | 4331 // Miss if |key| is not a String. |
4355 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); | 4332 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); |
4356 GotoUnless(IsStringInstanceType(key_instance_type), if_bailout); | 4333 GotoUnless(IsStringInstanceType(key_instance_type), if_bailout); |
4357 // |key| is a String. Check if it has a cached array index. | 4334 // |key| is a String. Check if it has a cached array index. |
4358 Node* hash = LoadNameHashField(key); | 4335 Node* hash = LoadNameHashField(key); |
4359 Node* contains_index = | 4336 Node* contains_index = |
4360 Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); | 4337 Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); |
4361 GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_hascachedindex); | 4338 GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_hascachedindex); |
4362 // No cached array index. If the string knows that it contains an index, | 4339 // No cached array index. If the string knows that it contains an index, |
4363 // then it must be an uncacheable index. Handle this case in the runtime. | 4340 // then it must be an uncacheable index. Handle this case in the runtime. |
4364 Node* not_an_index = | 4341 Node* not_an_index = |
4365 Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); | 4342 Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); |
4366 GotoIf(Word32Equal(not_an_index, Int32Constant(0)), if_bailout); | 4343 GotoIf(Word32Equal(not_an_index, Int32Constant(0)), if_bailout); |
4367 // Check if we have a ThinString. | |
4368 GotoIf(Word32Equal(key_instance_type, Int32Constant(THIN_STRING_TYPE)), | |
4369 &if_thinstring); | |
4370 GotoIf( | |
4371 Word32Equal(key_instance_type, Int32Constant(THIN_ONE_BYTE_STRING_TYPE)), | |
4372 &if_thinstring); | |
4373 // Finally, check if |key| is internalized. | 4344 // Finally, check if |key| is internalized. |
4374 STATIC_ASSERT(kNotInternalizedTag != 0); | 4345 STATIC_ASSERT(kNotInternalizedTag != 0); |
4375 Node* not_internalized = | 4346 Node* not_internalized = |
4376 Word32And(key_instance_type, Int32Constant(kIsNotInternalizedMask)); | 4347 Word32And(key_instance_type, Int32Constant(kIsNotInternalizedMask)); |
4377 GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)), if_bailout); | 4348 GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)), if_bailout); |
4378 Goto(if_keyisunique); | 4349 Goto(if_keyisunique); |
4379 | 4350 |
4380 Bind(&if_thinstring); | |
4381 var_unique->Bind(LoadObjectField(key, ThinString::kActualOffset)); | |
4382 Goto(if_keyisunique); | |
4383 | |
4384 Bind(&if_hascachedindex); | 4351 Bind(&if_hascachedindex); |
4385 var_index->Bind(DecodeWordFromWord32<Name::ArrayIndexValueBits>(hash)); | 4352 var_index->Bind(DecodeWordFromWord32<Name::ArrayIndexValueBits>(hash)); |
4386 Goto(if_keyisindex); | 4353 Goto(if_keyisindex); |
4387 } | 4354 } |
4388 | 4355 |
4389 template <typename Dictionary> | 4356 template <typename Dictionary> |
4390 Node* CodeStubAssembler::EntryToIndex(Node* entry, int field_index) { | 4357 Node* CodeStubAssembler::EntryToIndex(Node* entry, int field_index) { |
4391 Node* entry_index = IntPtrMul(entry, IntPtrConstant(Dictionary::kEntrySize)); | 4358 Node* entry_index = IntPtrMul(entry, IntPtrConstant(Dictionary::kEntrySize)); |
4392 return IntPtrAdd(entry_index, IntPtrConstant(Dictionary::kElementsStartIndex + | 4359 return IntPtrAdd(entry_index, IntPtrConstant(Dictionary::kElementsStartIndex + |
4393 field_index)); | 4360 field_index)); |
(...skipping 829 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5223 Label if_objectisreceiver(this); | 5190 Label if_objectisreceiver(this); |
5224 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | 5191 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
5225 STATIC_ASSERT(FIRST_JS_RECEIVER_TYPE == JS_PROXY_TYPE); | 5192 STATIC_ASSERT(FIRST_JS_RECEIVER_TYPE == JS_PROXY_TYPE); |
5226 Branch( | 5193 Branch( |
5227 Int32GreaterThan(instance_type, Int32Constant(FIRST_JS_RECEIVER_TYPE)), | 5194 Int32GreaterThan(instance_type, Int32Constant(FIRST_JS_RECEIVER_TYPE)), |
5228 &if_objectisreceiver, if_bailout); | 5195 &if_objectisreceiver, if_bailout); |
5229 Bind(&if_objectisreceiver); | 5196 Bind(&if_objectisreceiver); |
5230 } | 5197 } |
5231 | 5198 |
5232 Variable var_index(this, MachineType::PointerRepresentation()); | 5199 Variable var_index(this, MachineType::PointerRepresentation()); |
5233 Variable var_unique(this, MachineRepresentation::kTagged); | |
5234 | 5200 |
5235 Label if_keyisindex(this), if_iskeyunique(this); | 5201 Label if_keyisindex(this), if_iskeyunique(this); |
5236 TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, &var_unique, | 5202 TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, if_bailout); |
5237 if_bailout); | |
5238 | 5203 |
5239 Bind(&if_iskeyunique); | 5204 Bind(&if_iskeyunique); |
5240 { | 5205 { |
5241 Variable var_holder(this, MachineRepresentation::kTagged); | 5206 Variable var_holder(this, MachineRepresentation::kTagged); |
5242 Variable var_holder_map(this, MachineRepresentation::kTagged); | 5207 Variable var_holder_map(this, MachineRepresentation::kTagged); |
5243 Variable var_holder_instance_type(this, MachineRepresentation::kWord32); | 5208 Variable var_holder_instance_type(this, MachineRepresentation::kWord32); |
5244 | 5209 |
5245 Variable* merged_variables[] = {&var_holder, &var_holder_map, | 5210 Variable* merged_variables[] = {&var_holder, &var_holder_map, |
5246 &var_holder_instance_type}; | 5211 &var_holder_instance_type}; |
5247 Label loop(this, arraysize(merged_variables), merged_variables); | 5212 Label loop(this, arraysize(merged_variables), merged_variables); |
5248 var_holder.Bind(receiver); | 5213 var_holder.Bind(receiver); |
5249 var_holder_map.Bind(map); | 5214 var_holder_map.Bind(map); |
5250 var_holder_instance_type.Bind(instance_type); | 5215 var_holder_instance_type.Bind(instance_type); |
5251 Goto(&loop); | 5216 Goto(&loop); |
5252 Bind(&loop); | 5217 Bind(&loop); |
5253 { | 5218 { |
5254 Node* holder_map = var_holder_map.value(); | 5219 Node* holder_map = var_holder_map.value(); |
5255 Node* holder_instance_type = var_holder_instance_type.value(); | 5220 Node* holder_instance_type = var_holder_instance_type.value(); |
5256 | 5221 |
5257 Label next_proto(this); | 5222 Label next_proto(this); |
5258 lookup_property_in_holder(receiver, var_holder.value(), holder_map, | 5223 lookup_property_in_holder(receiver, var_holder.value(), holder_map, |
5259 holder_instance_type, var_unique.value(), | 5224 holder_instance_type, key, &next_proto, |
5260 &next_proto, if_bailout); | 5225 if_bailout); |
5261 Bind(&next_proto); | 5226 Bind(&next_proto); |
5262 | 5227 |
5263 // Bailout if it can be an integer indexed exotic case. | 5228 // Bailout if it can be an integer indexed exotic case. |
5264 GotoIf( | 5229 GotoIf( |
5265 Word32Equal(holder_instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)), | 5230 Word32Equal(holder_instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)), |
5266 if_bailout); | 5231 if_bailout); |
5267 | 5232 |
5268 Node* proto = LoadMapPrototype(holder_map); | 5233 Node* proto = LoadMapPrototype(holder_map); |
5269 | 5234 |
5270 Label if_not_null(this); | 5235 Label if_not_null(this); |
(...skipping 3010 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8281 StoreObjectFieldNoWriteBarrier(result, | 8246 StoreObjectFieldNoWriteBarrier(result, |
8282 PromiseReactionJobInfo::kDebugNameOffset, | 8247 PromiseReactionJobInfo::kDebugNameOffset, |
8283 SmiConstant(kDebugNotActive)); | 8248 SmiConstant(kDebugNotActive)); |
8284 StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kContextOffset, | 8249 StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kContextOffset, |
8285 context); | 8250 context); |
8286 return result; | 8251 return result; |
8287 } | 8252 } |
8288 | 8253 |
8289 } // namespace internal | 8254 } // namespace internal |
8290 } // namespace v8 | 8255 } // namespace v8 |
OLD | NEW |