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 947 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1301 Node* result = CallRuntime(Runtime::kAllocateSeqTwoByteString, context, | 1309 Node* result = CallRuntime(Runtime::kAllocateSeqTwoByteString, context, |
1302 SmiFromWord(length)); | 1310 SmiFromWord(length)); |
1303 var_result.Bind(result); | 1311 var_result.Bind(result); |
1304 Goto(&if_join); | 1312 Goto(&if_join); |
1305 } | 1313 } |
1306 | 1314 |
1307 Bind(&if_join); | 1315 Bind(&if_join); |
1308 return var_result.value(); | 1316 return var_result.value(); |
1309 } | 1317 } |
1310 | 1318 |
1319 Node* CodeStubAssembler::AllocateSlicedOneByteString(Node* length, Node* parent, | |
1320 Node* offset) { | |
1321 Node* result = Allocate(SlicedString::kSize); | |
1322 Node* map = LoadRoot(Heap::kSlicedOneByteStringMapRootIndex); | |
1323 StoreMapNoWriteBarrier(result, map); | |
1324 StoreObjectFieldNoWriteBarrier(result, SlicedString::kLengthOffset, length, | |
1325 MachineRepresentation::kTagged); | |
1326 StoreObjectFieldNoWriteBarrier(result, SlicedString::kHashFieldOffset, | |
1327 Int32Constant(String::kEmptyHashField), | |
1328 MachineRepresentation::kWord32); | |
1329 StoreObjectFieldNoWriteBarrier(result, SlicedString::kParentOffset, parent, | |
1330 MachineRepresentation::kTagged); | |
1331 StoreObjectFieldNoWriteBarrier(result, SlicedString::kOffsetOffset, offset, | |
1332 MachineRepresentation::kTagged); | |
1333 return result; | |
1334 } | |
1335 | |
1336 Node* CodeStubAssembler::AllocateSlicedTwoByteString(Node* length, Node* parent, | |
1337 Node* offset) { | |
1338 Node* result = Allocate(SlicedString::kSize); | |
1339 Node* map = LoadRoot(Heap::kSlicedStringMapRootIndex); | |
1340 StoreMapNoWriteBarrier(result, map); | |
1341 StoreObjectFieldNoWriteBarrier(result, SlicedString::kLengthOffset, length, | |
1342 MachineRepresentation::kTagged); | |
1343 StoreObjectFieldNoWriteBarrier(result, SlicedString::kHashFieldOffset, | |
1344 Int32Constant(String::kEmptyHashField), | |
1345 MachineRepresentation::kWord32); | |
1346 StoreObjectFieldNoWriteBarrier(result, SlicedString::kParentOffset, parent, | |
1347 MachineRepresentation::kTagged); | |
1348 StoreObjectFieldNoWriteBarrier(result, SlicedString::kOffsetOffset, offset, | |
1349 MachineRepresentation::kTagged); | |
1350 return result; | |
1351 } | |
1352 | |
1311 Node* CodeStubAssembler::AllocateUninitializedJSArrayWithoutElements( | 1353 Node* CodeStubAssembler::AllocateUninitializedJSArrayWithoutElements( |
1312 ElementsKind kind, Node* array_map, Node* length, Node* allocation_site) { | 1354 ElementsKind kind, Node* array_map, Node* length, Node* allocation_site) { |
1313 Comment("begin allocation of JSArray without elements"); | 1355 Comment("begin allocation of JSArray without elements"); |
1314 int base_size = JSArray::kSize; | 1356 int base_size = JSArray::kSize; |
1315 | |
1316 if (allocation_site != nullptr) { | 1357 if (allocation_site != nullptr) { |
1317 base_size += AllocationMemento::kSize; | 1358 base_size += AllocationMemento::kSize; |
1318 } | 1359 } |
1319 | 1360 |
1320 Node* size = IntPtrConstant(base_size); | 1361 Node* size = IntPtrConstant(base_size); |
1321 Node* array = AllocateUninitializedJSArray(kind, array_map, length, | 1362 Node* array = AllocateUninitializedJSArray(kind, array_map, length, |
1322 allocation_site, size); | 1363 allocation_site, size); |
1323 return array; | 1364 return array; |
1324 } | 1365 } |
1325 | 1366 |
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1638 Bind(&next_iter); | 1679 Bind(&next_iter); |
1639 Node* compare = WordNotEqual(from_offset, limit_offset); | 1680 Node* compare = WordNotEqual(from_offset, limit_offset); |
1640 Branch(compare, &decrement, &done); | 1681 Branch(compare, &decrement, &done); |
1641 } | 1682 } |
1642 | 1683 |
1643 Bind(&done); | 1684 Bind(&done); |
1644 IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1); | 1685 IncrementCounter(isolate()->counters()->inlined_copied_elements(), 1); |
1645 Comment("] CopyFixedArrayElements"); | 1686 Comment("] CopyFixedArrayElements"); |
1646 } | 1687 } |
1647 | 1688 |
1689 void CodeStubAssembler::CopyStringCharacters(compiler::Node* from_string, | |
1690 compiler::Node* to_string, | |
1691 compiler::Node* from_index, | |
1692 compiler::Node* character_count, | |
1693 String::Encoding encoding) { | |
1694 Label out(this); | |
1695 | |
1696 // Nothing to do for zero characters. | |
1697 | |
1698 GotoIf(SmiLessThanOrEqual(character_count, SmiConstant(Smi::FromInt(0))), | |
1699 &out); | |
1700 | |
1701 // Calculate offsets into the strings. | |
1702 | |
1703 Node* from_offset; | |
1704 Node* limit_offset; | |
1705 Node* to_offset; | |
1706 | |
1707 { | |
1708 Node* byte_count = SmiToWord32(character_count); | |
Igor Sheludko
2016/09/28 16:04:26
Do SmiUntag() instead or we will end up mixing int
jgruber
2016/09/29 07:06:41
Done.
| |
1709 Node* from_byte_index = SmiToWord32(from_index); | |
Igor Sheludko
2016/09/28 16:04:26
Same here.
jgruber
2016/09/29 07:06:41
Done.
| |
1710 if (encoding == String::ONE_BYTE_ENCODING) { | |
1711 const int offset = SeqOneByteString::kHeaderSize - kHeapObjectTag; | |
1712 from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); | |
1713 limit_offset = IntPtrAdd(from_offset, byte_count); | |
1714 to_offset = IntPtrConstant(offset); | |
1715 } else { | |
1716 STATIC_ASSERT(2 == sizeof(uc16)); | |
1717 byte_count = WordShl(byte_count, 1); | |
1718 from_byte_index = WordShl(from_byte_index, 1); | |
1719 | |
1720 const int offset = SeqTwoByteString::kHeaderSize - kHeapObjectTag; | |
1721 from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); | |
1722 limit_offset = IntPtrAdd(from_offset, byte_count); | |
1723 to_offset = IntPtrConstant(offset); | |
1724 } | |
1725 } | |
1726 | |
1727 Variable var_from_offset(this, MachineType::PointerRepresentation()); | |
1728 Variable var_to_offset(this, MachineType::PointerRepresentation()); | |
1729 | |
1730 var_from_offset.Bind(from_offset); | |
1731 var_to_offset.Bind(to_offset); | |
1732 | |
1733 Variable* vars[] = {&var_from_offset, &var_to_offset}; | |
1734 Label decrement(this, 2, vars); | |
1735 | |
1736 Label loop(this, 2, vars); | |
1737 Goto(&loop); | |
1738 Bind(&loop); | |
1739 { | |
1740 from_offset = var_from_offset.value(); | |
1741 to_offset = var_to_offset.value(); | |
1742 | |
1743 // TODO(jgruber): We could make this faster through larger copy unit sizes. | |
1744 Node* value = Load(MachineType::Uint8(), from_string, from_offset); | |
1745 StoreNoWriteBarrier(MachineRepresentation::kWord8, to_string, to_offset, | |
1746 value); | |
1747 | |
1748 Node* new_from_offset = IntPtrAdd(from_offset, IntPtrConstant(1)); | |
1749 var_from_offset.Bind(new_from_offset); | |
1750 var_to_offset.Bind(IntPtrAdd(to_offset, IntPtrConstant(1))); | |
1751 | |
1752 Branch(WordNotEqual(new_from_offset, limit_offset), &loop, &out); | |
1753 } | |
1754 | |
1755 Bind(&out); | |
1756 } | |
1757 | |
1648 Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, | 1758 Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, |
1649 Node* offset, | 1759 Node* offset, |
1650 ElementsKind from_kind, | 1760 ElementsKind from_kind, |
1651 ElementsKind to_kind, | 1761 ElementsKind to_kind, |
1652 Label* if_hole) { | 1762 Label* if_hole) { |
1653 if (IsFastDoubleElementsKind(from_kind)) { | 1763 if (IsFastDoubleElementsKind(from_kind)) { |
1654 Node* value = | 1764 Node* value = |
1655 LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64()); | 1765 LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64()); |
1656 if (!IsFastDoubleElementsKind(to_kind)) { | 1766 if (!IsFastDoubleElementsKind(to_kind)) { |
1657 value = AllocateHeapNumberWithValue(value); | 1767 value = AllocateHeapNumberWithValue(value); |
(...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2348 MachineRepresentation::kWord16, result, | 2458 MachineRepresentation::kWord16, result, |
2349 IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), code); | 2459 IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), code); |
2350 var_result.Bind(result); | 2460 var_result.Bind(result); |
2351 Goto(&if_done); | 2461 Goto(&if_done); |
2352 } | 2462 } |
2353 | 2463 |
2354 Bind(&if_done); | 2464 Bind(&if_done); |
2355 return var_result.value(); | 2465 return var_result.value(); |
2356 } | 2466 } |
2357 | 2467 |
2468 namespace { | |
2469 | |
2470 // A wrapper around CopyStringCharacters which determines the correct string | |
2471 // encoding, allocates a corresponding sequential string, and then copies the | |
2472 // given character range using CopyStringCharacters. | |
2473 // |from_string| must be a sequential string. |from_index| and | |
2474 // |character_count| must be Smis s.t. | |
2475 // 0 <= |from_index| <= |from_index| + |character_count| < from_string.length. | |
2476 Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context, | |
2477 Node* from, Node* from_instance_type, | |
2478 Node* from_index, Node* character_count) { | |
2479 typedef CodeStubAssembler::Label Label; | |
2480 typedef CodeStubAssembler::Variable Variable; | |
2481 | |
2482 Label end(a), two_byte_sequential(a); | |
2483 Variable var_result(a, MachineRepresentation::kTagged); | |
2484 | |
2485 STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); | |
2486 a->GotoIf(a->Word32Equal(a->Word32And(from_instance_type, | |
2487 a->Int32Constant(kStringEncodingMask)), | |
2488 a->Int32Constant(0)), | |
2489 &two_byte_sequential); | |
2490 | |
2491 // The subject string is a sequential one-byte string. | |
2492 { | |
2493 Node* result = | |
2494 a->AllocateSeqOneByteString(context, a->SmiToWord(character_count)); | |
2495 a->CopyStringCharacters(from, result, from_index, character_count, | |
2496 String::ONE_BYTE_ENCODING); | |
2497 var_result.Bind(result); | |
2498 | |
2499 a->Goto(&end); | |
2500 } | |
2501 | |
2502 // The subject string is a sequential two-byte string. | |
2503 a->Bind(&two_byte_sequential); | |
2504 { | |
2505 Node* result = | |
2506 a->AllocateSeqTwoByteString(context, a->SmiToWord(character_count)); | |
2507 a->CopyStringCharacters(from, result, from_index, character_count, | |
2508 String::TWO_BYTE_ENCODING); | |
2509 var_result.Bind(result); | |
2510 | |
2511 a->Goto(&end); | |
2512 } | |
2513 | |
2514 a->Bind(&end); | |
2515 return var_result.value(); | |
2516 } | |
2517 | |
2518 } // namespace | |
2519 | |
2520 Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, | |
2521 Node* to) { | |
2522 Label end(this); | |
2523 Label runtime(this); | |
2524 | |
2525 Variable var_instance_type(this, MachineRepresentation::kWord8); // Int32. | |
2526 Variable var_result(this, MachineRepresentation::kTagged); // String. | |
2527 Variable var_from(this, MachineRepresentation::kTagged); // Smi. | |
2528 Variable var_string(this, MachineRepresentation::kTagged); // String. | |
2529 | |
2530 var_instance_type.Bind(Int32Constant(0)); | |
2531 var_string.Bind(string); | |
2532 var_from.Bind(from); | |
2533 | |
2534 // Make sure first argument is a string. | |
2535 | |
2536 // Bailout if receiver is a Smi. | |
2537 GotoIf(WordIsSmi(string), &runtime); | |
2538 | |
2539 // Load the instance type of the {string}. | |
2540 Node* const instance_type = LoadInstanceType(string); | |
2541 var_instance_type.Bind(instance_type); | |
2542 | |
2543 // Check if {string} is a String. | |
2544 GotoIf(Int32GreaterThanOrEqual(instance_type, | |
2545 Int32Constant(FIRST_NONSTRING_TYPE)), | |
2546 &runtime); | |
2547 | |
2548 // Make sure that both from and to are non-negative smis. | |
2549 | |
2550 GotoUnless(WordIsPositiveSmi(from), &runtime); | |
2551 GotoUnless(WordIsPositiveSmi(to), &runtime); | |
2552 | |
2553 Node* const substr_length = SmiSub(to, from); | |
2554 Node* const string_length = LoadStringLength(string); | |
2555 | |
2556 // Begin dispatching based on substring length. | |
2557 | |
2558 Label original_string_or_invalid_length(this); | |
2559 GotoIf(SmiAboveOrEqual(substr_length, string_length), | |
2560 &original_string_or_invalid_length); | |
2561 | |
2562 // A real substring (substr_length < string_length). | |
2563 | |
2564 Label single_char(this); | |
2565 GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char); | |
2566 | |
2567 // TODO(jgruber): Add an additional case for substring of length == 0? | |
2568 | |
2569 // Deal with different string types: update the index if necessary | |
2570 // and put the underlying string into var_string. | |
2571 | |
2572 // If the string is not indirect, it can only be sequential or external. | |
2573 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); | |
2574 STATIC_ASSERT(kIsIndirectStringMask != 0); | |
2575 Label underlying_unpacked(this); | |
2576 GotoIf(Word32Equal( | |
2577 Word32And(instance_type, Int32Constant(kIsIndirectStringMask)), | |
2578 Int32Constant(0)), | |
2579 &underlying_unpacked); | |
2580 | |
2581 // The subject string is either a sliced or cons string. | |
2582 | |
2583 Label sliced_string(this); | |
2584 GotoIf(Word32NotEqual( | |
2585 Word32And(instance_type, Int32Constant(kSlicedNotConsMask)), | |
2586 Int32Constant(0)), | |
2587 &sliced_string); | |
2588 | |
2589 // Cons string. Check whether it is flat, then fetch first part. | |
2590 // Flat cons strings have an empty second part. | |
2591 { | |
2592 GotoIf(WordNotEqual(LoadObjectField(string, ConsString::kSecondOffset), | |
2593 EmptyStringConstant()), | |
2594 &runtime); | |
2595 | |
2596 Node* first_string_part = LoadObjectField(string, ConsString::kFirstOffset); | |
2597 var_string.Bind(first_string_part); | |
2598 var_instance_type.Bind(LoadInstanceType(first_string_part)); | |
2599 | |
2600 Goto(&underlying_unpacked); | |
2601 } | |
2602 | |
2603 Bind(&sliced_string); | |
2604 { | |
2605 // Fetch parent and correct start index by offset. | |
2606 Node* sliced_offset = LoadObjectField(string, SlicedString::kOffsetOffset); | |
2607 var_from.Bind(SmiAdd(from, sliced_offset)); | |
2608 | |
2609 Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); | |
2610 var_string.Bind(slice_parent); | |
2611 | |
2612 Node* slice_parent_instance_type = LoadInstanceType(slice_parent); | |
2613 var_instance_type.Bind(slice_parent_instance_type); | |
2614 | |
2615 Goto(&underlying_unpacked); | |
2616 } | |
2617 | |
2618 // The subject string can only be external or sequential string of either | |
2619 // encoding at this point. | |
2620 Label external_string(this); | |
2621 Bind(&underlying_unpacked); | |
2622 { | |
2623 if (FLAG_string_slices) { | |
2624 Label copy_routine(this); | |
2625 | |
2626 // Short slice. Copy instead of slicing. | |
2627 GotoIf(SmiLessThan(substr_length, | |
2628 SmiConstant(Smi::FromInt(SlicedString::kMinLength))), | |
2629 ©_routine); | |
2630 | |
2631 // Allocate new sliced string. | |
2632 | |
2633 Label two_byte_slice(this); | |
2634 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | |
2635 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | |
2636 | |
2637 Counters* counters = isolate()->counters(); | |
2638 IncrementCounter(counters->sub_string_native(), 1); | |
2639 | |
2640 GotoIf(Word32Equal(Word32And(var_instance_type.value(), | |
2641 Int32Constant(kStringEncodingMask)), | |
2642 Int32Constant(0)), | |
2643 &two_byte_slice); | |
2644 | |
2645 var_result.Bind(AllocateSlicedOneByteString( | |
2646 substr_length, var_string.value(), var_from.value())); | |
2647 Goto(&end); | |
2648 | |
2649 Bind(&two_byte_slice); | |
2650 | |
2651 var_result.Bind(AllocateSlicedTwoByteString( | |
2652 substr_length, var_string.value(), var_from.value())); | |
2653 Goto(&end); | |
2654 | |
2655 Bind(©_routine); | |
2656 } | |
2657 | |
2658 // The subject string can only be external or sequential string of either | |
2659 // encoding at this point. | |
2660 STATIC_ASSERT(kExternalStringTag != 0); | |
2661 STATIC_ASSERT(kSeqStringTag == 0); | |
2662 GotoUnless(Word32Equal(Word32And(var_instance_type.value(), | |
2663 Int32Constant(kExternalStringTag)), | |
2664 Int32Constant(0)), | |
2665 &external_string); | |
2666 | |
2667 var_result.Bind(AllocAndCopyStringCharacters( | |
2668 this, context, var_string.value(), var_instance_type.value(), | |
2669 var_from.value(), substr_length)); | |
2670 | |
2671 Counters* counters = isolate()->counters(); | |
2672 IncrementCounter(counters->sub_string_native(), 1); | |
2673 | |
2674 Goto(&end); | |
2675 } | |
2676 | |
2677 // Handle external string. | |
2678 Bind(&external_string); | |
2679 { | |
2680 // Rule out short external strings. | |
2681 STATIC_ASSERT(kShortExternalStringTag != 0); | |
2682 GotoIf(Word32NotEqual(Word32And(var_instance_type.value(), | |
2683 Int32Constant(kShortExternalStringMask)), | |
2684 Int32Constant(0)), | |
2685 &runtime); | |
2686 | |
2687 // Move the pointer so that offset-wise, it looks like a sequential string. | |
2688 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == | |
2689 SeqOneByteString::kHeaderSize); | |
2690 | |
2691 Node* resource_data = LoadObjectField(var_string.value(), | |
2692 ExternalString::kResourceDataOffset); | |
2693 Node* const fake_sequential_string = IntPtrSub( | |
2694 resource_data, | |
2695 IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
2696 | |
2697 var_result.Bind(AllocAndCopyStringCharacters( | |
2698 this, context, fake_sequential_string, var_instance_type.value(), | |
2699 var_from.value(), substr_length)); | |
2700 | |
2701 Counters* counters = isolate()->counters(); | |
2702 IncrementCounter(counters->sub_string_native(), 1); | |
2703 | |
2704 Goto(&end); | |
2705 } | |
2706 | |
2707 // Substrings of length 1 are generated through CharCodeAt and FromCharCode. | |
2708 Bind(&single_char); | |
2709 { | |
2710 Node* char_code = StringCharCodeAt(var_string.value(), var_from.value()); | |
2711 var_result.Bind(StringFromCharCode(char_code)); | |
2712 Goto(&end); | |
2713 } | |
2714 | |
2715 Bind(&original_string_or_invalid_length); | |
2716 { | |
2717 // Longer than original string's length or negative: unsafe arguments. | |
2718 GotoIf(SmiAbove(substr_length, string_length), &runtime); | |
2719 | |
2720 // Equal length - check if {from, to} == {0, str.length}. | |
2721 GotoIf(SmiAbove(from, SmiConstant(Smi::FromInt(0))), &runtime); | |
2722 | |
2723 // Return the original string (substr_length == string_length). | |
2724 | |
2725 Counters* counters = isolate()->counters(); | |
2726 IncrementCounter(counters->sub_string_native(), 1); | |
2727 | |
2728 var_result.Bind(string); | |
2729 Goto(&end); | |
2730 } | |
2731 | |
2732 // Fall back to a runtime call. | |
2733 Bind(&runtime); | |
2734 { | |
2735 var_result.Bind( | |
2736 CallRuntime(Runtime::kSubString, context, string, from, to)); | |
2737 Goto(&end); | |
2738 } | |
2739 | |
2740 Bind(&end); | |
2741 return var_result.value(); | |
2742 } | |
2743 | |
2358 Node* CodeStubAssembler::StringFromCodePoint(compiler::Node* codepoint, | 2744 Node* CodeStubAssembler::StringFromCodePoint(compiler::Node* codepoint, |
2359 UnicodeEncoding encoding) { | 2745 UnicodeEncoding encoding) { |
2360 Variable var_result(this, MachineRepresentation::kTagged); | 2746 Variable var_result(this, MachineRepresentation::kTagged); |
2361 var_result.Bind(EmptyStringConstant()); | 2747 var_result.Bind(EmptyStringConstant()); |
2362 | 2748 |
2363 Label if_isword16(this), if_isword32(this), return_result(this); | 2749 Label if_isword16(this), if_isword32(this), return_result(this); |
2364 | 2750 |
2365 Branch(Uint32LessThan(codepoint, Int32Constant(0x10000)), &if_isword16, | 2751 Branch(Uint32LessThan(codepoint, Int32Constant(0x10000)), &if_isword16, |
2366 &if_isword32); | 2752 &if_isword32); |
2367 | 2753 |
(...skipping 2947 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5315 Heap::kTheHoleValueRootIndex); | 5701 Heap::kTheHoleValueRootIndex); |
5316 | 5702 |
5317 // Store the WeakCell in the feedback vector. | 5703 // Store the WeakCell in the feedback vector. |
5318 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, | 5704 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, |
5319 CodeStubAssembler::SMI_PARAMETERS); | 5705 CodeStubAssembler::SMI_PARAMETERS); |
5320 return cell; | 5706 return cell; |
5321 } | 5707 } |
5322 | 5708 |
5323 } // namespace internal | 5709 } // namespace internal |
5324 } // namespace v8 | 5710 } // namespace v8 |
OLD | NEW |