| 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 | 4 |
| 5 #include "src/code-stub-assembler.h" | 5 #include "src/code-stub-assembler.h" |
| 6 #include "src/code-factory.h" | 6 #include "src/code-factory.h" |
| 7 #include "src/frames-inl.h" | 7 #include "src/frames-inl.h" |
| 8 #include "src/frames.h" | 8 #include "src/frames.h" |
| 9 #include "src/ic/handler-configuration.h" | 9 #include "src/ic/handler-configuration.h" |
| 10 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
| (...skipping 1332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1343 StoreObjectFieldNoWriteBarrier(result, SlicedString::kHashFieldOffset, | 1343 StoreObjectFieldNoWriteBarrier(result, SlicedString::kHashFieldOffset, |
| 1344 Int32Constant(String::kEmptyHashField), | 1344 Int32Constant(String::kEmptyHashField), |
| 1345 MachineRepresentation::kWord32); | 1345 MachineRepresentation::kWord32); |
| 1346 StoreObjectFieldNoWriteBarrier(result, SlicedString::kParentOffset, parent, | 1346 StoreObjectFieldNoWriteBarrier(result, SlicedString::kParentOffset, parent, |
| 1347 MachineRepresentation::kTagged); | 1347 MachineRepresentation::kTagged); |
| 1348 StoreObjectFieldNoWriteBarrier(result, SlicedString::kOffsetOffset, offset, | 1348 StoreObjectFieldNoWriteBarrier(result, SlicedString::kOffsetOffset, offset, |
| 1349 MachineRepresentation::kTagged); | 1349 MachineRepresentation::kTagged); |
| 1350 return result; | 1350 return result; |
| 1351 } | 1351 } |
| 1352 | 1352 |
| 1353 Node* CodeStubAssembler::AllocateOneByteConsString(Node* length, Node* first, |
| 1354 Node* second) { |
| 1355 Node* result = Allocate(ConsString::kSize); |
| 1356 Node* map = LoadRoot(Heap::kConsOneByteStringMapRootIndex); |
| 1357 StoreMapNoWriteBarrier(result, map); |
| 1358 StoreObjectFieldNoWriteBarrier(result, ConsString::kLengthOffset, length, |
| 1359 MachineRepresentation::kTagged); |
| 1360 StoreObjectFieldNoWriteBarrier(result, ConsString::kHashFieldOffset, |
| 1361 Int32Constant(String::kEmptyHashField), |
| 1362 MachineRepresentation::kWord32); |
| 1363 StoreObjectFieldNoWriteBarrier(result, ConsString::kFirstOffset, first, |
| 1364 MachineRepresentation::kTagged); |
| 1365 StoreObjectFieldNoWriteBarrier(result, ConsString::kSecondOffset, second, |
| 1366 MachineRepresentation::kTagged); |
| 1367 return result; |
| 1368 } |
| 1369 |
| 1370 Node* CodeStubAssembler::AllocateTwoByteConsString(Node* length, Node* first, |
| 1371 Node* second) { |
| 1372 Node* result = Allocate(ConsString::kSize); |
| 1373 Node* map = LoadRoot(Heap::kConsStringMapRootIndex); |
| 1374 StoreMapNoWriteBarrier(result, map); |
| 1375 StoreObjectFieldNoWriteBarrier(result, ConsString::kLengthOffset, length, |
| 1376 MachineRepresentation::kTagged); |
| 1377 StoreObjectFieldNoWriteBarrier(result, ConsString::kHashFieldOffset, |
| 1378 Int32Constant(String::kEmptyHashField), |
| 1379 MachineRepresentation::kWord32); |
| 1380 StoreObjectFieldNoWriteBarrier(result, ConsString::kFirstOffset, first, |
| 1381 MachineRepresentation::kTagged); |
| 1382 StoreObjectFieldNoWriteBarrier(result, ConsString::kSecondOffset, second, |
| 1383 MachineRepresentation::kTagged); |
| 1384 return result; |
| 1385 } |
| 1386 |
| 1353 Node* CodeStubAssembler::AllocateRegExpResult(Node* context, Node* length, | 1387 Node* CodeStubAssembler::AllocateRegExpResult(Node* context, Node* length, |
| 1354 Node* index, Node* input) { | 1388 Node* index, Node* input) { |
| 1355 Node* const max_length = | 1389 Node* const max_length = |
| 1356 SmiConstant(Smi::FromInt(JSArray::kInitialMaxFastElementArray)); | 1390 SmiConstant(Smi::FromInt(JSArray::kInitialMaxFastElementArray)); |
| 1357 Assert(SmiLessThanOrEqual(length, max_length)); | 1391 Assert(SmiLessThanOrEqual(length, max_length)); |
| 1358 | 1392 |
| 1359 // Allocate the JSRegExpResult. | 1393 // Allocate the JSRegExpResult. |
| 1360 // TODO(jgruber): Fold JSArray and FixedArray allocations, then remove | 1394 // TODO(jgruber): Fold JSArray and FixedArray allocations, then remove |
| 1361 // unneeded store of elements. | 1395 // unneeded store of elements. |
| 1362 Node* const result = Allocate(JSRegExpResult::kSize); | 1396 Node* const result = Allocate(JSRegExpResult::kSize); |
| (...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1680 } | 1714 } |
| 1681 | 1715 |
| 1682 Bind(&done); | 1716 Bind(&done); |
| 1683 IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1); | 1717 IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1); |
| 1684 Comment("] CopyFixedArrayElements"); | 1718 Comment("] CopyFixedArrayElements"); |
| 1685 } | 1719 } |
| 1686 | 1720 |
| 1687 void CodeStubAssembler::CopyStringCharacters(compiler::Node* from_string, | 1721 void CodeStubAssembler::CopyStringCharacters(compiler::Node* from_string, |
| 1688 compiler::Node* to_string, | 1722 compiler::Node* to_string, |
| 1689 compiler::Node* from_index, | 1723 compiler::Node* from_index, |
| 1724 compiler::Node* to_index, |
| 1690 compiler::Node* character_count, | 1725 compiler::Node* character_count, |
| 1691 String::Encoding encoding) { | 1726 String::Encoding encoding) { |
| 1692 Label out(this); | 1727 Label out(this); |
| 1693 | 1728 |
| 1694 // Nothing to do for zero characters. | 1729 // Nothing to do for zero characters. |
| 1695 | 1730 |
| 1696 GotoIf(SmiLessThanOrEqual(character_count, SmiConstant(Smi::kZero)), &out); | 1731 GotoIf(SmiLessThanOrEqual(character_count, SmiConstant(Smi::kZero)), &out); |
| 1697 | 1732 |
| 1698 // Calculate offsets into the strings. | 1733 // Calculate offsets into the strings. |
| 1699 | 1734 |
| 1700 Node* from_offset; | 1735 Node* from_offset; |
| 1701 Node* limit_offset; | 1736 Node* limit_offset; |
| 1702 Node* to_offset; | 1737 Node* to_offset; |
| 1703 | 1738 |
| 1704 { | 1739 { |
| 1705 Node* byte_count = SmiUntag(character_count); | 1740 Node* byte_count = SmiUntag(character_count); |
| 1706 Node* from_byte_index = SmiUntag(from_index); | 1741 Node* from_byte_index = SmiUntag(from_index); |
| 1742 Node* to_byte_index = SmiUntag(to_index); |
| 1707 if (encoding == String::ONE_BYTE_ENCODING) { | 1743 if (encoding == String::ONE_BYTE_ENCODING) { |
| 1708 const int offset = SeqOneByteString::kHeaderSize - kHeapObjectTag; | 1744 const int offset = SeqOneByteString::kHeaderSize - kHeapObjectTag; |
| 1709 from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); | 1745 from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); |
| 1710 limit_offset = IntPtrAdd(from_offset, byte_count); | 1746 limit_offset = IntPtrAdd(from_offset, byte_count); |
| 1711 to_offset = IntPtrConstant(offset); | 1747 to_offset = IntPtrAdd(IntPtrConstant(offset), to_byte_index); |
| 1712 } else { | 1748 } else { |
| 1713 STATIC_ASSERT(2 == sizeof(uc16)); | 1749 STATIC_ASSERT(2 == sizeof(uc16)); |
| 1714 byte_count = WordShl(byte_count, 1); | 1750 byte_count = WordShl(byte_count, 1); |
| 1715 from_byte_index = WordShl(from_byte_index, 1); | 1751 from_byte_index = WordShl(from_byte_index, 1); |
| 1752 to_byte_index = WordShl(to_byte_index, 1); |
| 1716 | 1753 |
| 1717 const int offset = SeqTwoByteString::kHeaderSize - kHeapObjectTag; | 1754 const int offset = SeqTwoByteString::kHeaderSize - kHeapObjectTag; |
| 1718 from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); | 1755 from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); |
| 1719 limit_offset = IntPtrAdd(from_offset, byte_count); | 1756 limit_offset = IntPtrAdd(from_offset, byte_count); |
| 1720 to_offset = IntPtrConstant(offset); | 1757 to_offset = IntPtrAdd(IntPtrConstant(offset), to_byte_index); |
| 1721 } | 1758 } |
| 1722 } | 1759 } |
| 1723 | 1760 |
| 1724 Variable var_from_offset(this, MachineType::PointerRepresentation()); | 1761 Variable var_from_offset(this, MachineType::PointerRepresentation()); |
| 1725 Variable var_to_offset(this, MachineType::PointerRepresentation()); | 1762 Variable var_to_offset(this, MachineType::PointerRepresentation()); |
| 1726 | 1763 |
| 1727 var_from_offset.Bind(from_offset); | 1764 var_from_offset.Bind(from_offset); |
| 1728 var_to_offset.Bind(to_offset); | 1765 var_to_offset.Bind(to_offset); |
| 1729 | 1766 |
| 1730 Variable* vars[] = {&var_from_offset, &var_to_offset}; | 1767 Variable* vars[] = {&var_from_offset, &var_to_offset}; |
| (...skipping 777 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2508 // 0 <= |from_index| <= |from_index| + |character_count| < from_string.length. | 2545 // 0 <= |from_index| <= |from_index| + |character_count| < from_string.length. |
| 2509 Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context, | 2546 Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context, |
| 2510 Node* from, Node* from_instance_type, | 2547 Node* from, Node* from_instance_type, |
| 2511 Node* from_index, Node* character_count) { | 2548 Node* from_index, Node* character_count) { |
| 2512 typedef CodeStubAssembler::Label Label; | 2549 typedef CodeStubAssembler::Label Label; |
| 2513 typedef CodeStubAssembler::Variable Variable; | 2550 typedef CodeStubAssembler::Variable Variable; |
| 2514 | 2551 |
| 2515 Label end(a), two_byte_sequential(a); | 2552 Label end(a), two_byte_sequential(a); |
| 2516 Variable var_result(a, MachineRepresentation::kTagged); | 2553 Variable var_result(a, MachineRepresentation::kTagged); |
| 2517 | 2554 |
| 2555 Node* const smi_zero = a->SmiConstant(Smi::kZero); |
| 2556 |
| 2518 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); | 2557 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); |
| 2519 a->GotoIf(a->Word32Equal(a->Word32And(from_instance_type, | 2558 a->GotoIf(a->Word32Equal(a->Word32And(from_instance_type, |
| 2520 a->Int32Constant(kStringEncodingMask)), | 2559 a->Int32Constant(kStringEncodingMask)), |
| 2521 a->Int32Constant(0)), | 2560 a->Int32Constant(0)), |
| 2522 &two_byte_sequential); | 2561 &two_byte_sequential); |
| 2523 | 2562 |
| 2524 // The subject string is a sequential one-byte string. | 2563 // The subject string is a sequential one-byte string. |
| 2525 { | 2564 { |
| 2526 Node* result = | 2565 Node* result = |
| 2527 a->AllocateSeqOneByteString(context, a->SmiToWord(character_count)); | 2566 a->AllocateSeqOneByteString(context, a->SmiToWord(character_count)); |
| 2528 a->CopyStringCharacters(from, result, from_index, character_count, | 2567 a->CopyStringCharacters(from, result, from_index, smi_zero, character_count, |
| 2529 String::ONE_BYTE_ENCODING); | 2568 String::ONE_BYTE_ENCODING); |
| 2530 var_result.Bind(result); | 2569 var_result.Bind(result); |
| 2531 | 2570 |
| 2532 a->Goto(&end); | 2571 a->Goto(&end); |
| 2533 } | 2572 } |
| 2534 | 2573 |
| 2535 // The subject string is a sequential two-byte string. | 2574 // The subject string is a sequential two-byte string. |
| 2536 a->Bind(&two_byte_sequential); | 2575 a->Bind(&two_byte_sequential); |
| 2537 { | 2576 { |
| 2538 Node* result = | 2577 Node* result = |
| 2539 a->AllocateSeqTwoByteString(context, a->SmiToWord(character_count)); | 2578 a->AllocateSeqTwoByteString(context, a->SmiToWord(character_count)); |
| 2540 a->CopyStringCharacters(from, result, from_index, character_count, | 2579 a->CopyStringCharacters(from, result, from_index, smi_zero, character_count, |
| 2541 String::TWO_BYTE_ENCODING); | 2580 String::TWO_BYTE_ENCODING); |
| 2542 var_result.Bind(result); | 2581 var_result.Bind(result); |
| 2543 | 2582 |
| 2544 a->Goto(&end); | 2583 a->Goto(&end); |
| 2545 } | 2584 } |
| 2546 | 2585 |
| 2547 a->Bind(&end); | 2586 a->Bind(&end); |
| 2548 return var_result.value(); | 2587 return var_result.value(); |
| 2549 } | 2588 } |
| 2550 | 2589 |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2765 { | 2804 { |
| 2766 var_result.Bind( | 2805 var_result.Bind( |
| 2767 CallRuntime(Runtime::kSubString, context, string, from, to)); | 2806 CallRuntime(Runtime::kSubString, context, string, from, to)); |
| 2768 Goto(&end); | 2807 Goto(&end); |
| 2769 } | 2808 } |
| 2770 | 2809 |
| 2771 Bind(&end); | 2810 Bind(&end); |
| 2772 return var_result.value(); | 2811 return var_result.value(); |
| 2773 } | 2812 } |
| 2774 | 2813 |
| 2814 Node* CodeStubAssembler::StringConcat(Node* context, Node* first, |
| 2815 Node* second) { |
| 2816 Variable var_result(this, MachineRepresentation::kTagged); |
| 2817 |
| 2818 Label out(this), runtime(this, Label::kDeferred); |
| 2819 |
| 2820 // TODO(jgruber): Handle indirect, external, and two-byte strings. |
| 2821 |
| 2822 Node* const one_byte_seq_mask = Int32Constant( |
| 2823 kIsIndirectStringMask | kExternalStringTag | kStringEncodingMask); |
| 2824 Node* const expected_masked = Int32Constant(kOneByteStringTag); |
| 2825 |
| 2826 Node* const first_instance_type = LoadInstanceType(first); |
| 2827 GotoUnless(Word32Equal(Word32And(first_instance_type, one_byte_seq_mask), |
| 2828 expected_masked), |
| 2829 &runtime); |
| 2830 |
| 2831 Node* const second_instance_type = LoadInstanceType(second); |
| 2832 GotoUnless(Word32Equal(Word32And(second_instance_type, one_byte_seq_mask), |
| 2833 expected_masked), |
| 2834 &runtime); |
| 2835 |
| 2836 Node* const smi_zero = SmiConstant(Smi::kZero); |
| 2837 Node* const first_length = LoadStringLength(first); |
| 2838 Node* const second_length = LoadStringLength(second); |
| 2839 Node* const length = SmiAdd(first_length, second_length); |
| 2840 |
| 2841 Label if_makeseqstring(this), if_makeconsstring(this); |
| 2842 Node* const min_cons_length = |
| 2843 SmiConstant(Smi::FromInt(ConsString::kMinLength)); |
| 2844 Branch(SmiLessThan(length, min_cons_length), &if_makeseqstring, |
| 2845 &if_makeconsstring); |
| 2846 |
| 2847 Bind(&if_makeseqstring); |
| 2848 { |
| 2849 Node* result = AllocateSeqOneByteString(context, SmiToWord(length)); |
| 2850 |
| 2851 CopyStringCharacters(first, result, smi_zero, smi_zero, first_length, |
| 2852 String::ONE_BYTE_ENCODING); |
| 2853 CopyStringCharacters(second, result, smi_zero, first_length, second_length, |
| 2854 String::ONE_BYTE_ENCODING); |
| 2855 |
| 2856 var_result.Bind(result); |
| 2857 Goto(&out); |
| 2858 } |
| 2859 |
| 2860 Bind(&if_makeconsstring); |
| 2861 { |
| 2862 Node* result = AllocateOneByteConsString(length, first, second); |
| 2863 var_result.Bind(result); |
| 2864 Goto(&out); |
| 2865 } |
| 2866 |
| 2867 Bind(&runtime); |
| 2868 { |
| 2869 Node* const result = |
| 2870 CallRuntime(Runtime::kStringAdd, context, first, second); |
| 2871 var_result.Bind(result); |
| 2872 Goto(&out); |
| 2873 } |
| 2874 |
| 2875 Bind(&out); |
| 2876 return var_result.value(); |
| 2877 } |
| 2878 |
| 2879 Node* CodeStubAssembler::StringIndexOfChar(Node* context, Node* string, |
| 2880 Node* needle_char, Node* from) { |
| 2881 Variable var_result(this, MachineRepresentation::kTagged); |
| 2882 |
| 2883 Label out(this), runtime(this, Label::kDeferred); |
| 2884 |
| 2885 // Let runtime handle non-one-byte {needle_char}. |
| 2886 |
| 2887 Node* const one_byte_char_mask = IntPtrConstant(0xFF); |
| 2888 GotoUnless(WordEqual(WordAnd(needle_char, one_byte_char_mask), needle_char), |
| 2889 &runtime); |
| 2890 |
| 2891 // TODO(jgruber): Handle external and two-byte strings. |
| 2892 |
| 2893 Node* const one_byte_seq_mask = Int32Constant( |
| 2894 kIsIndirectStringMask | kExternalStringTag | kStringEncodingMask); |
| 2895 Node* const expected_masked = Int32Constant(kOneByteStringTag); |
| 2896 |
| 2897 Node* const string_instance_type = LoadInstanceType(string); |
| 2898 GotoUnless(Word32Equal(Word32And(string_instance_type, one_byte_seq_mask), |
| 2899 expected_masked), |
| 2900 &runtime); |
| 2901 |
| 2902 // If we reach this, {string} is a non-indirect, non-external one-byte string. |
| 2903 |
| 2904 Node* const length = LoadStringLength(string); |
| 2905 Node* const search_range_length = SmiUntag(SmiSub(length, from)); |
| 2906 |
| 2907 const int offset = SeqOneByteString::kHeaderSize - kHeapObjectTag; |
| 2908 Node* const begin = IntPtrConstant(offset); |
| 2909 Node* const cursor = IntPtrAdd(begin, SmiUntag(from)); |
| 2910 Node* const end = IntPtrAdd(cursor, search_range_length); |
| 2911 |
| 2912 Variable var_cursor(this, MachineType::PointerRepresentation()); |
| 2913 Variable* vars[] = {&var_cursor}; |
| 2914 Label loop(this, 1, vars), loop_tail(this); |
| 2915 |
| 2916 var_cursor.Bind(cursor); |
| 2917 var_result.Bind(SmiConstant(Smi::FromInt(-1))); |
| 2918 |
| 2919 Goto(&loop); |
| 2920 Bind(&loop); |
| 2921 { |
| 2922 Node* const cursor = var_cursor.value(); |
| 2923 |
| 2924 Node* value = Load(MachineType::Uint8(), string, cursor); |
| 2925 GotoUnless(WordEqual(value, needle_char), &loop_tail); |
| 2926 |
| 2927 // Found a match. |
| 2928 Node* index = SmiTag(IntPtrSub(cursor, begin)); |
| 2929 var_result.Bind(index); |
| 2930 Goto(&out); |
| 2931 |
| 2932 Bind(&loop_tail); |
| 2933 { |
| 2934 Node* const new_cursor = IntPtrAdd(cursor, IntPtrConstant(1)); |
| 2935 var_cursor.Bind(new_cursor); |
| 2936 Branch(IntPtrLessThan(new_cursor, end), &loop, &out); |
| 2937 } |
| 2938 } |
| 2939 |
| 2940 Bind(&runtime); |
| 2941 { |
| 2942 Node* const pattern = StringFromCharCode(needle_char); |
| 2943 Node* const result = |
| 2944 CallRuntime(Runtime::kStringIndexOf, context, string, pattern, from); |
| 2945 var_result.Bind(result); |
| 2946 var_cursor.Bind(IntPtrConstant(0)); |
| 2947 Goto(&out); |
| 2948 } |
| 2949 |
| 2950 Bind(&out); |
| 2951 return var_result.value(); |
| 2952 } |
| 2953 |
| 2775 Node* CodeStubAssembler::StringFromCodePoint(compiler::Node* codepoint, | 2954 Node* CodeStubAssembler::StringFromCodePoint(compiler::Node* codepoint, |
| 2776 UnicodeEncoding encoding) { | 2955 UnicodeEncoding encoding) { |
| 2777 Variable var_result(this, MachineRepresentation::kTagged); | 2956 Variable var_result(this, MachineRepresentation::kTagged); |
| 2778 var_result.Bind(EmptyStringConstant()); | 2957 var_result.Bind(EmptyStringConstant()); |
| 2779 | 2958 |
| 2780 Label if_isword16(this), if_isword32(this), return_result(this); | 2959 Label if_isword16(this), if_isword32(this), return_result(this); |
| 2781 | 2960 |
| 2782 Branch(Uint32LessThan(codepoint, Int32Constant(0x10000)), &if_isword16, | 2961 Branch(Uint32LessThan(codepoint, Int32Constant(0x10000)), &if_isword16, |
| 2783 &if_isword32); | 2962 &if_isword32); |
| 2784 | 2963 |
| (...skipping 4452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7237 result.Bind(CallRuntime(Runtime::kInstanceOf, context, object, callable)); | 7416 result.Bind(CallRuntime(Runtime::kInstanceOf, context, object, callable)); |
| 7238 Goto(&end); | 7417 Goto(&end); |
| 7239 } | 7418 } |
| 7240 | 7419 |
| 7241 Bind(&end); | 7420 Bind(&end); |
| 7242 return result.value(); | 7421 return result.value(); |
| 7243 } | 7422 } |
| 7244 | 7423 |
| 7245 } // namespace internal | 7424 } // namespace internal |
| 7246 } // namespace v8 | 7425 } // namespace v8 |
| OLD | NEW |