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 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 |