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 | 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 | |
| 340 Node* CodeStubAssembler::SmiAboveOrEqual(Node* a, Node* b) { | 344 Node* CodeStubAssembler::SmiAboveOrEqual(Node* a, Node* b) { |
| 341 return UintPtrGreaterThanOrEqual(a, b); | 345 return UintPtrGreaterThanOrEqual(a, b); |
| 342 } | 346 } |
| 343 | 347 |
| 348 Node* CodeStubAssembler::SmiBelow(Node* a, Node* b) { | |
| 349 return UintPtrLessThan(a, b); | |
| 350 } | |
| 351 | |
| 344 Node* CodeStubAssembler::SmiLessThan(Node* a, Node* b) { | 352 Node* CodeStubAssembler::SmiLessThan(Node* a, Node* b) { |
| 345 return IntPtrLessThan(a, b); | 353 return IntPtrLessThan(a, b); |
| 346 } | 354 } |
| 347 | 355 |
| 348 Node* CodeStubAssembler::SmiLessThanOrEqual(Node* a, Node* b) { | 356 Node* CodeStubAssembler::SmiLessThanOrEqual(Node* a, Node* b) { |
| 349 return IntPtrLessThanOrEqual(a, b); | 357 return IntPtrLessThanOrEqual(a, b); |
| 350 } | 358 } |
| 351 | 359 |
| 352 Node* CodeStubAssembler::SmiMin(Node* a, Node* b) { | 360 Node* CodeStubAssembler::SmiMin(Node* a, Node* b) { |
| 353 // TODO(bmeurer): Consider using Select once available. | 361 // TODO(bmeurer): Consider using Select once available. |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 490 | 498 |
| 491 Node* CodeStubAssembler::WordIsSmi(Node* a) { | 499 Node* CodeStubAssembler::WordIsSmi(Node* a) { |
| 492 return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask)), IntPtrConstant(0)); | 500 return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask)), IntPtrConstant(0)); |
| 493 } | 501 } |
| 494 | 502 |
| 495 Node* CodeStubAssembler::WordIsPositiveSmi(Node* a) { | 503 Node* CodeStubAssembler::WordIsPositiveSmi(Node* a) { |
| 496 return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask | kSmiSignMask)), | 504 return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask | kSmiSignMask)), |
| 497 IntPtrConstant(0)); | 505 IntPtrConstant(0)); |
| 498 } | 506 } |
| 499 | 507 |
| 508 Node* CodeStubAssembler::WordIsNotPositiveSmi(Node* a) { | |
| 509 return WordNotEqual(WordAnd(a, IntPtrConstant(kSmiTagMask | kSmiSignMask)), | |
| 510 IntPtrConstant(0)); | |
| 511 } | |
| 512 | |
| 500 void CodeStubAssembler::BranchIfSameValueZero(Node* a, Node* b, Node* context, | 513 void CodeStubAssembler::BranchIfSameValueZero(Node* a, Node* b, Node* context, |
| 501 Label* if_true, Label* if_false) { | 514 Label* if_true, Label* if_false) { |
| 502 Node* number_map = HeapNumberMapConstant(); | 515 Node* number_map = HeapNumberMapConstant(); |
| 503 Label a_isnumber(this), a_isnotnumber(this), b_isnumber(this), a_isnan(this), | 516 Label a_isnumber(this), a_isnotnumber(this), b_isnumber(this), a_isnan(this), |
| 504 float_not_equal(this); | 517 float_not_equal(this); |
| 505 // If register A and register B are identical, goto `if_true` | 518 // If register A and register B are identical, goto `if_true` |
| 506 GotoIf(WordEqual(a, b), if_true); | 519 GotoIf(WordEqual(a, b), if_true); |
| 507 // If either register A or B are Smis, goto `if_false` | 520 // If either register A or B are Smis, goto `if_false` |
| 508 GotoIf(Word32Or(WordIsSmi(a), WordIsSmi(b)), if_false); | 521 GotoIf(Word32Or(WordIsSmi(a), WordIsSmi(b)), if_false); |
| 509 // GotoIf(WordIsSmi(b), if_false); | 522 // GotoIf(WordIsSmi(b), if_false); |
| (...skipping 865 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1375 Node* result = CallRuntime(Runtime::kAllocateSeqTwoByteString, context, | 1388 Node* result = CallRuntime(Runtime::kAllocateSeqTwoByteString, context, |
| 1376 SmiFromWord(length)); | 1389 SmiFromWord(length)); |
| 1377 var_result.Bind(result); | 1390 var_result.Bind(result); |
| 1378 Goto(&if_join); | 1391 Goto(&if_join); |
| 1379 } | 1392 } |
| 1380 | 1393 |
| 1381 Bind(&if_join); | 1394 Bind(&if_join); |
| 1382 return var_result.value(); | 1395 return var_result.value(); |
| 1383 } | 1396 } |
| 1384 | 1397 |
| 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 | |
| 1385 Node* CodeStubAssembler::AllocateUninitializedJSArrayWithoutElements( | 1432 Node* CodeStubAssembler::AllocateUninitializedJSArrayWithoutElements( |
| 1386 ElementsKind kind, Node* array_map, Node* length, Node* allocation_site) { | 1433 ElementsKind kind, Node* array_map, Node* length, Node* allocation_site) { |
| 1387 Comment("begin allocation of JSArray without elements"); | 1434 Comment("begin allocation of JSArray without elements"); |
| 1388 int base_size = JSArray::kSize; | 1435 int base_size = JSArray::kSize; |
| 1389 | |
| 1390 if (allocation_site != nullptr) { | 1436 if (allocation_site != nullptr) { |
| 1391 base_size += AllocationMemento::kSize; | 1437 base_size += AllocationMemento::kSize; |
| 1392 } | 1438 } |
| 1393 | 1439 |
| 1394 Node* size = IntPtrConstant(base_size); | 1440 Node* size = IntPtrConstant(base_size); |
| 1395 Node* array = AllocateUninitializedJSArray(kind, array_map, length, | 1441 Node* array = AllocateUninitializedJSArray(kind, array_map, length, |
| 1396 allocation_site, size); | 1442 allocation_site, size); |
| 1397 return array; | 1443 return array; |
| 1398 } | 1444 } |
| 1399 | 1445 |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1712 Bind(&next_iter); | 1758 Bind(&next_iter); |
| 1713 Node* compare = WordNotEqual(from_offset, limit_offset); | 1759 Node* compare = WordNotEqual(from_offset, limit_offset); |
| 1714 Branch(compare, &decrement, &done); | 1760 Branch(compare, &decrement, &done); |
| 1715 } | 1761 } |
| 1716 | 1762 |
| 1717 Bind(&done); | 1763 Bind(&done); |
| 1718 IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1); | 1764 IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1); |
| 1719 Comment("] CopyFixedArrayElements"); | 1765 Comment("] CopyFixedArrayElements"); |
| 1720 } | 1766 } |
| 1721 | 1767 |
| 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 | |
| 1722 Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, | 1837 Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, |
| 1723 Node* offset, | 1838 Node* offset, |
| 1724 ElementsKind from_kind, | 1839 ElementsKind from_kind, |
| 1725 ElementsKind to_kind, | 1840 ElementsKind to_kind, |
| 1726 Label* if_hole) { | 1841 Label* if_hole) { |
| 1727 if (IsFastDoubleElementsKind(from_kind)) { | 1842 if (IsFastDoubleElementsKind(from_kind)) { |
| 1728 Node* value = | 1843 Node* value = |
| 1729 LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64()); | 1844 LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64()); |
| 1730 if (!IsFastDoubleElementsKind(to_kind)) { | 1845 if (!IsFastDoubleElementsKind(to_kind)) { |
| 1731 value = AllocateHeapNumberWithValue(value); | 1846 value = AllocateHeapNumberWithValue(value); |
| (...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2422 MachineRepresentation::kWord16, result, | 2537 MachineRepresentation::kWord16, result, |
| 2423 IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), code); | 2538 IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), code); |
| 2424 var_result.Bind(result); | 2539 var_result.Bind(result); |
| 2425 Goto(&if_done); | 2540 Goto(&if_done); |
| 2426 } | 2541 } |
| 2427 | 2542 |
| 2428 Bind(&if_done); | 2543 Bind(&if_done); |
| 2429 return var_result.value(); | 2544 return var_result.value(); |
| 2430 } | 2545 } |
| 2431 | 2546 |
| 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)); | |
|
Igor Sheludko
2016/09/22 12:23:37
You could probably avoid this binding if you move
jgruber
2016/09/22 13:22:41
I'm not so sure - runtime (the label that complain
| |
| 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 | |
| 2432 Node* CodeStubAssembler::StringToNumber(Node* context, Node* input) { | 2791 Node* CodeStubAssembler::StringToNumber(Node* context, Node* input) { |
| 2433 Label runtime(this, Label::kDeferred); | 2792 Label runtime(this, Label::kDeferred); |
| 2434 Label end(this); | 2793 Label end(this); |
| 2435 | 2794 |
| 2436 Variable var_result(this, MachineRepresentation::kTagged); | 2795 Variable var_result(this, MachineRepresentation::kTagged); |
| 2437 | 2796 |
| 2438 // Check if string has a cached array index. | 2797 // Check if string has a cached array index. |
| 2439 Node* hash = LoadNameHashField(input); | 2798 Node* hash = LoadNameHashField(input); |
| 2440 Node* bit = | 2799 Node* bit = |
| 2441 Word32And(hash, Int32Constant(String::kContainsCachedArrayIndexMask)); | 2800 Word32And(hash, Int32Constant(String::kContainsCachedArrayIndexMask)); |
| (...skipping 2732 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5174 Heap::kTheHoleValueRootIndex); | 5533 Heap::kTheHoleValueRootIndex); |
| 5175 | 5534 |
| 5176 // Store the WeakCell in the feedback vector. | 5535 // Store the WeakCell in the feedback vector. |
| 5177 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, | 5536 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, |
| 5178 CodeStubAssembler::SMI_PARAMETERS); | 5537 CodeStubAssembler::SMI_PARAMETERS); |
| 5179 return cell; | 5538 return cell; |
| 5180 } | 5539 } |
| 5181 | 5540 |
| 5182 } // namespace internal | 5541 } // namespace internal |
| 5183 } // namespace v8 | 5542 } // namespace v8 |
| OLD | NEW |