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 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 } | 330 } |
331 | 331 |
332 Node* CodeStubAssembler::SmiSub(Node* a, Node* b) { return IntPtrSub(a, b); } | 332 Node* CodeStubAssembler::SmiSub(Node* a, Node* b) { return IntPtrSub(a, b); } |
333 | 333 |
334 Node* CodeStubAssembler::SmiSubWithOverflow(Node* a, Node* b) { | 334 Node* CodeStubAssembler::SmiSubWithOverflow(Node* a, Node* b) { |
335 return IntPtrSubWithOverflow(a, b); | 335 return IntPtrSubWithOverflow(a, b); |
336 } | 336 } |
337 | 337 |
338 Node* CodeStubAssembler::SmiEqual(Node* a, Node* b) { return WordEqual(a, b); } | 338 Node* CodeStubAssembler::SmiEqual(Node* a, Node* b) { return WordEqual(a, b); } |
339 | 339 |
340 Node* CodeStubAssembler::SmiAbove(Node* a, Node* b) { | |
341 return UintPtrGreaterThan(a, b); | |
342 } | |
343 | |
344 Node* CodeStubAssembler::SmiAboveOrEqual(Node* a, Node* b) { | 340 Node* CodeStubAssembler::SmiAboveOrEqual(Node* a, Node* b) { |
345 return UintPtrGreaterThanOrEqual(a, b); | 341 return UintPtrGreaterThanOrEqual(a, b); |
346 } | 342 } |
347 | 343 |
348 Node* CodeStubAssembler::SmiBelow(Node* a, Node* b) { | |
349 return UintPtrLessThan(a, b); | |
350 } | |
351 | |
352 Node* CodeStubAssembler::SmiLessThan(Node* a, Node* b) { | 344 Node* CodeStubAssembler::SmiLessThan(Node* a, Node* b) { |
353 return IntPtrLessThan(a, b); | 345 return IntPtrLessThan(a, b); |
354 } | 346 } |
355 | 347 |
356 Node* CodeStubAssembler::SmiLessThanOrEqual(Node* a, Node* b) { | 348 Node* CodeStubAssembler::SmiLessThanOrEqual(Node* a, Node* b) { |
357 return IntPtrLessThanOrEqual(a, b); | 349 return IntPtrLessThanOrEqual(a, b); |
358 } | 350 } |
359 | 351 |
360 Node* CodeStubAssembler::SmiMin(Node* a, Node* b) { | 352 Node* CodeStubAssembler::SmiMin(Node* a, Node* b) { |
361 // TODO(bmeurer): Consider using Select once available. | 353 // TODO(bmeurer): Consider using Select once available. |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 | 490 |
499 Node* CodeStubAssembler::WordIsSmi(Node* a) { | 491 Node* CodeStubAssembler::WordIsSmi(Node* a) { |
500 return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask)), IntPtrConstant(0)); | 492 return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask)), IntPtrConstant(0)); |
501 } | 493 } |
502 | 494 |
503 Node* CodeStubAssembler::WordIsPositiveSmi(Node* a) { | 495 Node* CodeStubAssembler::WordIsPositiveSmi(Node* a) { |
504 return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask | kSmiSignMask)), | 496 return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask | kSmiSignMask)), |
505 IntPtrConstant(0)); | 497 IntPtrConstant(0)); |
506 } | 498 } |
507 | 499 |
508 Node* CodeStubAssembler::WordIsNotPositiveSmi(Node* a) { | |
509 return WordNotEqual(WordAnd(a, IntPtrConstant(kSmiTagMask | kSmiSignMask)), | |
510 IntPtrConstant(0)); | |
511 } | |
512 | |
513 void CodeStubAssembler::BranchIfSameValueZero(Node* a, Node* b, Node* context, | 500 void CodeStubAssembler::BranchIfSameValueZero(Node* a, Node* b, Node* context, |
514 Label* if_true, Label* if_false) { | 501 Label* if_true, Label* if_false) { |
515 Node* number_map = HeapNumberMapConstant(); | 502 Node* number_map = HeapNumberMapConstant(); |
516 Label a_isnumber(this), a_isnotnumber(this), b_isnumber(this), a_isnan(this), | 503 Label a_isnumber(this), a_isnotnumber(this), b_isnumber(this), a_isnan(this), |
517 float_not_equal(this); | 504 float_not_equal(this); |
518 // If register A and register B are identical, goto `if_true` | 505 // If register A and register B are identical, goto `if_true` |
519 GotoIf(WordEqual(a, b), if_true); | 506 GotoIf(WordEqual(a, b), if_true); |
520 // If either register A or B are Smis, goto `if_false` | 507 // If either register A or B are Smis, goto `if_false` |
521 GotoIf(Word32Or(WordIsSmi(a), WordIsSmi(b)), if_false); | 508 GotoIf(Word32Or(WordIsSmi(a), WordIsSmi(b)), if_false); |
522 // GotoIf(WordIsSmi(b), if_false); | 509 // GotoIf(WordIsSmi(b), if_false); |
(...skipping 865 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1388 Node* result = CallRuntime(Runtime::kAllocateSeqTwoByteString, context, | 1375 Node* result = CallRuntime(Runtime::kAllocateSeqTwoByteString, context, |
1389 SmiFromWord(length)); | 1376 SmiFromWord(length)); |
1390 var_result.Bind(result); | 1377 var_result.Bind(result); |
1391 Goto(&if_join); | 1378 Goto(&if_join); |
1392 } | 1379 } |
1393 | 1380 |
1394 Bind(&if_join); | 1381 Bind(&if_join); |
1395 return var_result.value(); | 1382 return var_result.value(); |
1396 } | 1383 } |
1397 | 1384 |
1398 Node* CodeStubAssembler::AllocateSlicedOneByteString(Node* length, Node* parent, | |
1399 Node* offset) { | |
1400 Node* result = Allocate(SlicedString::kSize); | |
1401 Node* map = LoadRoot(Heap::kSlicedOneByteStringMapRootIndex); | |
1402 StoreMapNoWriteBarrier(result, map); | |
1403 StoreObjectFieldNoWriteBarrier(result, SlicedString::kLengthOffset, length, | |
1404 MachineRepresentation::kTagged); | |
1405 StoreObjectFieldNoWriteBarrier(result, SlicedString::kHashFieldOffset, | |
1406 Int32Constant(String::kEmptyHashField), | |
1407 MachineRepresentation::kWord32); | |
1408 StoreObjectFieldNoWriteBarrier(result, SlicedString::kParentOffset, parent, | |
1409 MachineRepresentation::kTagged); | |
1410 StoreObjectFieldNoWriteBarrier(result, SlicedString::kOffsetOffset, offset, | |
1411 MachineRepresentation::kTagged); | |
1412 return result; | |
1413 } | |
1414 | |
1415 Node* CodeStubAssembler::AllocateSlicedTwoByteString(Node* length, Node* parent, | |
1416 Node* offset) { | |
1417 Node* result = Allocate(SlicedString::kSize); | |
1418 Node* map = LoadRoot(Heap::kSlicedStringMapRootIndex); | |
1419 StoreMapNoWriteBarrier(result, map); | |
1420 StoreObjectFieldNoWriteBarrier(result, SlicedString::kLengthOffset, length, | |
1421 MachineRepresentation::kTagged); | |
1422 StoreObjectFieldNoWriteBarrier(result, SlicedString::kHashFieldOffset, | |
1423 Int32Constant(String::kEmptyHashField), | |
1424 MachineRepresentation::kWord32); | |
1425 StoreObjectFieldNoWriteBarrier(result, SlicedString::kParentOffset, parent, | |
1426 MachineRepresentation::kTagged); | |
1427 StoreObjectFieldNoWriteBarrier(result, SlicedString::kOffsetOffset, offset, | |
1428 MachineRepresentation::kTagged); | |
1429 return result; | |
1430 } | |
1431 | |
1432 Node* CodeStubAssembler::AllocateUninitializedJSArrayWithoutElements( | 1385 Node* CodeStubAssembler::AllocateUninitializedJSArrayWithoutElements( |
1433 ElementsKind kind, Node* array_map, Node* length, Node* allocation_site) { | 1386 ElementsKind kind, Node* array_map, Node* length, Node* allocation_site) { |
1434 Comment("begin allocation of JSArray without elements"); | 1387 Comment("begin allocation of JSArray without elements"); |
1435 int base_size = JSArray::kSize; | 1388 int base_size = JSArray::kSize; |
| 1389 |
1436 if (allocation_site != nullptr) { | 1390 if (allocation_site != nullptr) { |
1437 base_size += AllocationMemento::kSize; | 1391 base_size += AllocationMemento::kSize; |
1438 } | 1392 } |
1439 | 1393 |
1440 Node* size = IntPtrConstant(base_size); | 1394 Node* size = IntPtrConstant(base_size); |
1441 Node* array = AllocateUninitializedJSArray(kind, array_map, length, | 1395 Node* array = AllocateUninitializedJSArray(kind, array_map, length, |
1442 allocation_site, size); | 1396 allocation_site, size); |
1443 return array; | 1397 return array; |
1444 } | 1398 } |
1445 | 1399 |
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1758 Bind(&next_iter); | 1712 Bind(&next_iter); |
1759 Node* compare = WordNotEqual(from_offset, limit_offset); | 1713 Node* compare = WordNotEqual(from_offset, limit_offset); |
1760 Branch(compare, &decrement, &done); | 1714 Branch(compare, &decrement, &done); |
1761 } | 1715 } |
1762 | 1716 |
1763 Bind(&done); | 1717 Bind(&done); |
1764 IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1); | 1718 IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1); |
1765 Comment("] CopyFixedArrayElements"); | 1719 Comment("] CopyFixedArrayElements"); |
1766 } | 1720 } |
1767 | 1721 |
1768 void CodeStubAssembler::CopyStringCharacters(compiler::Node* from_string, | |
1769 compiler::Node* to_string, | |
1770 compiler::Node* from_index, | |
1771 compiler::Node* character_count, | |
1772 String::Encoding encoding) { | |
1773 Label out(this); | |
1774 | |
1775 // Nothing to do for zero characters. | |
1776 | |
1777 GotoIf(SmiLessThanOrEqual(character_count, SmiConstant(Smi::FromInt(0))), | |
1778 &out); | |
1779 | |
1780 // Calculate offsets into the strings. | |
1781 | |
1782 Node* from_offset; | |
1783 Node* limit_offset; | |
1784 Node* to_offset; | |
1785 | |
1786 { | |
1787 Node* byte_count = SmiToWord32(character_count); | |
1788 Node* from_byte_index = SmiToWord32(from_index); | |
1789 if (encoding == String::ONE_BYTE_ENCODING) { | |
1790 const int offset = SeqOneByteString::kHeaderSize - kHeapObjectTag; | |
1791 from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); | |
1792 limit_offset = IntPtrAdd(from_offset, byte_count); | |
1793 to_offset = IntPtrConstant(offset); | |
1794 } else { | |
1795 STATIC_ASSERT(2 == sizeof(uc16)); | |
1796 byte_count = WordShl(byte_count, 1); | |
1797 from_byte_index = WordShl(from_byte_index, 1); | |
1798 | |
1799 const int offset = SeqTwoByteString::kHeaderSize - kHeapObjectTag; | |
1800 from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); | |
1801 limit_offset = IntPtrAdd(from_offset, byte_count); | |
1802 to_offset = IntPtrConstant(offset); | |
1803 } | |
1804 } | |
1805 | |
1806 Variable var_from_offset(this, MachineType::PointerRepresentation()); | |
1807 Variable var_to_offset(this, MachineType::PointerRepresentation()); | |
1808 | |
1809 var_from_offset.Bind(from_offset); | |
1810 var_to_offset.Bind(to_offset); | |
1811 | |
1812 Variable* vars[] = {&var_from_offset, &var_to_offset}; | |
1813 Label decrement(this, 2, vars); | |
1814 | |
1815 Label loop(this, 2, vars); | |
1816 Goto(&loop); | |
1817 Bind(&loop); | |
1818 { | |
1819 from_offset = var_from_offset.value(); | |
1820 to_offset = var_to_offset.value(); | |
1821 | |
1822 // TODO(jgruber): We could make this faster through larger copy unit sizes. | |
1823 Node* value = Load(MachineType::Uint8(), from_string, from_offset); | |
1824 StoreNoWriteBarrier(MachineRepresentation::kWord8, to_string, to_offset, | |
1825 value); | |
1826 | |
1827 Node* new_from_offset = IntPtrAdd(from_offset, IntPtrConstant(1)); | |
1828 var_from_offset.Bind(new_from_offset); | |
1829 var_to_offset.Bind(IntPtrAdd(to_offset, IntPtrConstant(1))); | |
1830 | |
1831 Branch(WordNotEqual(new_from_offset, limit_offset), &loop, &out); | |
1832 } | |
1833 | |
1834 Bind(&out); | |
1835 } | |
1836 | |
1837 Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, | 1722 Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, |
1838 Node* offset, | 1723 Node* offset, |
1839 ElementsKind from_kind, | 1724 ElementsKind from_kind, |
1840 ElementsKind to_kind, | 1725 ElementsKind to_kind, |
1841 Label* if_hole) { | 1726 Label* if_hole) { |
1842 if (IsFastDoubleElementsKind(from_kind)) { | 1727 if (IsFastDoubleElementsKind(from_kind)) { |
1843 Node* value = | 1728 Node* value = |
1844 LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64()); | 1729 LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64()); |
1845 if (!IsFastDoubleElementsKind(to_kind)) { | 1730 if (!IsFastDoubleElementsKind(to_kind)) { |
1846 value = AllocateHeapNumberWithValue(value); | 1731 value = AllocateHeapNumberWithValue(value); |
(...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2537 MachineRepresentation::kWord16, result, | 2422 MachineRepresentation::kWord16, result, |
2538 IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), code); | 2423 IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), code); |
2539 var_result.Bind(result); | 2424 var_result.Bind(result); |
2540 Goto(&if_done); | 2425 Goto(&if_done); |
2541 } | 2426 } |
2542 | 2427 |
2543 Bind(&if_done); | 2428 Bind(&if_done); |
2544 return var_result.value(); | 2429 return var_result.value(); |
2545 } | 2430 } |
2546 | 2431 |
2547 Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, | |
2548 Node* to) { | |
2549 Label end(this); | |
2550 Label runtime(this); | |
2551 | |
2552 Variable var_instance_type(this, MachineRepresentation::kWord8); // Int32. | |
2553 Variable var_result(this, MachineRepresentation::kTagged); // String. | |
2554 Variable var_from(this, MachineRepresentation::kTagged); // Smi. | |
2555 Variable var_string(this, MachineRepresentation::kTagged); // String. | |
2556 | |
2557 var_instance_type.Bind(Int32Constant(0)); | |
2558 var_string.Bind(string); | |
2559 var_from.Bind(from); | |
2560 | |
2561 // Make sure first argument is a string. | |
2562 | |
2563 // Bailout if receiver is a Smi. | |
2564 GotoIf(WordIsSmi(string), &runtime); | |
2565 | |
2566 // Load the instance type of the {string}. | |
2567 Node* const instance_type = LoadInstanceType(string); | |
2568 var_instance_type.Bind(instance_type); | |
2569 | |
2570 // Check if {string} is a String. | |
2571 GotoIf(Int32GreaterThanOrEqual(instance_type, | |
2572 Int32Constant(FIRST_NONSTRING_TYPE)), | |
2573 &runtime); | |
2574 | |
2575 // Make sure that both from and to are non-negative smis. | |
2576 | |
2577 GotoIf(WordIsNotPositiveSmi(from), &runtime); | |
2578 GotoIf(WordIsNotPositiveSmi(to), &runtime); | |
2579 | |
2580 Node* const substr_length = SmiSub(to, from); | |
2581 Node* const string_length = LoadStringLength(string); | |
2582 | |
2583 // Begin dispatching based on substring length. | |
2584 | |
2585 Label original_string_or_invalid_length(this); | |
2586 GotoIf(SmiAboveOrEqual(substr_length, string_length), | |
2587 &original_string_or_invalid_length); | |
2588 | |
2589 // A real substring (substr_length < string_length). | |
2590 | |
2591 Label single_char(this); | |
2592 GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char); | |
2593 | |
2594 // TODO(jgruber): Add an additional case for substring of length == 0? | |
2595 | |
2596 // Deal with different string types: update the index if necessary | |
2597 // and put the underlying string into var_string. | |
2598 | |
2599 // If the string is not indirect, it can only be sequential or external. | |
2600 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); | |
2601 STATIC_ASSERT(kIsIndirectStringMask != 0); | |
2602 Label underlying_unpacked(this); | |
2603 GotoIf(Word32Equal( | |
2604 Word32And(instance_type, Int32Constant(kIsIndirectStringMask)), | |
2605 Int32Constant(0)), | |
2606 &underlying_unpacked); | |
2607 | |
2608 // The subject string is either a sliced or cons string. | |
2609 | |
2610 Label sliced_string(this); | |
2611 GotoIf(Word32NotEqual( | |
2612 Word32And(instance_type, Int32Constant(kSlicedNotConsMask)), | |
2613 Int32Constant(0)), | |
2614 &sliced_string); | |
2615 | |
2616 // Cons string. Check whether it is flat, then fetch first part. | |
2617 // Flat cons strings have an empty second part. | |
2618 { | |
2619 GotoIf(WordNotEqual(LoadObjectField(string, ConsString::kSecondOffset), | |
2620 EmptyStringConstant()), | |
2621 &runtime); | |
2622 | |
2623 Node* first_string_part = LoadObjectField(string, ConsString::kFirstOffset); | |
2624 var_string.Bind(first_string_part); | |
2625 var_instance_type.Bind(LoadInstanceType(first_string_part)); | |
2626 | |
2627 Goto(&underlying_unpacked); | |
2628 } | |
2629 | |
2630 Bind(&sliced_string); | |
2631 { | |
2632 // Fetch parent and correct start index by offset. | |
2633 Node* sliced_offset = LoadObjectField(string, SlicedString::kOffsetOffset); | |
2634 var_from.Bind(SmiAdd(from, sliced_offset)); | |
2635 | |
2636 Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); | |
2637 var_string.Bind(slice_parent); | |
2638 | |
2639 Node* slice_parent_instance_type = LoadInstanceType(slice_parent); | |
2640 var_instance_type.Bind(slice_parent_instance_type); | |
2641 | |
2642 Goto(&underlying_unpacked); | |
2643 } | |
2644 | |
2645 // The subject string can only be external or sequential string of either | |
2646 // encoding at this point. | |
2647 Bind(&underlying_unpacked); | |
2648 | |
2649 if (FLAG_string_slices) { | |
2650 Label copy_routine(this); | |
2651 | |
2652 // Short slice. Copy instead of slicing. | |
2653 GotoIf(SmiLessThan(substr_length, | |
2654 SmiConstant(Smi::FromInt(SlicedString::kMinLength))), | |
2655 ©_routine); | |
2656 | |
2657 // Allocate new sliced string. | |
2658 | |
2659 Label two_byte_slice(this); | |
2660 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | |
2661 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | |
2662 | |
2663 Counters* counters = isolate()->counters(); | |
2664 IncrementCounter(counters->sub_string_native(), 1); | |
2665 | |
2666 GotoIf(Word32Equal(Word32And(var_instance_type.value(), | |
2667 Int32Constant(kStringEncodingMask)), | |
2668 Int32Constant(0)), | |
2669 &two_byte_slice); | |
2670 | |
2671 var_result.Bind(AllocateSlicedOneByteString( | |
2672 substr_length, var_string.value(), var_from.value())); | |
2673 Goto(&end); | |
2674 | |
2675 Bind(&two_byte_slice); | |
2676 | |
2677 var_result.Bind(AllocateSlicedTwoByteString( | |
2678 substr_length, var_string.value(), var_from.value())); | |
2679 Goto(&end); | |
2680 | |
2681 Bind(©_routine); | |
2682 } | |
2683 | |
2684 // The subject string can only be external or sequential string of either | |
2685 // encoding at this point. | |
2686 STATIC_ASSERT(kExternalStringTag != 0); | |
2687 STATIC_ASSERT(kSeqStringTag == 0); | |
2688 Label sequential_string(this); | |
2689 GotoIf(Word32Equal(Word32And(var_instance_type.value(), | |
2690 Int32Constant(kExternalStringTag)), | |
2691 Int32Constant(0)), | |
2692 &sequential_string); | |
2693 | |
2694 // Handle external string. | |
2695 { | |
2696 // Rule out short external strings. | |
2697 STATIC_ASSERT(kShortExternalStringTag != 0); | |
2698 GotoIf(Word32NotEqual(Word32And(var_instance_type.value(), | |
2699 Int32Constant(kShortExternalStringMask)), | |
2700 Int32Constant(0)), | |
2701 &runtime); | |
2702 | |
2703 // Move the pointer so that offset-wise, it looks like a sequential string. | |
2704 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == | |
2705 SeqOneByteString::kHeaderSize); | |
2706 | |
2707 Node* resource_data = | |
2708 LoadObjectField(var_string.value(), ExternalString::kResourceDataOffset, | |
2709 MachineType::AnyTagged()); | |
2710 var_string.Bind(IntPtrSub( | |
2711 resource_data, | |
2712 Int32Constant(SeqTwoByteString::kHeaderSize - kHeapObjectTag))); | |
2713 | |
2714 Goto(&sequential_string); | |
2715 } | |
2716 | |
2717 Label two_byte_sequential(this); | |
2718 Bind(&sequential_string); | |
2719 { | |
2720 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); | |
2721 GotoIf(Word32Equal(Word32And(var_instance_type.value(), | |
2722 Int32Constant(kStringEncodingMask)), | |
2723 Int32Constant(0)), | |
2724 &two_byte_sequential); | |
2725 } | |
2726 | |
2727 // The subject string is a sequential one-byte string. | |
2728 { | |
2729 Node* result = AllocateSeqOneByteString(context, SmiToWord(substr_length)); | |
2730 CopyStringCharacters(var_string.value(), result, var_from.value(), | |
2731 substr_length, String::ONE_BYTE_ENCODING); | |
2732 var_result.Bind(result); | |
2733 | |
2734 Counters* counters = isolate()->counters(); | |
2735 IncrementCounter(counters->sub_string_native(), 1); | |
2736 | |
2737 Goto(&end); | |
2738 } | |
2739 | |
2740 // The subject string is a sequential two-byte string. | |
2741 Bind(&two_byte_sequential); | |
2742 { | |
2743 Node* result = AllocateSeqTwoByteString(context, SmiToWord(substr_length)); | |
2744 CopyStringCharacters(var_string.value(), result, var_from.value(), | |
2745 substr_length, String::TWO_BYTE_ENCODING); | |
2746 var_result.Bind(result); | |
2747 | |
2748 Counters* counters = isolate()->counters(); | |
2749 IncrementCounter(counters->sub_string_native(), 1); | |
2750 | |
2751 Goto(&end); | |
2752 } | |
2753 | |
2754 // Substrings of length 1 are generated through CharCodeAt and FromCharCode. | |
2755 Bind(&single_char); | |
2756 { | |
2757 Node* char_code = StringCharCodeAt(var_string.value(), var_from.value()); | |
2758 var_result.Bind(StringFromCharCode(char_code)); | |
2759 Goto(&end); | |
2760 } | |
2761 | |
2762 Bind(&original_string_or_invalid_length); | |
2763 { | |
2764 // Longer than original string's length or negative: unsafe arguments. | |
2765 GotoIf(SmiAbove(substr_length, string_length), &runtime); | |
2766 | |
2767 // Equal length - check if {from, to} == {0, str.length}. | |
2768 GotoIf(SmiAbove(from, SmiConstant(Smi::FromInt(0))), &runtime); | |
2769 | |
2770 // Return the original string (substr_length == string_length). | |
2771 | |
2772 Counters* counters = isolate()->counters(); | |
2773 IncrementCounter(counters->sub_string_native(), 1); | |
2774 | |
2775 var_result.Bind(string); | |
2776 Goto(&end); | |
2777 } | |
2778 | |
2779 // Fall back to a runtime call. | |
2780 Bind(&runtime); | |
2781 { | |
2782 var_result.Bind( | |
2783 CallRuntime(Runtime::kSubString, context, string, from, to)); | |
2784 Goto(&end); | |
2785 } | |
2786 | |
2787 Bind(&end); | |
2788 return var_result.value(); | |
2789 } | |
2790 | |
2791 Node* CodeStubAssembler::StringToNumber(Node* context, Node* input) { | 2432 Node* CodeStubAssembler::StringToNumber(Node* context, Node* input) { |
2792 Label runtime(this, Label::kDeferred); | 2433 Label runtime(this, Label::kDeferred); |
2793 Label end(this); | 2434 Label end(this); |
2794 | 2435 |
2795 Variable var_result(this, MachineRepresentation::kTagged); | 2436 Variable var_result(this, MachineRepresentation::kTagged); |
2796 | 2437 |
2797 // Check if string has a cached array index. | 2438 // Check if string has a cached array index. |
2798 Node* hash = LoadNameHashField(input); | 2439 Node* hash = LoadNameHashField(input); |
2799 Node* bit = | 2440 Node* bit = |
2800 Word32And(hash, Int32Constant(String::kContainsCachedArrayIndexMask)); | 2441 Word32And(hash, Int32Constant(String::kContainsCachedArrayIndexMask)); |
(...skipping 2732 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5533 Heap::kTheHoleValueRootIndex); | 5174 Heap::kTheHoleValueRootIndex); |
5534 | 5175 |
5535 // Store the WeakCell in the feedback vector. | 5176 // Store the WeakCell in the feedback vector. |
5536 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, | 5177 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, |
5537 CodeStubAssembler::SMI_PARAMETERS); | 5178 CodeStubAssembler::SMI_PARAMETERS); |
5538 return cell; | 5179 return cell; |
5539 } | 5180 } |
5540 | 5181 |
5541 } // namespace internal | 5182 } // namespace internal |
5542 } // namespace v8 | 5183 } // namespace v8 |
OLD | NEW |