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