Chromium Code Reviews| 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 } | |
| 1575 Node* result = Allocate(SeqOneByteString::SizeFor(length), flags); | 1578 Node* result = Allocate(SeqOneByteString::SizeFor(length), flags); |
| 1576 DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex)); | 1579 DCHECK(Heap::RootIsImmortalImmovable(Heap::kOneByteStringMapRootIndex)); |
| 1577 StoreMapNoWriteBarrier(result, Heap::kOneByteStringMapRootIndex); | 1580 StoreMapNoWriteBarrier(result, Heap::kOneByteStringMapRootIndex); |
| 1578 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset, | 1581 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset, |
| 1579 SmiConstant(Smi::FromInt(length))); | 1582 SmiConstant(Smi::FromInt(length))); |
| 1580 // Initialize both used and unused parts of hash field slot at once. | 1583 // Initialize both used and unused parts of hash field slot at once. |
| 1581 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldSlot, | 1584 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldSlot, |
| 1582 IntPtrConstant(String::kEmptyHashField), | 1585 IntPtrConstant(String::kEmptyHashField), |
| 1583 MachineType::PointerRepresentation()); | 1586 MachineType::PointerRepresentation()); |
| 1584 return result; | 1587 return result; |
| 1585 } | 1588 } |
| 1586 | 1589 |
| 1587 Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length, | 1590 Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length, |
| 1588 ParameterMode mode, | 1591 ParameterMode mode, |
| 1589 AllocationFlags flags) { | 1592 AllocationFlags flags) { |
| 1590 Comment("AllocateSeqOneByteString"); | 1593 Comment("AllocateSeqOneByteString"); |
| 1591 Variable var_result(this, MachineRepresentation::kTagged); | 1594 Variable var_result(this, MachineRepresentation::kTagged); |
| 1592 | 1595 |
| 1593 // Compute the SeqOneByteString size and check if it fits into new space. | 1596 // Compute the SeqOneByteString size and check if it fits into new space. |
| 1594 Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), | 1597 Label if_lengthiszero(this), if_sizeissmall(this), |
| 1595 if_join(this); | 1598 if_notsizeissmall(this, Label::kDeferred), if_join(this); |
| 1599 GotoIf(WordEqual(length, IntPtrOrSmiConstant(0, mode)), &if_lengthiszero); | |
| 1600 | |
| 1596 Node* raw_size = GetArrayAllocationSize( | 1601 Node* raw_size = GetArrayAllocationSize( |
| 1597 length, UINT8_ELEMENTS, mode, | 1602 length, UINT8_ELEMENTS, mode, |
| 1598 SeqOneByteString::kHeaderSize + kObjectAlignmentMask); | 1603 SeqOneByteString::kHeaderSize + kObjectAlignmentMask); |
| 1599 Node* size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); | 1604 Node* size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); |
| 1600 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), | 1605 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), |
| 1601 &if_sizeissmall, &if_notsizeissmall); | 1606 &if_sizeissmall, &if_notsizeissmall); |
| 1602 | 1607 |
| 1603 Bind(&if_sizeissmall); | 1608 Bind(&if_sizeissmall); |
| 1604 { | 1609 { |
| 1605 // Just allocate the SeqOneByteString in new space. | 1610 // Just allocate the SeqOneByteString in new space. |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1618 | 1623 |
| 1619 Bind(&if_notsizeissmall); | 1624 Bind(&if_notsizeissmall); |
| 1620 { | 1625 { |
| 1621 // We might need to allocate in large object space, go to the runtime. | 1626 // We might need to allocate in large object space, go to the runtime. |
| 1622 Node* result = CallRuntime(Runtime::kAllocateSeqOneByteString, context, | 1627 Node* result = CallRuntime(Runtime::kAllocateSeqOneByteString, context, |
| 1623 ParameterToTagged(length, mode)); | 1628 ParameterToTagged(length, mode)); |
| 1624 var_result.Bind(result); | 1629 var_result.Bind(result); |
| 1625 Goto(&if_join); | 1630 Goto(&if_join); |
| 1626 } | 1631 } |
| 1627 | 1632 |
| 1633 Bind(&if_lengthiszero); | |
| 1634 { | |
| 1635 var_result.Bind(LoadRoot(Heap::kempty_stringRootIndex)); | |
| 1636 Goto(&if_join); | |
| 1637 } | |
| 1638 | |
| 1628 Bind(&if_join); | 1639 Bind(&if_join); |
| 1629 return var_result.value(); | 1640 return var_result.value(); |
| 1630 } | 1641 } |
| 1631 | 1642 |
| 1632 Node* CodeStubAssembler::AllocateSeqTwoByteString(int length, | 1643 Node* CodeStubAssembler::AllocateSeqTwoByteString(int length, |
| 1633 AllocationFlags flags) { | 1644 AllocationFlags flags) { |
| 1634 Comment("AllocateSeqTwoByteString"); | 1645 Comment("AllocateSeqTwoByteString"); |
| 1646 if (length == 0) { | |
| 1647 return LoadRoot(Heap::kempty_stringRootIndex); | |
| 1648 } | |
| 1635 Node* result = Allocate(SeqTwoByteString::SizeFor(length), flags); | 1649 Node* result = Allocate(SeqTwoByteString::SizeFor(length), flags); |
| 1636 DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex)); | 1650 DCHECK(Heap::RootIsImmortalImmovable(Heap::kStringMapRootIndex)); |
| 1637 StoreMapNoWriteBarrier(result, Heap::kStringMapRootIndex); | 1651 StoreMapNoWriteBarrier(result, Heap::kStringMapRootIndex); |
| 1638 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset, | 1652 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset, |
| 1639 SmiConstant(Smi::FromInt(length))); | 1653 SmiConstant(Smi::FromInt(length))); |
| 1640 // Initialize both used and unused parts of hash field slot at once. | 1654 // Initialize both used and unused parts of hash field slot at once. |
| 1641 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldSlot, | 1655 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldSlot, |
| 1642 IntPtrConstant(String::kEmptyHashField), | 1656 IntPtrConstant(String::kEmptyHashField), |
| 1643 MachineType::PointerRepresentation()); | 1657 MachineType::PointerRepresentation()); |
| 1644 return result; | 1658 return result; |
| 1645 } | 1659 } |
| 1646 | 1660 |
| 1647 Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length, | 1661 Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length, |
| 1648 ParameterMode mode, | 1662 ParameterMode mode, |
| 1649 AllocationFlags flags) { | 1663 AllocationFlags flags) { |
| 1650 Comment("AllocateSeqTwoByteString"); | 1664 Comment("AllocateSeqTwoByteString"); |
| 1651 Variable var_result(this, MachineRepresentation::kTagged); | 1665 Variable var_result(this, MachineRepresentation::kTagged); |
| 1652 | 1666 |
| 1653 // Compute the SeqTwoByteString size and check if it fits into new space. | 1667 // Compute the SeqTwoByteString size and check if it fits into new space. |
| 1654 Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), | 1668 Label if_lengthiszero(this), if_sizeissmall(this), |
| 1655 if_join(this); | 1669 if_notsizeissmall(this, Label::kDeferred), if_join(this); |
| 1670 GotoIf(WordEqual(length, IntPtrOrSmiConstant(0, mode)), &if_lengthiszero); | |
| 1671 | |
| 1656 Node* raw_size = GetArrayAllocationSize( | 1672 Node* raw_size = GetArrayAllocationSize( |
| 1657 length, UINT16_ELEMENTS, mode, | 1673 length, UINT16_ELEMENTS, mode, |
| 1658 SeqOneByteString::kHeaderSize + kObjectAlignmentMask); | 1674 SeqOneByteString::kHeaderSize + kObjectAlignmentMask); |
| 1659 Node* size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); | 1675 Node* size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask)); |
| 1660 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), | 1676 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)), |
| 1661 &if_sizeissmall, &if_notsizeissmall); | 1677 &if_sizeissmall, &if_notsizeissmall); |
| 1662 | 1678 |
| 1663 Bind(&if_sizeissmall); | 1679 Bind(&if_sizeissmall); |
| 1664 { | 1680 { |
| 1665 // Just allocate the SeqTwoByteString in new space. | 1681 // Just allocate the SeqTwoByteString in new space. |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1680 Bind(&if_notsizeissmall); | 1696 Bind(&if_notsizeissmall); |
| 1681 { | 1697 { |
| 1682 // We might need to allocate in large object space, go to the runtime. | 1698 // We might need to allocate in large object space, go to the runtime. |
| 1683 Node* result = | 1699 Node* result = |
| 1684 CallRuntime(Runtime::kAllocateSeqTwoByteString, context, | 1700 CallRuntime(Runtime::kAllocateSeqTwoByteString, context, |
| 1685 mode == SMI_PARAMETERS ? length : SmiFromWord(length)); | 1701 mode == SMI_PARAMETERS ? length : SmiFromWord(length)); |
| 1686 var_result.Bind(result); | 1702 var_result.Bind(result); |
| 1687 Goto(&if_join); | 1703 Goto(&if_join); |
| 1688 } | 1704 } |
| 1689 | 1705 |
| 1706 Bind(&if_lengthiszero); | |
| 1707 { | |
| 1708 var_result.Bind(LoadRoot(Heap::kempty_stringRootIndex)); | |
| 1709 Goto(&if_join); | |
| 1710 } | |
| 1711 | |
| 1690 Bind(&if_join); | 1712 Bind(&if_join); |
| 1691 return var_result.value(); | 1713 return var_result.value(); |
| 1692 } | 1714 } |
| 1693 | 1715 |
| 1694 Node* CodeStubAssembler::AllocateSlicedString( | 1716 Node* CodeStubAssembler::AllocateSlicedString( |
| 1695 Heap::RootListIndex map_root_index, Node* length, Node* parent, | 1717 Heap::RootListIndex map_root_index, Node* length, Node* parent, |
| 1696 Node* offset) { | 1718 Node* offset) { |
| 1697 CSA_ASSERT(this, TaggedIsSmi(length)); | 1719 CSA_ASSERT(this, TaggedIsSmi(length)); |
| 1698 Node* result = Allocate(SlicedString::kSize); | 1720 Node* result = Allocate(SlicedString::kSize); |
| 1699 DCHECK(Heap::RootIsImmortalImmovable(map_root_index)); | 1721 DCHECK(Heap::RootIsImmortalImmovable(map_root_index)); |
| (...skipping 1295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2995 Node* CodeStubAssembler::IsJSFunction(Node* object) { | 3017 Node* CodeStubAssembler::IsJSFunction(Node* object) { |
| 2996 return HasInstanceType(object, JS_FUNCTION_TYPE); | 3018 return HasInstanceType(object, JS_FUNCTION_TYPE); |
| 2997 } | 3019 } |
| 2998 | 3020 |
| 2999 Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index, | 3021 Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index, |
| 3000 ParameterMode parameter_mode) { | 3022 ParameterMode parameter_mode) { |
| 3001 CSA_ASSERT(this, IsString(string)); | 3023 CSA_ASSERT(this, IsString(string)); |
| 3002 // Translate the {index} into a Word. | 3024 // Translate the {index} into a Word. |
| 3003 index = ParameterToWord(index, parameter_mode); | 3025 index = ParameterToWord(index, parameter_mode); |
| 3004 | 3026 |
| 3005 // We may need to loop in case of cons or sliced strings. | 3027 // We may need to loop in case of cons, thin, or sliced strings. |
| 3006 Variable var_index(this, MachineType::PointerRepresentation()); | 3028 Variable var_index(this, MachineType::PointerRepresentation()); |
| 3007 Variable var_result(this, MachineRepresentation::kWord32); | 3029 Variable var_result(this, MachineRepresentation::kWord32); |
| 3008 Variable var_string(this, MachineRepresentation::kTagged); | 3030 Variable var_string(this, MachineRepresentation::kTagged); |
| 3009 Variable* loop_vars[] = {&var_index, &var_string}; | 3031 Variable* loop_vars[] = {&var_index, &var_string}; |
| 3010 Label done_loop(this, &var_result), loop(this, 2, loop_vars); | 3032 Label done_loop(this, &var_result), loop(this, 2, loop_vars); |
| 3011 var_string.Bind(string); | 3033 var_string.Bind(string); |
| 3012 var_index.Bind(index); | 3034 var_index.Bind(index); |
| 3013 Goto(&loop); | 3035 Goto(&loop); |
| 3014 Bind(&loop); | 3036 Bind(&loop); |
| 3015 { | 3037 { |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3147 // The {string} might be compressed, call the runtime. | 3169 // The {string} might be compressed, call the runtime. |
| 3148 var_result.Bind(SmiToWord32( | 3170 var_result.Bind(SmiToWord32( |
| 3149 CallRuntime(Runtime::kExternalStringGetChar, | 3171 CallRuntime(Runtime::kExternalStringGetChar, |
| 3150 NoContextConstant(), string, SmiTag(index)))); | 3172 NoContextConstant(), string, SmiTag(index)))); |
| 3151 Goto(&done_loop); | 3173 Goto(&done_loop); |
| 3152 } | 3174 } |
| 3153 } | 3175 } |
| 3154 | 3176 |
| 3155 Bind(&if_stringisnotexternal); | 3177 Bind(&if_stringisnotexternal); |
| 3156 { | 3178 { |
| 3157 // The {string} is a SlicedString, continue with its parent. | 3179 Label if_stringissliced(this), if_stringisthin(this); |
| 3158 Node* string_offset = | 3180 Branch( |
| 3159 LoadAndUntagObjectField(string, SlicedString::kOffsetOffset); | 3181 Word32Equal(Word32And(string_instance_type, |
| 3160 Node* string_parent = | 3182 Int32Constant(kStringRepresentationMask)), |
| 3161 LoadObjectField(string, SlicedString::kParentOffset); | 3183 Int32Constant(kSlicedStringTag)), |
| 3162 var_index.Bind(IntPtrAdd(index, string_offset)); | 3184 &if_stringissliced, &if_stringisthin); |
| 3163 var_string.Bind(string_parent); | 3185 Bind(&if_stringissliced); |
| 3164 Goto(&loop); | 3186 { |
| 3187 // The {string} is a SlicedString, continue with its parent. | |
| 3188 Node* string_offset = | |
| 3189 LoadAndUntagObjectField(string, SlicedString::kOffsetOffset); | |
| 3190 Node* string_parent = | |
| 3191 LoadObjectField(string, SlicedString::kParentOffset); | |
| 3192 var_index.Bind(IntPtrAdd(index, string_offset)); | |
| 3193 var_string.Bind(string_parent); | |
| 3194 Goto(&loop); | |
| 3195 } | |
| 3196 Bind(&if_stringisthin); | |
| 3197 { | |
| 3198 // The {string} is a ThinString, continue with its actual value. | |
| 3199 var_string.Bind(LoadObjectField(string, ThinString::kActualOffset)); | |
| 3200 Goto(&loop); | |
| 3201 } | |
| 3165 } | 3202 } |
| 3166 } | 3203 } |
| 3167 } | 3204 } |
| 3168 } | 3205 } |
| 3169 | 3206 |
| 3170 Bind(&done_loop); | 3207 Bind(&done_loop); |
| 3171 return var_result.value(); | 3208 return var_result.value(); |
| 3172 } | 3209 } |
| 3173 | 3210 |
| 3174 Node* CodeStubAssembler::StringFromCharCode(Node* code) { | 3211 Node* CodeStubAssembler::StringFromCharCode(Node* code) { |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3285 } | 3322 } |
| 3286 | 3323 |
| 3287 } // namespace | 3324 } // namespace |
| 3288 | 3325 |
| 3289 Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, | 3326 Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, |
| 3290 Node* to) { | 3327 Node* to) { |
| 3291 Label end(this); | 3328 Label end(this); |
| 3292 Label runtime(this); | 3329 Label runtime(this); |
| 3293 | 3330 |
| 3294 Variable var_instance_type(this, MachineRepresentation::kWord32); // Int32. | 3331 Variable var_instance_type(this, MachineRepresentation::kWord32); // Int32. |
| 3332 Variable var_representation(this, MachineRepresentation::kWord32); // Int32. | |
| 3295 Variable var_result(this, MachineRepresentation::kTagged); // String. | 3333 Variable var_result(this, MachineRepresentation::kTagged); // String. |
| 3296 Variable var_from(this, MachineRepresentation::kTagged); // Smi. | 3334 Variable var_from(this, MachineRepresentation::kTagged); // Smi. |
| 3297 Variable var_string(this, MachineRepresentation::kTagged); // String. | 3335 Variable var_string(this, MachineRepresentation::kTagged); // String. |
| 3298 | 3336 |
| 3299 var_instance_type.Bind(Int32Constant(0)); | 3337 var_instance_type.Bind(Int32Constant(0)); |
| 3338 var_representation.Bind(Int32Constant(0)); | |
| 3300 var_string.Bind(string); | 3339 var_string.Bind(string); |
| 3301 var_from.Bind(from); | 3340 var_from.Bind(from); |
| 3302 | 3341 |
| 3303 // Make sure first argument is a string. | 3342 // Make sure first argument is a string. |
| 3304 | 3343 |
| 3305 // Bailout if receiver is a Smi. | 3344 // Bailout if receiver is a Smi. |
| 3306 GotoIf(TaggedIsSmi(string), &runtime); | 3345 GotoIf(TaggedIsSmi(string), &runtime); |
| 3307 | 3346 |
| 3308 // Load the instance type of the {string}. | 3347 // Load the instance type of the {string}. |
| 3309 Node* const instance_type = LoadInstanceType(string); | 3348 Node* const instance_type = LoadInstanceType(string); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 3330 | 3369 |
| 3331 Label single_char(this); | 3370 Label single_char(this); |
| 3332 GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char); | 3371 GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char); |
| 3333 | 3372 |
| 3334 // TODO(jgruber): Add an additional case for substring of length == 0? | 3373 // TODO(jgruber): Add an additional case for substring of length == 0? |
| 3335 | 3374 |
| 3336 // Deal with different string types: update the index if necessary | 3375 // Deal with different string types: update the index if necessary |
| 3337 // and put the underlying string into var_string. | 3376 // and put the underlying string into var_string. |
| 3338 | 3377 |
| 3339 // If the string is not indirect, it can only be sequential or external. | 3378 // If the string is not indirect, it can only be sequential or external. |
| 3340 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); | 3379 STATIC_ASSERT(kIsIndirectStringMask == |
| 3380 (kSlicedStringTag & kConsStringTag & kThinStringTag)); | |
| 3341 STATIC_ASSERT(kIsIndirectStringMask != 0); | 3381 STATIC_ASSERT(kIsIndirectStringMask != 0); |
| 3342 Label underlying_unpacked(this); | 3382 Label underlying_unpacked(this); |
| 3343 GotoIf(Word32Equal( | 3383 GotoIf(Word32Equal( |
| 3344 Word32And(instance_type, Int32Constant(kIsIndirectStringMask)), | 3384 Word32And(instance_type, Int32Constant(kIsIndirectStringMask)), |
| 3345 Int32Constant(0)), | 3385 Int32Constant(0)), |
| 3346 &underlying_unpacked); | 3386 &underlying_unpacked); |
| 3347 | 3387 |
| 3348 // The subject string is either a sliced or cons string. | 3388 // The subject string is a sliced, cons, or thin string. |
| 3349 | 3389 |
| 3350 Label sliced_string(this); | 3390 Label sliced_string(this), thin_or_sliced(this); |
| 3351 GotoIf(Word32NotEqual( | 3391 var_representation.Bind( |
| 3352 Word32And(instance_type, Int32Constant(kSlicedNotConsMask)), | 3392 Word32And(instance_type, Int32Constant(kStringRepresentationMask))); |
| 3353 Int32Constant(0)), | 3393 GotoIf( |
| 3354 &sliced_string); | 3394 Word32NotEqual(var_representation.value(), Int32Constant(kConsStringTag)), |
| 3395 &thin_or_sliced); | |
| 3355 | 3396 |
| 3356 // Cons string. Check whether it is flat, then fetch first part. | 3397 // Cons string. Check whether it is flat, then fetch first part. |
| 3357 // Flat cons strings have an empty second part. | 3398 // Flat cons strings have an empty second part. |
| 3358 { | 3399 { |
| 3359 GotoIf(WordNotEqual(LoadObjectField(string, ConsString::kSecondOffset), | 3400 GotoIf(WordNotEqual(LoadObjectField(string, ConsString::kSecondOffset), |
| 3360 EmptyStringConstant()), | 3401 EmptyStringConstant()), |
| 3361 &runtime); | 3402 &runtime); |
| 3362 | 3403 |
| 3363 Node* first_string_part = LoadObjectField(string, ConsString::kFirstOffset); | 3404 Node* first_string_part = LoadObjectField(string, ConsString::kFirstOffset); |
| 3364 var_string.Bind(first_string_part); | 3405 var_string.Bind(first_string_part); |
| 3365 var_instance_type.Bind(LoadInstanceType(first_string_part)); | 3406 var_instance_type.Bind(LoadInstanceType(first_string_part)); |
| 3407 var_representation.Bind(Word32And( | |
| 3408 var_instance_type.value(), Int32Constant(kStringRepresentationMask))); | |
| 3366 | 3409 |
| 3410 // The loaded first part might be a thin string. | |
| 3411 Branch(Word32Equal(Word32And(var_instance_type.value(), | |
| 3412 Int32Constant(kIsIndirectStringMask)), | |
| 3413 Int32Constant(0)), | |
| 3414 &underlying_unpacked, &thin_or_sliced); | |
| 3415 } | |
| 3416 | |
| 3417 Bind(&thin_or_sliced); | |
| 3418 { | |
| 3419 GotoIf(Word32Equal(var_representation.value(), | |
| 3420 Int32Constant(kSlicedStringTag)), | |
| 3421 &sliced_string); | |
| 3422 Node* actual_string = | |
| 3423 LoadObjectField(var_string.value(), ThinString::kActualOffset); | |
| 3424 var_string.Bind(actual_string); | |
| 3425 var_instance_type.Bind(LoadInstanceType(actual_string)); | |
| 3367 Goto(&underlying_unpacked); | 3426 Goto(&underlying_unpacked); |
| 3368 } | 3427 } |
| 3369 | 3428 |
| 3370 Bind(&sliced_string); | 3429 Bind(&sliced_string); |
| 3371 { | 3430 { |
| 3372 // Fetch parent and correct start index by offset. | 3431 // Fetch parent and correct start index by offset. |
| 3373 Node* sliced_offset = LoadObjectField(string, SlicedString::kOffsetOffset); | 3432 Node* sliced_offset = |
| 3433 LoadObjectField(var_string.value(), SlicedString::kOffsetOffset); | |
| 3374 var_from.Bind(SmiAdd(from, sliced_offset)); | 3434 var_from.Bind(SmiAdd(from, sliced_offset)); |
| 3375 | 3435 |
| 3376 Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); | 3436 Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); |
| 3377 var_string.Bind(slice_parent); | 3437 var_string.Bind(slice_parent); |
| 3378 | 3438 |
| 3379 Node* slice_parent_instance_type = LoadInstanceType(slice_parent); | 3439 Node* slice_parent_instance_type = LoadInstanceType(slice_parent); |
| 3380 var_instance_type.Bind(slice_parent_instance_type); | 3440 var_instance_type.Bind(slice_parent_instance_type); |
| 3381 | 3441 |
| 3382 Goto(&underlying_unpacked); | 3442 Goto(&underlying_unpacked); |
| 3383 } | 3443 } |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3502 { | 3562 { |
| 3503 var_result.Bind( | 3563 var_result.Bind( |
| 3504 CallRuntime(Runtime::kSubString, context, string, from, to)); | 3564 CallRuntime(Runtime::kSubString, context, string, from, to)); |
| 3505 Goto(&end); | 3565 Goto(&end); |
| 3506 } | 3566 } |
| 3507 | 3567 |
| 3508 Bind(&end); | 3568 Bind(&end); |
| 3509 return var_result.value(); | 3569 return var_result.value(); |
| 3510 } | 3570 } |
| 3511 | 3571 |
| 3572 void CodeStubAssembler::MaybeDerefIndirectString(Variable* var_string, | |
| 3573 Node* instance_type, | |
| 3574 Variable* var_did_something) { | |
| 3575 Label deref(this), done(this, var_did_something); | |
| 3576 Node* representation = | |
| 3577 Word32And(instance_type, Int32Constant(kStringRepresentationMask)); | |
| 3578 STATIC_ASSERT(ThinString::kActualOffset == ConsString::kFirstOffset); | |
| 3579 GotoIf(Word32Equal(representation, Int32Constant(kThinStringTag)), &deref); | |
| 3580 GotoIf(Word32NotEqual(representation, Int32Constant(kConsStringTag)), &done); | |
| 3581 // Cons string. | |
| 3582 Node* rhs = LoadObjectField(var_string->value(), ConsString::kSecondOffset); | |
| 3583 GotoIf(WordEqual(rhs, EmptyStringConstant()), &deref); | |
|
Igor Sheludko
2017/01/18 14:55:20
Maybe we should stop using ConsStrings this way on
Jakob Kummerow
2017/01/19 10:20:16
Yes, maybe.
Pro: code checking for indirect strin
| |
| 3584 Goto(&done); | |
| 3585 | |
| 3586 Bind(&deref); | |
|
Igor Sheludko
2017/01/18 14:55:20
STATIC_ASSERT(ConsString::kFirstOffset == ThinStri
Jakob Kummerow
2017/01/19 10:20:16
Done.
| |
| 3587 var_string->Bind( | |
| 3588 LoadObjectField(var_string->value(), ThinString::kActualOffset)); | |
| 3589 var_did_something->Bind(IntPtrConstant(1)); | |
| 3590 Goto(&done); | |
| 3591 | |
| 3592 Bind(&done); | |
| 3593 } | |
| 3594 | |
| 3595 void CodeStubAssembler::MaybeDerefIndirectStrings(Variable* var_left, | |
| 3596 Node* left_instance_type, | |
| 3597 Variable* var_right, | |
| 3598 Node* right_instance_type, | |
| 3599 Label* did_something) { | |
| 3600 Variable var_did_something(this, MachineType::PointerRepresentation()); | |
| 3601 var_did_something.Bind(IntPtrConstant(0)); | |
| 3602 MaybeDerefIndirectString(var_left, left_instance_type, &var_did_something); | |
| 3603 MaybeDerefIndirectString(var_right, right_instance_type, &var_did_something); | |
| 3604 | |
| 3605 GotoIf(WordNotEqual(var_did_something.value(), IntPtrConstant(0)), | |
| 3606 did_something); | |
| 3607 // Fall through if neither string was an indirect string. | |
| 3608 } | |
| 3609 | |
| 3512 Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, | 3610 Node* CodeStubAssembler::StringAdd(Node* context, Node* left, Node* right, |
| 3513 AllocationFlags flags) { | 3611 AllocationFlags flags) { |
| 3514 Label check_right(this); | 3612 Label check_right(this); |
| 3515 Label runtime(this, Label::kDeferred); | 3613 Label runtime(this, Label::kDeferred); |
| 3516 Label cons(this); | 3614 Label cons(this); |
| 3517 Label non_cons(this); | |
| 3518 Variable result(this, MachineRepresentation::kTagged); | 3615 Variable result(this, MachineRepresentation::kTagged); |
| 3519 Label done(this, &result); | 3616 Label done(this, &result); |
| 3520 Label done_native(this, &result); | 3617 Label done_native(this, &result); |
| 3521 Counters* counters = isolate()->counters(); | 3618 Counters* counters = isolate()->counters(); |
| 3522 | 3619 |
| 3523 Node* left_length = LoadStringLength(left); | 3620 Node* left_length = LoadStringLength(left); |
| 3524 GotoIf(WordNotEqual(IntPtrConstant(0), left_length), &check_right); | 3621 GotoIf(WordNotEqual(IntPtrConstant(0), left_length), &check_right); |
| 3525 result.Bind(right); | 3622 result.Bind(right); |
| 3526 Goto(&done_native); | 3623 Goto(&done_native); |
| 3527 | 3624 |
| 3528 Bind(&check_right); | 3625 Bind(&check_right); |
| 3529 Node* right_length = LoadStringLength(right); | 3626 Node* right_length = LoadStringLength(right); |
| 3530 GotoIf(WordNotEqual(IntPtrConstant(0), right_length), &cons); | 3627 GotoIf(WordNotEqual(IntPtrConstant(0), right_length), &cons); |
| 3531 result.Bind(left); | 3628 result.Bind(left); |
| 3532 Goto(&done_native); | 3629 Goto(&done_native); |
| 3533 | 3630 |
| 3534 Bind(&cons); | 3631 Bind(&cons); |
| 3535 CSA_ASSERT(this, TaggedIsSmi(left_length)); | 3632 { |
| 3536 CSA_ASSERT(this, TaggedIsSmi(right_length)); | 3633 CSA_ASSERT(this, TaggedIsSmi(left_length)); |
| 3537 Node* new_length = SmiAdd(left_length, right_length); | 3634 CSA_ASSERT(this, TaggedIsSmi(right_length)); |
| 3538 GotoIf(SmiAboveOrEqual(new_length, SmiConstant(String::kMaxLength)), | 3635 Node* new_length = SmiAdd(left_length, right_length); |
| 3539 &runtime); | 3636 GotoIf(SmiAboveOrEqual(new_length, SmiConstant(String::kMaxLength)), |
| 3637 &runtime); | |
| 3540 | 3638 |
| 3541 GotoIf(SmiLessThan(new_length, SmiConstant(ConsString::kMinLength)), | 3639 Variable var_left(this, MachineRepresentation::kTagged); |
| 3542 &non_cons); | 3640 Variable var_right(this, MachineRepresentation::kTagged); |
| 3641 Variable* input_vars[2] = {&var_left, &var_right}; | |
| 3642 Label non_cons(this, 2, input_vars); | |
| 3643 Label slow(this, Label::kDeferred); | |
| 3644 var_left.Bind(left); | |
| 3645 var_right.Bind(right); | |
| 3646 GotoIf(SmiLessThan(new_length, SmiConstant(ConsString::kMinLength)), | |
| 3647 &non_cons); | |
| 3543 | 3648 |
| 3544 result.Bind(NewConsString(context, new_length, left, right, flags)); | 3649 result.Bind(NewConsString(context, new_length, var_left.value(), |
| 3545 Goto(&done_native); | 3650 var_right.value(), flags)); |
| 3651 Goto(&done_native); | |
| 3546 | 3652 |
| 3547 Bind(&non_cons); | 3653 Bind(&non_cons); |
| 3548 | 3654 |
| 3549 Comment("Full string concatenate"); | 3655 Comment("Full string concatenate"); |
| 3550 Node* left_instance_type = LoadInstanceType(left); | 3656 Node* left_instance_type = LoadInstanceType(var_left.value()); |
| 3551 Node* right_instance_type = LoadInstanceType(right); | 3657 Node* right_instance_type = LoadInstanceType(var_right.value()); |
| 3552 // Compute intersection and difference of instance types. | 3658 // Compute intersection and difference of instance types. |
| 3553 | 3659 |
| 3554 Node* ored_instance_types = Word32Or(left_instance_type, right_instance_type); | 3660 Node* ored_instance_types = |
| 3555 Node* xored_instance_types = | 3661 Word32Or(left_instance_type, right_instance_type); |
| 3556 Word32Xor(left_instance_type, right_instance_type); | 3662 Node* xored_instance_types = |
| 3663 Word32Xor(left_instance_type, right_instance_type); | |
| 3557 | 3664 |
| 3558 // Check if both strings have the same encoding and both are sequential. | 3665 // Check if both strings have the same encoding and both are sequential. |
| 3559 GotoIf(Word32NotEqual(Word32And(xored_instance_types, | 3666 GotoIf(Word32NotEqual(Word32And(xored_instance_types, |
| 3560 Int32Constant(kStringEncodingMask)), | 3667 Int32Constant(kStringEncodingMask)), |
| 3561 Int32Constant(0)), | 3668 Int32Constant(0)), |
| 3562 &runtime); | 3669 &runtime); |
| 3563 GotoIf(Word32NotEqual(Word32And(ored_instance_types, | 3670 GotoIf(Word32NotEqual(Word32And(ored_instance_types, |
| 3564 Int32Constant(kStringRepresentationMask)), | 3671 Int32Constant(kStringRepresentationMask)), |
| 3565 Int32Constant(0)), | 3672 Int32Constant(0)), |
| 3566 &runtime); | 3673 &slow); |
| 3567 | 3674 |
| 3568 Label two_byte(this); | 3675 Label two_byte(this); |
| 3569 GotoIf(Word32Equal( | 3676 GotoIf(Word32Equal(Word32And(ored_instance_types, |
| 3570 Word32And(ored_instance_types, Int32Constant(kStringEncodingMask)), | 3677 Int32Constant(kStringEncodingMask)), |
| 3571 Int32Constant(kTwoByteStringTag)), | 3678 Int32Constant(kTwoByteStringTag)), |
| 3572 &two_byte); | 3679 &two_byte); |
| 3573 // One-byte sequential string case | 3680 // One-byte sequential string case |
| 3574 Node* new_string = | 3681 Node* new_string = |
| 3575 AllocateSeqOneByteString(context, new_length, SMI_PARAMETERS); | 3682 AllocateSeqOneByteString(context, new_length, SMI_PARAMETERS); |
| 3576 CopyStringCharacters(left, new_string, SmiConstant(Smi::kZero), | 3683 CopyStringCharacters(var_left.value(), new_string, SmiConstant(Smi::kZero), |
| 3577 SmiConstant(Smi::kZero), left_length, | |
| 3578 String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING, | |
| 3579 SMI_PARAMETERS); | |
| 3580 CopyStringCharacters(right, new_string, SmiConstant(Smi::kZero), left_length, | |
| 3581 right_length, String::ONE_BYTE_ENCODING, | |
| 3582 String::ONE_BYTE_ENCODING, SMI_PARAMETERS); | |
| 3583 result.Bind(new_string); | |
| 3584 Goto(&done_native); | |
| 3585 | |
| 3586 Bind(&two_byte); | |
| 3587 { | |
| 3588 // Two-byte sequential string case | |
| 3589 new_string = AllocateSeqTwoByteString(context, new_length, SMI_PARAMETERS); | |
| 3590 CopyStringCharacters(left, new_string, SmiConstant(Smi::kZero), | |
| 3591 SmiConstant(Smi::kZero), left_length, | 3684 SmiConstant(Smi::kZero), left_length, |
| 3592 String::TWO_BYTE_ENCODING, String::TWO_BYTE_ENCODING, | 3685 String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING, |
| 3593 SMI_PARAMETERS); | 3686 SMI_PARAMETERS); |
| 3594 CopyStringCharacters(right, new_string, SmiConstant(Smi::kZero), | 3687 CopyStringCharacters(var_right.value(), new_string, SmiConstant(Smi::kZero), |
| 3595 left_length, right_length, String::TWO_BYTE_ENCODING, | 3688 left_length, right_length, String::ONE_BYTE_ENCODING, |
| 3596 String::TWO_BYTE_ENCODING, SMI_PARAMETERS); | 3689 String::ONE_BYTE_ENCODING, SMI_PARAMETERS); |
| 3597 result.Bind(new_string); | 3690 result.Bind(new_string); |
| 3598 Goto(&done_native); | 3691 Goto(&done_native); |
| 3692 | |
| 3693 Bind(&two_byte); | |
| 3694 { | |
| 3695 // Two-byte sequential string case | |
| 3696 new_string = | |
| 3697 AllocateSeqTwoByteString(context, new_length, SMI_PARAMETERS); | |
| 3698 CopyStringCharacters(var_left.value(), new_string, | |
| 3699 SmiConstant(Smi::kZero), SmiConstant(Smi::kZero), | |
| 3700 left_length, String::TWO_BYTE_ENCODING, | |
| 3701 String::TWO_BYTE_ENCODING, SMI_PARAMETERS); | |
| 3702 CopyStringCharacters(var_right.value(), new_string, | |
| 3703 SmiConstant(Smi::kZero), left_length, right_length, | |
| 3704 String::TWO_BYTE_ENCODING, String::TWO_BYTE_ENCODING, | |
| 3705 SMI_PARAMETERS); | |
| 3706 result.Bind(new_string); | |
| 3707 Goto(&done_native); | |
| 3708 } | |
| 3709 | |
| 3710 Bind(&slow); | |
| 3711 { | |
| 3712 // Try to unwrap indirect strings, restart the above attempt on success. | |
| 3713 MaybeDerefIndirectStrings(&var_left, left_instance_type, &var_right, | |
| 3714 right_instance_type, &non_cons); | |
| 3715 Goto(&runtime); | |
| 3716 } | |
| 3599 } | 3717 } |
| 3600 | |
| 3601 Bind(&runtime); | 3718 Bind(&runtime); |
| 3602 { | 3719 { |
| 3603 result.Bind(CallRuntime(Runtime::kStringAdd, context, left, right)); | 3720 result.Bind(CallRuntime(Runtime::kStringAdd, context, left, right)); |
| 3604 Goto(&done); | 3721 Goto(&done); |
| 3605 } | 3722 } |
| 3606 | 3723 |
| 3607 Bind(&done_native); | 3724 Bind(&done_native); |
| 3608 { | 3725 { |
| 3609 IncrementCounter(counters->string_add_native(), 1); | 3726 IncrementCounter(counters->string_add_native(), 1); |
| 3610 Goto(&done); | 3727 Goto(&done); |
| (...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4136 Bind(&runtime); | 4253 Bind(&runtime); |
| 4137 { | 4254 { |
| 4138 result.Bind(CallRuntime(Runtime::kToString, context, input)); | 4255 result.Bind(CallRuntime(Runtime::kToString, context, input)); |
| 4139 Goto(&done); | 4256 Goto(&done); |
| 4140 } | 4257 } |
| 4141 | 4258 |
| 4142 Bind(&done); | 4259 Bind(&done); |
| 4143 return result.value(); | 4260 return result.value(); |
| 4144 } | 4261 } |
| 4145 | 4262 |
| 4146 Node* CodeStubAssembler::FlattenString(Node* string) { | |
| 4147 CSA_ASSERT(this, IsString(string)); | |
| 4148 Variable var_result(this, MachineRepresentation::kTagged); | |
| 4149 var_result.Bind(string); | |
| 4150 | |
| 4151 Node* instance_type = LoadInstanceType(string); | |
| 4152 | |
| 4153 // Check if the {string} is not a ConsString (i.e. already flat). | |
| 4154 Label is_cons(this, Label::kDeferred), is_flat_in_cons(this), end(this); | |
| 4155 { | |
| 4156 GotoUnless(Word32Equal(Word32And(instance_type, | |
| 4157 Int32Constant(kStringRepresentationMask)), | |
| 4158 Int32Constant(kConsStringTag)), | |
| 4159 &end); | |
| 4160 | |
| 4161 // Check whether the right hand side is the empty string (i.e. if | |
| 4162 // this is really a flat string in a cons string). | |
| 4163 Node* rhs = LoadObjectField(string, ConsString::kSecondOffset); | |
| 4164 Branch(WordEqual(rhs, EmptyStringConstant()), &is_flat_in_cons, &is_cons); | |
| 4165 } | |
| 4166 | |
| 4167 // Bail out to the runtime. | |
| 4168 Bind(&is_cons); | |
| 4169 { | |
| 4170 var_result.Bind( | |
| 4171 CallRuntime(Runtime::kFlattenString, NoContextConstant(), string)); | |
| 4172 Goto(&end); | |
| 4173 } | |
| 4174 | |
| 4175 Bind(&is_flat_in_cons); | |
| 4176 { | |
| 4177 var_result.Bind(LoadObjectField(string, ConsString::kFirstOffset)); | |
| 4178 Goto(&end); | |
| 4179 } | |
| 4180 | |
| 4181 Bind(&end); | |
| 4182 return var_result.value(); | |
| 4183 } | |
| 4184 | |
| 4185 Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) { | 4263 Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) { |
| 4186 Label if_isreceiver(this, Label::kDeferred), if_isnotreceiver(this); | 4264 Label if_isreceiver(this, Label::kDeferred), if_isnotreceiver(this); |
| 4187 Variable result(this, MachineRepresentation::kTagged); | 4265 Variable result(this, MachineRepresentation::kTagged); |
| 4188 Label done(this, &result); | 4266 Label done(this, &result); |
| 4189 | 4267 |
| 4190 BranchIfJSReceiver(input, &if_isreceiver, &if_isnotreceiver); | 4268 BranchIfJSReceiver(input, &if_isreceiver, &if_isnotreceiver); |
| 4191 | 4269 |
| 4192 Bind(&if_isreceiver); | 4270 Bind(&if_isreceiver); |
| 4193 { | 4271 { |
| 4194 // Convert {input} to a primitive first passing Number hint. | 4272 // Convert {input} to a primitive first passing Number hint. |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4316 variable.Bind( | 4394 variable.Bind( |
| 4317 IntPtrOrSmiAdd(variable.value(), IntPtrOrSmiConstant(value, mode), mode)); | 4395 IntPtrOrSmiAdd(variable.value(), IntPtrOrSmiConstant(value, mode), mode)); |
| 4318 } | 4396 } |
| 4319 | 4397 |
| 4320 void CodeStubAssembler::Use(Label* label) { | 4398 void CodeStubAssembler::Use(Label* label) { |
| 4321 GotoIf(Word32Equal(Int32Constant(0), Int32Constant(1)), label); | 4399 GotoIf(Word32Equal(Int32Constant(0), Int32Constant(1)), label); |
| 4322 } | 4400 } |
| 4323 | 4401 |
| 4324 void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, | 4402 void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, |
| 4325 Variable* var_index, Label* if_keyisunique, | 4403 Variable* var_index, Label* if_keyisunique, |
| 4326 Label* if_bailout) { | 4404 Variable* var_unique, Label* if_bailout) { |
| 4327 DCHECK_EQ(MachineType::PointerRepresentation(), var_index->rep()); | 4405 DCHECK_EQ(MachineType::PointerRepresentation(), var_index->rep()); |
| 4406 DCHECK_EQ(MachineRepresentation::kTagged, var_unique->rep()); | |
| 4328 Comment("TryToName"); | 4407 Comment("TryToName"); |
| 4329 | 4408 |
| 4330 Label if_hascachedindex(this), if_keyisnotindex(this); | 4409 Label if_hascachedindex(this), if_keyisnotindex(this), if_thinstring(this); |
| 4331 // Handle Smi and HeapNumber keys. | 4410 // Handle Smi and HeapNumber keys. |
| 4332 var_index->Bind(TryToIntptr(key, &if_keyisnotindex)); | 4411 var_index->Bind(TryToIntptr(key, &if_keyisnotindex)); |
| 4333 Goto(if_keyisindex); | 4412 Goto(if_keyisindex); |
| 4334 | 4413 |
| 4335 Bind(&if_keyisnotindex); | 4414 Bind(&if_keyisnotindex); |
| 4336 Node* key_map = LoadMap(key); | 4415 Node* key_map = LoadMap(key); |
| 4416 var_unique->Bind(key); | |
| 4337 // Symbols are unique. | 4417 // Symbols are unique. |
| 4338 GotoIf(IsSymbolMap(key_map), if_keyisunique); | 4418 GotoIf(IsSymbolMap(key_map), if_keyisunique); |
| 4339 Node* key_instance_type = LoadMapInstanceType(key_map); | 4419 Node* key_instance_type = LoadMapInstanceType(key_map); |
| 4340 // Miss if |key| is not a String. | 4420 // Miss if |key| is not a String. |
| 4341 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); | 4421 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE); |
| 4342 GotoUnless(IsStringInstanceType(key_instance_type), if_bailout); | 4422 GotoUnless(IsStringInstanceType(key_instance_type), if_bailout); |
| 4343 // |key| is a String. Check if it has a cached array index. | 4423 // |key| is a String. Check if it has a cached array index. |
| 4344 Node* hash = LoadNameHashField(key); | 4424 Node* hash = LoadNameHashField(key); |
| 4345 Node* contains_index = | 4425 Node* contains_index = |
| 4346 Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); | 4426 Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); |
| 4347 GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_hascachedindex); | 4427 GotoIf(Word32Equal(contains_index, Int32Constant(0)), &if_hascachedindex); |
| 4348 // No cached array index. If the string knows that it contains an index, | 4428 // No cached array index. If the string knows that it contains an index, |
| 4349 // then it must be an uncacheable index. Handle this case in the runtime. | 4429 // then it must be an uncacheable index. Handle this case in the runtime. |
| 4350 Node* not_an_index = | 4430 Node* not_an_index = |
| 4351 Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); | 4431 Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); |
| 4352 GotoIf(Word32Equal(not_an_index, Int32Constant(0)), if_bailout); | 4432 GotoIf(Word32Equal(not_an_index, Int32Constant(0)), if_bailout); |
| 4433 // Check if we have a ThinString. | |
| 4434 GotoIf(Word32Equal(key_instance_type, Int32Constant(THIN_STRING_TYPE)), | |
| 4435 &if_thinstring); | |
| 4436 GotoIf( | |
| 4437 Word32Equal(key_instance_type, Int32Constant(THIN_ONE_BYTE_STRING_TYPE)), | |
| 4438 &if_thinstring); | |
| 4353 // Finally, check if |key| is internalized. | 4439 // Finally, check if |key| is internalized. |
| 4354 STATIC_ASSERT(kNotInternalizedTag != 0); | 4440 STATIC_ASSERT(kNotInternalizedTag != 0); |
| 4355 Node* not_internalized = | 4441 Node* not_internalized = |
| 4356 Word32And(key_instance_type, Int32Constant(kIsNotInternalizedMask)); | 4442 Word32And(key_instance_type, Int32Constant(kIsNotInternalizedMask)); |
| 4357 GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)), if_bailout); | 4443 GotoIf(Word32NotEqual(not_internalized, Int32Constant(0)), if_bailout); |
| 4358 Goto(if_keyisunique); | 4444 Goto(if_keyisunique); |
| 4359 | 4445 |
| 4446 Bind(&if_thinstring); | |
| 4447 var_unique->Bind(LoadObjectField(key, ThinString::kActualOffset)); | |
| 4448 Goto(if_keyisunique); | |
| 4449 | |
| 4360 Bind(&if_hascachedindex); | 4450 Bind(&if_hascachedindex); |
| 4361 var_index->Bind(DecodeWordFromWord32<Name::ArrayIndexValueBits>(hash)); | 4451 var_index->Bind(DecodeWordFromWord32<Name::ArrayIndexValueBits>(hash)); |
| 4362 Goto(if_keyisindex); | 4452 Goto(if_keyisindex); |
| 4363 } | 4453 } |
| 4364 | 4454 |
| 4365 template <typename Dictionary> | 4455 template <typename Dictionary> |
| 4366 Node* CodeStubAssembler::EntryToIndex(Node* entry, int field_index) { | 4456 Node* CodeStubAssembler::EntryToIndex(Node* entry, int field_index) { |
| 4367 Node* entry_index = IntPtrMul(entry, IntPtrConstant(Dictionary::kEntrySize)); | 4457 Node* entry_index = IntPtrMul(entry, IntPtrConstant(Dictionary::kEntrySize)); |
| 4368 return IntPtrAdd(entry_index, IntPtrConstant(Dictionary::kElementsStartIndex + | 4458 return IntPtrAdd(entry_index, IntPtrConstant(Dictionary::kElementsStartIndex + |
| 4369 field_index)); | 4459 field_index)); |
| (...skipping 829 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5199 Label if_objectisreceiver(this); | 5289 Label if_objectisreceiver(this); |
| 5200 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | 5290 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
| 5201 STATIC_ASSERT(FIRST_JS_RECEIVER_TYPE == JS_PROXY_TYPE); | 5291 STATIC_ASSERT(FIRST_JS_RECEIVER_TYPE == JS_PROXY_TYPE); |
| 5202 Branch( | 5292 Branch( |
| 5203 Int32GreaterThan(instance_type, Int32Constant(FIRST_JS_RECEIVER_TYPE)), | 5293 Int32GreaterThan(instance_type, Int32Constant(FIRST_JS_RECEIVER_TYPE)), |
| 5204 &if_objectisreceiver, if_bailout); | 5294 &if_objectisreceiver, if_bailout); |
| 5205 Bind(&if_objectisreceiver); | 5295 Bind(&if_objectisreceiver); |
| 5206 } | 5296 } |
| 5207 | 5297 |
| 5208 Variable var_index(this, MachineType::PointerRepresentation()); | 5298 Variable var_index(this, MachineType::PointerRepresentation()); |
| 5299 Variable var_unique(this, MachineRepresentation::kTagged); | |
| 5209 | 5300 |
| 5210 Label if_keyisindex(this), if_iskeyunique(this); | 5301 Label if_keyisindex(this), if_iskeyunique(this); |
| 5211 TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, if_bailout); | 5302 TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, &var_unique, |
| 5303 if_bailout); | |
| 5212 | 5304 |
| 5213 Bind(&if_iskeyunique); | 5305 Bind(&if_iskeyunique); |
| 5214 { | 5306 { |
| 5215 Variable var_holder(this, MachineRepresentation::kTagged); | 5307 Variable var_holder(this, MachineRepresentation::kTagged); |
| 5216 Variable var_holder_map(this, MachineRepresentation::kTagged); | 5308 Variable var_holder_map(this, MachineRepresentation::kTagged); |
| 5217 Variable var_holder_instance_type(this, MachineRepresentation::kWord32); | 5309 Variable var_holder_instance_type(this, MachineRepresentation::kWord32); |
| 5218 | 5310 |
| 5219 Variable* merged_variables[] = {&var_holder, &var_holder_map, | 5311 Variable* merged_variables[] = {&var_holder, &var_holder_map, |
| 5220 &var_holder_instance_type}; | 5312 &var_holder_instance_type}; |
| 5221 Label loop(this, arraysize(merged_variables), merged_variables); | 5313 Label loop(this, arraysize(merged_variables), merged_variables); |
| 5222 var_holder.Bind(receiver); | 5314 var_holder.Bind(receiver); |
| 5223 var_holder_map.Bind(map); | 5315 var_holder_map.Bind(map); |
| 5224 var_holder_instance_type.Bind(instance_type); | 5316 var_holder_instance_type.Bind(instance_type); |
| 5225 Goto(&loop); | 5317 Goto(&loop); |
| 5226 Bind(&loop); | 5318 Bind(&loop); |
| 5227 { | 5319 { |
| 5228 Node* holder_map = var_holder_map.value(); | 5320 Node* holder_map = var_holder_map.value(); |
| 5229 Node* holder_instance_type = var_holder_instance_type.value(); | 5321 Node* holder_instance_type = var_holder_instance_type.value(); |
| 5230 | 5322 |
| 5231 Label next_proto(this); | 5323 Label next_proto(this); |
| 5232 lookup_property_in_holder(receiver, var_holder.value(), holder_map, | 5324 lookup_property_in_holder(receiver, var_holder.value(), holder_map, |
| 5233 holder_instance_type, key, &next_proto, | 5325 holder_instance_type, var_unique.value(), |
| 5234 if_bailout); | 5326 &next_proto, if_bailout); |
| 5235 Bind(&next_proto); | 5327 Bind(&next_proto); |
| 5236 | 5328 |
| 5237 // Bailout if it can be an integer indexed exotic case. | 5329 // Bailout if it can be an integer indexed exotic case. |
| 5238 GotoIf( | 5330 GotoIf( |
| 5239 Word32Equal(holder_instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)), | 5331 Word32Equal(holder_instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)), |
| 5240 if_bailout); | 5332 if_bailout); |
| 5241 | 5333 |
| 5242 Node* proto = LoadMapPrototype(holder_map); | 5334 Node* proto = LoadMapPrototype(holder_map); |
| 5243 | 5335 |
| 5244 Label if_not_null(this); | 5336 Label if_not_null(this); |
| (...skipping 3005 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8250 deferred_on_reject); | 8342 deferred_on_reject); |
| 8251 StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kDebugIdOffset, | 8343 StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kDebugIdOffset, |
| 8252 SmiConstant(kDebugPromiseNoID)); | 8344 SmiConstant(kDebugPromiseNoID)); |
| 8253 StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kContextOffset, | 8345 StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kContextOffset, |
| 8254 context); | 8346 context); |
| 8255 return result; | 8347 return result; |
| 8256 } | 8348 } |
| 8257 | 8349 |
| 8258 } // namespace internal | 8350 } // namespace internal |
| 8259 } // namespace v8 | 8351 } // namespace v8 |
| OLD | NEW |