diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 8a36f359c8..cb7981f7ed 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -2124,231 +2124,6 @@ void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, __ bind(&done); } - -void SubStringStub::Generate(MacroAssembler* masm) { - Label runtime; - - // Stack frame on entry. - // lr: return address - // sp[0]: to - // sp[4]: from - // sp[8]: string - - // This stub is called from the native-call %_SubString(...), so - // nothing can be assumed about the arguments. It is tested that: - // "string" is a sequential string, - // both "from" and "to" are smis, and - // 0 <= from <= to <= string.length. - // If any of these assumptions fail, we call the runtime system. - - const int kToOffset = 0 * kPointerSize; - const int kFromOffset = 1 * kPointerSize; - const int kStringOffset = 2 * kPointerSize; - - __ Ldrd(r2, r3, MemOperand(sp, kToOffset)); - STATIC_ASSERT(kFromOffset == kToOffset + 4); - STATIC_ASSERT(kSmiTag == 0); - STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); - - // Arithmetic shift right by one un-smi-tags. In this case we rotate right - // instead because we bail out on non-smi values: ROR and ASR are equivalent - // for smis but they set the flags in a way that's easier to optimize. - __ mov(r2, Operand(r2, ROR, 1), SetCC); - __ mov(r3, Operand(r3, ROR, 1), SetCC, cc); - // If either to or from had the smi tag bit set, then C is set now, and N - // has the same value: we rotated by 1, so the bottom bit is now the top bit. - // We want to bailout to runtime here if From is negative. In that case, the - // next instruction is not executed and we fall through to bailing out to - // runtime. - // Executed if both r2 and r3 are untagged integers. - __ sub(r2, r2, Operand(r3), SetCC, cc); - // One of the above un-smis or the above SUB could have set N==1. - __ b(mi, &runtime); // Either "from" or "to" is not an smi, or from > to. - - // Make sure first argument is a string. - __ ldr(r0, MemOperand(sp, kStringOffset)); - __ JumpIfSmi(r0, &runtime); - Condition is_string = masm->IsObjectStringType(r0, r1); - __ b(NegateCondition(is_string), &runtime); - - Label single_char; - __ cmp(r2, Operand(1)); - __ b(eq, &single_char); - - // Short-cut for the case of trivial substring. - Label return_r0; - // r0: original string - // r2: result string length - __ ldr(r4, FieldMemOperand(r0, String::kLengthOffset)); - __ cmp(r2, Operand(r4, ASR, 1)); - // Return original string. - __ b(eq, &return_r0); - // Longer than original string's length or negative: unsafe arguments. - __ b(hi, &runtime); - // Shorter than original string's length: an actual substring. - - // Deal with different string types: update the index if necessary - // and put the underlying string into r5. - // r0: original string - // r1: instance type - // r2: length - // r3: from index (untagged) - Label underlying_unpacked, sliced_string, seq_or_external_string; - // If the string is not indirect, it can only be sequential or external. - STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); - STATIC_ASSERT(kIsIndirectStringMask != 0); - __ tst(r1, Operand(kIsIndirectStringMask)); - __ b(eq, &seq_or_external_string); - - __ tst(r1, Operand(kSlicedNotConsMask)); - __ b(ne, &sliced_string); - // Cons string. Check whether it is flat, then fetch first part. - __ ldr(r5, FieldMemOperand(r0, ConsString::kSecondOffset)); - __ CompareRoot(r5, Heap::kempty_stringRootIndex); - __ b(ne, &runtime); - __ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset)); - // Update instance type. - __ ldr(r1, FieldMemOperand(r5, HeapObject::kMapOffset)); - __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); - __ jmp(&underlying_unpacked); - - __ bind(&sliced_string); - // Sliced string. Fetch parent and correct start index by offset. - __ ldr(r5, FieldMemOperand(r0, SlicedString::kParentOffset)); - __ ldr(r4, FieldMemOperand(r0, SlicedString::kOffsetOffset)); - __ add(r3, r3, Operand(r4, ASR, 1)); // Add offset to index. - // Update instance type. - __ ldr(r1, FieldMemOperand(r5, HeapObject::kMapOffset)); - __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); - __ jmp(&underlying_unpacked); - - __ bind(&seq_or_external_string); - // Sequential or external string. Just move string to the expected register. - __ mov(r5, r0); - - __ bind(&underlying_unpacked); - - if (FLAG_string_slices) { - Label copy_routine; - // r5: underlying subject string - // r1: instance type of underlying subject string - // r2: length - // r3: adjusted start index (untagged) - __ cmp(r2, Operand(SlicedString::kMinLength)); - // Short slice. Copy instead of slicing. - __ b(lt, ©_routine); - // Allocate new sliced string. At this point we do not reload the instance - // type including the string encoding because we simply rely on the info - // provided by the original string. It does not matter if the original - // string's encoding is wrong because we always have to recheck encoding of - // the newly created string's parent anyways due to externalized strings. - Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ tst(r1, Operand(kStringEncodingMask)); - __ b(eq, &two_byte_slice); - __ AllocateOneByteSlicedString(r0, r2, r6, r4, &runtime); - __ jmp(&set_slice_header); - __ bind(&two_byte_slice); - __ AllocateTwoByteSlicedString(r0, r2, r6, r4, &runtime); - __ bind(&set_slice_header); - __ mov(r3, Operand(r3, LSL, 1)); - __ str(r5, FieldMemOperand(r0, SlicedString::kParentOffset)); - __ str(r3, FieldMemOperand(r0, SlicedString::kOffsetOffset)); - __ jmp(&return_r0); - - __ bind(©_routine); - } - - // r5: underlying subject string - // r1: instance type of underlying subject string - // r2: length - // r3: adjusted start index (untagged) - Label two_byte_sequential, sequential_string, allocate_result; - STATIC_ASSERT(kExternalStringTag != 0); - STATIC_ASSERT(kSeqStringTag == 0); - __ tst(r1, Operand(kExternalStringTag)); - __ b(eq, &sequential_string); - - // Handle external string. - // Rule out short external strings. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ tst(r1, Operand(kShortExternalStringTag)); - __ b(ne, &runtime); - __ ldr(r5, FieldMemOperand(r5, ExternalString::kResourceDataOffset)); - // r5 already points to the first character of underlying string. - __ jmp(&allocate_result); - - __ bind(&sequential_string); - // Locate first character of underlying subject string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); - __ add(r5, r5, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - - __ bind(&allocate_result); - // Sequential acii string. Allocate the result. - STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); - __ tst(r1, Operand(kStringEncodingMask)); - __ b(eq, &two_byte_sequential); - - // Allocate and copy the resulting one-byte string. - __ AllocateOneByteString(r0, r2, r4, r6, r1, &runtime); - - // Locate first character of substring to copy. - __ add(r5, r5, r3); - // Locate first character of result. - __ add(r1, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - - // r0: result string - // r1: first character of result string - // r2: result string length - // r5: first character of substring to copy - STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); - StringHelper::GenerateCopyCharacters( - masm, r1, r5, r2, r3, String::ONE_BYTE_ENCODING); - __ jmp(&return_r0); - - // Allocate and copy the resulting two-byte string. - __ bind(&two_byte_sequential); - __ AllocateTwoByteString(r0, r2, r4, r6, r1, &runtime); - - // Locate first character of substring to copy. - STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); - __ add(r5, r5, Operand(r3, LSL, 1)); - // Locate first character of result. - __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - - // r0: result string. - // r1: first character of result. - // r2: result length. - // r5: first character of substring to copy. - STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); - StringHelper::GenerateCopyCharacters( - masm, r1, r5, r2, r3, String::TWO_BYTE_ENCODING); - - __ bind(&return_r0); - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); - __ Drop(3); - __ Ret(); - - // Just jump to runtime to create the sub string. - __ bind(&runtime); - __ TailCallRuntime(Runtime::kSubString); - - __ bind(&single_char); - // r0: original string - // r1: instance type - // r2: length - // r3: from index (untagged) - __ SmiTag(r3, r3); - StringCharAtGenerator generator(r0, r3, r2, r0, &runtime, &runtime, &runtime, - RECEIVER_IS_STRING); - generator.GenerateFast(masm); - __ Drop(3); - __ Ret(); - generator.SkipSlow(masm, &runtime); -} - void ToStringStub::Generate(MacroAssembler* masm) { // The ToString stub takes one argument in r0. Label is_number; diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc index 5163fb964c..1296360b2f 100644 --- a/src/arm64/code-stubs-arm64.cc +++ b/src/arm64/code-stubs-arm64.cc @@ -2673,257 +2673,6 @@ void CompareICStub::GenerateMiss(MacroAssembler* masm) { __ Jump(stub_entry); } - -void SubStringStub::Generate(MacroAssembler* masm) { - ASM_LOCATION("SubStringStub::Generate"); - Label runtime; - - // Stack frame on entry. - // lr: return address - // jssp[0]: substring "to" offset - // jssp[8]: substring "from" offset - // jssp[16]: pointer to string object - - // This stub is called from the native-call %_SubString(...), so - // nothing can be assumed about the arguments. It is tested that: - // "string" is a sequential string, - // both "from" and "to" are smis, and - // 0 <= from <= to <= string.length (in debug mode.) - // If any of these assumptions fail, we call the runtime system. - - static const int kToOffset = 0 * kPointerSize; - static const int kFromOffset = 1 * kPointerSize; - static const int kStringOffset = 2 * kPointerSize; - - Register to = x0; - Register from = x15; - Register input_string = x10; - Register input_length = x11; - Register input_type = x12; - Register result_string = x0; - Register result_length = x1; - Register temp = x3; - - __ Peek(to, kToOffset); - __ Peek(from, kFromOffset); - - // Check that both from and to are smis. If not, jump to runtime. - __ JumpIfEitherNotSmi(from, to, &runtime); - __ SmiUntag(from); - __ SmiUntag(to); - - // Calculate difference between from and to. If to < from, branch to runtime. - __ Subs(result_length, to, from); - __ B(mi, &runtime); - - // Check from is positive. - __ Tbnz(from, kWSignBit, &runtime); - - // Make sure first argument is a string. - __ Peek(input_string, kStringOffset); - __ JumpIfSmi(input_string, &runtime); - __ IsObjectJSStringType(input_string, input_type, &runtime); - - Label single_char; - __ Cmp(result_length, 1); - __ B(eq, &single_char); - - // Short-cut for the case of trivial substring. - Label return_x0; - __ Ldrsw(input_length, - UntagSmiFieldMemOperand(input_string, String::kLengthOffset)); - - __ Cmp(result_length, input_length); - __ CmovX(x0, input_string, eq); - // Return original string. - __ B(eq, &return_x0); - - // Longer than original string's length or negative: unsafe arguments. - __ B(hi, &runtime); - - // Shorter than original string's length: an actual substring. - - // x0 to substring end character offset - // x1 result_length length of substring result - // x10 input_string pointer to input string object - // x10 unpacked_string pointer to unpacked string object - // x11 input_length length of input string - // x12 input_type instance type of input string - // x15 from substring start character offset - - // Deal with different string types: update the index if necessary and put - // the underlying string into register unpacked_string. - Label underlying_unpacked, sliced_string, seq_or_external_string; - Label update_instance_type; - // If the string is not indirect, it can only be sequential or external. - STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); - STATIC_ASSERT(kIsIndirectStringMask != 0); - - // Test for string types, and branch/fall through to appropriate unpacking - // code. - __ Tst(input_type, kIsIndirectStringMask); - __ B(eq, &seq_or_external_string); - __ Tst(input_type, kSlicedNotConsMask); - __ B(ne, &sliced_string); - - Register unpacked_string = input_string; - - // Cons string. Check whether it is flat, then fetch first part. - __ Ldr(temp, FieldMemOperand(input_string, ConsString::kSecondOffset)); - __ JumpIfNotRoot(temp, Heap::kempty_stringRootIndex, &runtime); - __ Ldr(unpacked_string, - FieldMemOperand(input_string, ConsString::kFirstOffset)); - __ B(&update_instance_type); - - __ Bind(&sliced_string); - // Sliced string. Fetch parent and correct start index by offset. - __ Ldrsw(temp, - UntagSmiFieldMemOperand(input_string, SlicedString::kOffsetOffset)); - __ Add(from, from, temp); - __ Ldr(unpacked_string, - FieldMemOperand(input_string, SlicedString::kParentOffset)); - - __ Bind(&update_instance_type); - __ Ldr(temp, FieldMemOperand(unpacked_string, HeapObject::kMapOffset)); - __ Ldrb(input_type, FieldMemOperand(temp, Map::kInstanceTypeOffset)); - // Now control must go to &underlying_unpacked. Since the no code is generated - // before then we fall through instead of generating a useless branch. - - __ Bind(&seq_or_external_string); - // Sequential or external string. Registers unpacked_string and input_string - // alias, so there's nothing to do here. - // Note that if code is added here, the above code must be updated. - - // x0 result_string pointer to result string object (uninit) - // x1 result_length length of substring result - // x10 unpacked_string pointer to unpacked string object - // x11 input_length length of input string - // x12 input_type instance type of input string - // x15 from substring start character offset - __ Bind(&underlying_unpacked); - - if (FLAG_string_slices) { - Label copy_routine; - __ Cmp(result_length, SlicedString::kMinLength); - // Short slice. Copy instead of slicing. - __ B(lt, ©_routine); - // Allocate new sliced string. At this point we do not reload the instance - // type including the string encoding because we simply rely on the info - // provided by the original string. It does not matter if the original - // string's encoding is wrong because we always have to recheck encoding of - // the newly created string's parent anyway due to externalized strings. - Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ Tbz(input_type, MaskToBit(kStringEncodingMask), &two_byte_slice); - __ AllocateOneByteSlicedString(result_string, result_length, x3, x4, - &runtime); - __ B(&set_slice_header); - - __ Bind(&two_byte_slice); - __ AllocateTwoByteSlicedString(result_string, result_length, x3, x4, - &runtime); - - __ Bind(&set_slice_header); - __ SmiTag(from); - __ Str(from, FieldMemOperand(result_string, SlicedString::kOffsetOffset)); - __ Str(unpacked_string, - FieldMemOperand(result_string, SlicedString::kParentOffset)); - __ B(&return_x0); - - __ Bind(©_routine); - } - - // x0 result_string pointer to result string object (uninit) - // x1 result_length length of substring result - // x10 unpacked_string pointer to unpacked string object - // x11 input_length length of input string - // x12 input_type instance type of input string - // x13 unpacked_char0 pointer to first char of unpacked string (uninit) - // x13 substring_char0 pointer to first char of substring (uninit) - // x14 result_char0 pointer to first char of result (uninit) - // x15 from substring start character offset - Register unpacked_char0 = x13; - Register substring_char0 = x13; - Register result_char0 = x14; - Label two_byte_sequential, sequential_string, allocate_result; - STATIC_ASSERT(kExternalStringTag != 0); - STATIC_ASSERT(kSeqStringTag == 0); - - __ Tst(input_type, kExternalStringTag); - __ B(eq, &sequential_string); - - __ Tst(input_type, kShortExternalStringTag); - __ B(ne, &runtime); - __ Ldr(unpacked_char0, - FieldMemOperand(unpacked_string, ExternalString::kResourceDataOffset)); - // unpacked_char0 points to the first character of the underlying string. - __ B(&allocate_result); - - __ Bind(&sequential_string); - // Locate first character of underlying subject string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); - __ Add(unpacked_char0, unpacked_string, - SeqOneByteString::kHeaderSize - kHeapObjectTag); - - __ Bind(&allocate_result); - // Sequential one-byte string. Allocate the result. - STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); - __ Tbz(input_type, MaskToBit(kStringEncodingMask), &two_byte_sequential); - - // Allocate and copy the resulting one-byte string. - __ AllocateOneByteString(result_string, result_length, x3, x4, x5, &runtime); - - // Locate first character of substring to copy. - __ Add(substring_char0, unpacked_char0, from); - - // Locate first character of result. - __ Add(result_char0, result_string, - SeqOneByteString::kHeaderSize - kHeapObjectTag); - - STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); - __ CopyBytes(result_char0, substring_char0, result_length, x3, kCopyLong); - __ B(&return_x0); - - // Allocate and copy the resulting two-byte string. - __ Bind(&two_byte_sequential); - __ AllocateTwoByteString(result_string, result_length, x3, x4, x5, &runtime); - - // Locate first character of substring to copy. - __ Add(substring_char0, unpacked_char0, Operand(from, LSL, 1)); - - // Locate first character of result. - __ Add(result_char0, result_string, - SeqTwoByteString::kHeaderSize - kHeapObjectTag); - - STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); - __ Add(result_length, result_length, result_length); - __ CopyBytes(result_char0, substring_char0, result_length, x3, kCopyLong); - - __ Bind(&return_x0); - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->sub_string_native(), 1, x3, x4); - __ Drop(3); - __ Ret(); - - __ Bind(&runtime); - __ TailCallRuntime(Runtime::kSubString); - - __ bind(&single_char); - // x1: result_length - // x10: input_string - // x12: input_type - // x15: from (untagged) - __ SmiTag(from); - StringCharAtGenerator generator(input_string, from, result_length, x0, - &runtime, &runtime, &runtime, - RECEIVER_IS_STRING); - generator.GenerateFast(masm); - __ Drop(3); - __ Ret(); - generator.SkipSlow(masm, &runtime); -} - void ToStringStub::Generate(MacroAssembler* masm) { // The ToString stub takes one argument in x0. Label is_number; diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc index c01fb67e09..f87f55a479 100644 --- a/src/code-stub-assembler.cc +++ b/src/code-stub-assembler.cc @@ -337,10 +337,18 @@ Node* CodeStubAssembler::SmiSubWithOverflow(Node* a, Node* b) { Node* CodeStubAssembler::SmiEqual(Node* a, Node* b) { return WordEqual(a, b); } +Node* CodeStubAssembler::SmiAbove(Node* a, Node* b) { + return UintPtrGreaterThan(a, b); +} + Node* CodeStubAssembler::SmiAboveOrEqual(Node* a, Node* b) { return UintPtrGreaterThanOrEqual(a, b); } +Node* CodeStubAssembler::SmiBelow(Node* a, Node* b) { + return UintPtrLessThan(a, b); +} + Node* CodeStubAssembler::SmiLessThan(Node* a, Node* b) { return IntPtrLessThan(a, b); } @@ -1301,11 +1309,44 @@ Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length) { return var_result.value(); } +Node* CodeStubAssembler::AllocateSlicedOneByteString(Node* length, Node* parent, + Node* offset) { + Node* result = Allocate(SlicedString::kSize); + Node* map = LoadRoot(Heap::kSlicedOneByteStringMapRootIndex); + StoreMapNoWriteBarrier(result, map); + StoreObjectFieldNoWriteBarrier(result, SlicedString::kLengthOffset, length, + MachineRepresentation::kTagged); + StoreObjectFieldNoWriteBarrier(result, SlicedString::kHashFieldOffset, + Int32Constant(String::kEmptyHashField), + MachineRepresentation::kWord32); + StoreObjectFieldNoWriteBarrier(result, SlicedString::kParentOffset, parent, + MachineRepresentation::kTagged); + StoreObjectFieldNoWriteBarrier(result, SlicedString::kOffsetOffset, offset, + MachineRepresentation::kTagged); + return result; +} + +Node* CodeStubAssembler::AllocateSlicedTwoByteString(Node* length, Node* parent, + Node* offset) { + Node* result = Allocate(SlicedString::kSize); + Node* map = LoadRoot(Heap::kSlicedStringMapRootIndex); + StoreMapNoWriteBarrier(result, map); + StoreObjectFieldNoWriteBarrier(result, SlicedString::kLengthOffset, length, + MachineRepresentation::kTagged); + StoreObjectFieldNoWriteBarrier(result, SlicedString::kHashFieldOffset, + Int32Constant(String::kEmptyHashField), + MachineRepresentation::kWord32); + StoreObjectFieldNoWriteBarrier(result, SlicedString::kParentOffset, parent, + MachineRepresentation::kTagged); + StoreObjectFieldNoWriteBarrier(result, SlicedString::kOffsetOffset, offset, + MachineRepresentation::kTagged); + return result; +} + Node* CodeStubAssembler::AllocateUninitializedJSArrayWithoutElements( ElementsKind kind, Node* array_map, Node* length, Node* allocation_site) { Comment("begin allocation of JSArray without elements"); int base_size = JSArray::kSize; - if (allocation_site != nullptr) { base_size += AllocationMemento::kSize; } @@ -1638,6 +1679,75 @@ void CodeStubAssembler::CopyFixedArrayElements( Comment("] CopyFixedArrayElements"); } +void CodeStubAssembler::CopyStringCharacters(compiler::Node* from_string, + compiler::Node* to_string, + compiler::Node* from_index, + compiler::Node* character_count, + String::Encoding encoding) { + Label out(this); + + // Nothing to do for zero characters. + + GotoIf(SmiLessThanOrEqual(character_count, SmiConstant(Smi::FromInt(0))), + &out); + + // Calculate offsets into the strings. + + Node* from_offset; + Node* limit_offset; + Node* to_offset; + + { + Node* byte_count = SmiUntag(character_count); + Node* from_byte_index = SmiUntag(from_index); + if (encoding == String::ONE_BYTE_ENCODING) { + const int offset = SeqOneByteString::kHeaderSize - kHeapObjectTag; + from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); + limit_offset = IntPtrAdd(from_offset, byte_count); + to_offset = IntPtrConstant(offset); + } else { + STATIC_ASSERT(2 == sizeof(uc16)); + byte_count = WordShl(byte_count, 1); + from_byte_index = WordShl(from_byte_index, 1); + + const int offset = SeqTwoByteString::kHeaderSize - kHeapObjectTag; + from_offset = IntPtrAdd(IntPtrConstant(offset), from_byte_index); + limit_offset = IntPtrAdd(from_offset, byte_count); + to_offset = IntPtrConstant(offset); + } + } + + Variable var_from_offset(this, MachineType::PointerRepresentation()); + Variable var_to_offset(this, MachineType::PointerRepresentation()); + + var_from_offset.Bind(from_offset); + var_to_offset.Bind(to_offset); + + Variable* vars[] = {&var_from_offset, &var_to_offset}; + Label decrement(this, 2, vars); + + Label loop(this, 2, vars); + Goto(&loop); + Bind(&loop); + { + from_offset = var_from_offset.value(); + to_offset = var_to_offset.value(); + + // TODO(jgruber): We could make this faster through larger copy unit sizes. + Node* value = Load(MachineType::Uint8(), from_string, from_offset); + StoreNoWriteBarrier(MachineRepresentation::kWord8, to_string, to_offset, + value); + + Node* new_from_offset = IntPtrAdd(from_offset, IntPtrConstant(1)); + var_from_offset.Bind(new_from_offset); + var_to_offset.Bind(IntPtrAdd(to_offset, IntPtrConstant(1))); + + Branch(WordNotEqual(new_from_offset, limit_offset), &loop, &out); + } + + Bind(&out); +} + Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array, Node* offset, ElementsKind from_kind, @@ -2348,6 +2458,282 @@ Node* CodeStubAssembler::StringFromCharCode(Node* code) { return var_result.value(); } +namespace { + +// A wrapper around CopyStringCharacters which determines the correct string +// encoding, allocates a corresponding sequential string, and then copies the +// given character range using CopyStringCharacters. +// |from_string| must be a sequential string. |from_index| and +// |character_count| must be Smis s.t. +// 0 <= |from_index| <= |from_index| + |character_count| < from_string.length. +Node* AllocAndCopyStringCharacters(CodeStubAssembler* a, Node* context, + Node* from, Node* from_instance_type, + Node* from_index, Node* character_count) { + typedef CodeStubAssembler::Label Label; + typedef CodeStubAssembler::Variable Variable; + + Label end(a), two_byte_sequential(a); + Variable var_result(a, MachineRepresentation::kTagged); + + STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); + a->GotoIf(a->Word32Equal(a->Word32And(from_instance_type, + a->Int32Constant(kStringEncodingMask)), + a->Int32Constant(0)), + &two_byte_sequential); + + // The subject string is a sequential one-byte string. + { + Node* result = + a->AllocateSeqOneByteString(context, a->SmiToWord(character_count)); + a->CopyStringCharacters(from, result, from_index, character_count, + String::ONE_BYTE_ENCODING); + var_result.Bind(result); + + a->Goto(&end); + } + + // The subject string is a sequential two-byte string. + a->Bind(&two_byte_sequential); + { + Node* result = + a->AllocateSeqTwoByteString(context, a->SmiToWord(character_count)); + a->CopyStringCharacters(from, result, from_index, character_count, + String::TWO_BYTE_ENCODING); + var_result.Bind(result); + + a->Goto(&end); + } + + a->Bind(&end); + return var_result.value(); +} + +} // namespace + +Node* CodeStubAssembler::SubString(Node* context, Node* string, Node* from, + Node* to) { + Label end(this); + Label runtime(this); + + Variable var_instance_type(this, MachineRepresentation::kWord8); // Int32. + Variable var_result(this, MachineRepresentation::kTagged); // String. + Variable var_from(this, MachineRepresentation::kTagged); // Smi. + Variable var_string(this, MachineRepresentation::kTagged); // String. + + var_instance_type.Bind(Int32Constant(0)); + var_string.Bind(string); + var_from.Bind(from); + + // Make sure first argument is a string. + + // Bailout if receiver is a Smi. + GotoIf(WordIsSmi(string), &runtime); + + // Load the instance type of the {string}. + Node* const instance_type = LoadInstanceType(string); + var_instance_type.Bind(instance_type); + + // Check if {string} is a String. + GotoIf(Int32GreaterThanOrEqual(instance_type, + Int32Constant(FIRST_NONSTRING_TYPE)), + &runtime); + + // Make sure that both from and to are non-negative smis. + + GotoUnless(WordIsPositiveSmi(from), &runtime); + GotoUnless(WordIsPositiveSmi(to), &runtime); + + Node* const substr_length = SmiSub(to, from); + Node* const string_length = LoadStringLength(string); + + // Begin dispatching based on substring length. + + Label original_string_or_invalid_length(this); + GotoIf(SmiAboveOrEqual(substr_length, string_length), + &original_string_or_invalid_length); + + // A real substring (substr_length < string_length). + + Label single_char(this); + GotoIf(SmiEqual(substr_length, SmiConstant(Smi::FromInt(1))), &single_char); + + // TODO(jgruber): Add an additional case for substring of length == 0? + + // Deal with different string types: update the index if necessary + // and put the underlying string into var_string. + + // If the string is not indirect, it can only be sequential or external. + STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); + STATIC_ASSERT(kIsIndirectStringMask != 0); + Label underlying_unpacked(this); + GotoIf(Word32Equal( + Word32And(instance_type, Int32Constant(kIsIndirectStringMask)), + Int32Constant(0)), + &underlying_unpacked); + + // The subject string is either a sliced or cons string. + + Label sliced_string(this); + GotoIf(Word32NotEqual( + Word32And(instance_type, Int32Constant(kSlicedNotConsMask)), + Int32Constant(0)), + &sliced_string); + + // Cons string. Check whether it is flat, then fetch first part. + // Flat cons strings have an empty second part. + { + GotoIf(WordNotEqual(LoadObjectField(string, ConsString::kSecondOffset), + EmptyStringConstant()), + &runtime); + + Node* first_string_part = LoadObjectField(string, ConsString::kFirstOffset); + var_string.Bind(first_string_part); + var_instance_type.Bind(LoadInstanceType(first_string_part)); + + Goto(&underlying_unpacked); + } + + Bind(&sliced_string); + { + // Fetch parent and correct start index by offset. + Node* sliced_offset = LoadObjectField(string, SlicedString::kOffsetOffset); + var_from.Bind(SmiAdd(from, sliced_offset)); + + Node* slice_parent = LoadObjectField(string, SlicedString::kParentOffset); + var_string.Bind(slice_parent); + + Node* slice_parent_instance_type = LoadInstanceType(slice_parent); + var_instance_type.Bind(slice_parent_instance_type); + + Goto(&underlying_unpacked); + } + + // The subject string can only be external or sequential string of either + // encoding at this point. + Label external_string(this); + Bind(&underlying_unpacked); + { + if (FLAG_string_slices) { + Label copy_routine(this); + + // Short slice. Copy instead of slicing. + GotoIf(SmiLessThan(substr_length, + SmiConstant(Smi::FromInt(SlicedString::kMinLength))), + ©_routine); + + // Allocate new sliced string. + + Label two_byte_slice(this); + STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); + STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); + + Counters* counters = isolate()->counters(); + IncrementCounter(counters->sub_string_native(), 1); + + GotoIf(Word32Equal(Word32And(var_instance_type.value(), + Int32Constant(kStringEncodingMask)), + Int32Constant(0)), + &two_byte_slice); + + var_result.Bind(AllocateSlicedOneByteString( + substr_length, var_string.value(), var_from.value())); + Goto(&end); + + Bind(&two_byte_slice); + + var_result.Bind(AllocateSlicedTwoByteString( + substr_length, var_string.value(), var_from.value())); + Goto(&end); + + Bind(©_routine); + } + + // The subject string can only be external or sequential string of either + // encoding at this point. + STATIC_ASSERT(kExternalStringTag != 0); + STATIC_ASSERT(kSeqStringTag == 0); + GotoUnless(Word32Equal(Word32And(var_instance_type.value(), + Int32Constant(kExternalStringTag)), + Int32Constant(0)), + &external_string); + + var_result.Bind(AllocAndCopyStringCharacters( + this, context, var_string.value(), var_instance_type.value(), + var_from.value(), substr_length)); + + Counters* counters = isolate()->counters(); + IncrementCounter(counters->sub_string_native(), 1); + + Goto(&end); + } + + // Handle external string. + Bind(&external_string); + { + // Rule out short external strings. + STATIC_ASSERT(kShortExternalStringTag != 0); + GotoIf(Word32NotEqual(Word32And(var_instance_type.value(), + Int32Constant(kShortExternalStringMask)), + Int32Constant(0)), + &runtime); + + // Move the pointer so that offset-wise, it looks like a sequential string. + STATIC_ASSERT(SeqTwoByteString::kHeaderSize == + SeqOneByteString::kHeaderSize); + + Node* resource_data = LoadObjectField(var_string.value(), + ExternalString::kResourceDataOffset); + Node* const fake_sequential_string = IntPtrSub( + resource_data, + IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); + + var_result.Bind(AllocAndCopyStringCharacters( + this, context, fake_sequential_string, var_instance_type.value(), + var_from.value(), substr_length)); + + Counters* counters = isolate()->counters(); + IncrementCounter(counters->sub_string_native(), 1); + + Goto(&end); + } + + // Substrings of length 1 are generated through CharCodeAt and FromCharCode. + Bind(&single_char); + { + Node* char_code = StringCharCodeAt(var_string.value(), var_from.value()); + var_result.Bind(StringFromCharCode(char_code)); + Goto(&end); + } + + Bind(&original_string_or_invalid_length); + { + // Longer than original string's length or negative: unsafe arguments. + GotoIf(SmiAbove(substr_length, string_length), &runtime); + + // Equal length - check if {from, to} == {0, str.length}. + GotoIf(SmiAbove(from, SmiConstant(Smi::FromInt(0))), &runtime); + + // Return the original string (substr_length == string_length). + + Counters* counters = isolate()->counters(); + IncrementCounter(counters->sub_string_native(), 1); + + var_result.Bind(string); + Goto(&end); + } + + // Fall back to a runtime call. + Bind(&runtime); + { + var_result.Bind( + CallRuntime(Runtime::kSubString, context, string, from, to)); + Goto(&end); + } + + Bind(&end); + return var_result.value(); +} + Node* CodeStubAssembler::StringFromCodePoint(compiler::Node* codepoint, UnicodeEncoding encoding) { Variable var_result(this, MachineRepresentation::kTagged); diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h index 76d4cece1b..936c5d2677 100644 --- a/src/code-stub-assembler.h +++ b/src/code-stub-assembler.h @@ -117,7 +117,9 @@ class CodeStubAssembler : public compiler::CodeAssembler { compiler::Node* SmiSub(compiler::Node* a, compiler::Node* b); compiler::Node* SmiSubWithOverflow(compiler::Node* a, compiler::Node* b); compiler::Node* SmiEqual(compiler::Node* a, compiler::Node* b); + compiler::Node* SmiAbove(compiler::Node* a, compiler::Node* b); compiler::Node* SmiAboveOrEqual(compiler::Node* a, compiler::Node* b); + compiler::Node* SmiBelow(compiler::Node* a, compiler::Node* b); compiler::Node* SmiLessThan(compiler::Node* a, compiler::Node* b); compiler::Node* SmiLessThanOrEqual(compiler::Node* a, compiler::Node* b); compiler::Node* SmiMax(compiler::Node* a, compiler::Node* b); @@ -141,7 +143,7 @@ class CodeStubAssembler : public compiler::CodeAssembler { // Check a value for smi-ness compiler::Node* WordIsSmi(compiler::Node* a); - // Check that the value is a positive smi. + // Check that the value is a non-negative smi. compiler::Node* WordIsPositiveSmi(compiler::Node* a); void BranchIfSmiEqual(compiler::Node* a, compiler::Node* b, Label* if_true, @@ -328,6 +330,18 @@ class CodeStubAssembler : public compiler::CodeAssembler { compiler::Node* AllocateSeqTwoByteString(int length); compiler::Node* AllocateSeqTwoByteString(compiler::Node* context, compiler::Node* length); + + // Allocate a SlicedOneByteString with the given length, parent and offset. + // |length| and |offset| are expected to be tagged. + compiler::Node* AllocateSlicedOneByteString(compiler::Node* length, + compiler::Node* parent, + compiler::Node* offset); + // Allocate a SlicedTwoByteString with the given length, parent and offset. + // |length| and |offset| are expected to be tagged. + compiler::Node* AllocateSlicedTwoByteString(compiler::Node* length, + compiler::Node* parent, + compiler::Node* offset); + // Allocate a JSArray without elements and initialize the header fields. compiler::Node* AllocateUninitializedJSArrayWithoutElements( ElementsKind kind, compiler::Node* array_map, compiler::Node* length, @@ -378,6 +392,16 @@ class CodeStubAssembler : public compiler::CodeAssembler { WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER, ParameterMode mode = INTEGER_PARAMETERS); + // Copies |character_count| elements from |from_string| to |to_string| + // starting at the |from_index|'th character. |from_index| and + // |character_count| must be Smis s.t. + // 0 <= |from_index| <= |from_index| + |character_count| < from_string.length. + void CopyStringCharacters(compiler::Node* from_string, + compiler::Node* to_string, + compiler::Node* from_index, + compiler::Node* character_count, + String::Encoding encoding); + // Loads an element from |array| of |from_kind| elements by given |offset| // (NOTE: not index!), does a hole check if |if_hole| is provided and // converts the value so that it becomes ready for storing to array of @@ -449,6 +473,10 @@ class CodeStubAssembler : public compiler::CodeAssembler { compiler::Node* smi_index); // Return the single character string with only {code}. compiler::Node* StringFromCharCode(compiler::Node* code); + // Return a new string object which holds a substring containing the range + // [from,to[ of string. |from| and |to| are expected to be tagged. + compiler::Node* SubString(compiler::Node* context, compiler::Node* string, + compiler::Node* from, compiler::Node* to); compiler::Node* StringFromCodePoint(compiler::Node* codepoint, UnicodeEncoding encoding); diff --git a/src/code-stubs.cc b/src/code-stubs.cc index d05fe0f258..3e06643f9a 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -2719,6 +2719,15 @@ compiler::Node* DecStub::Generate(CodeStubAssembler* assembler, return result_var.value(); } +// ES6 section 21.1.3.19 String.prototype.substring ( start, end ) +compiler::Node* SubStringStub::Generate(CodeStubAssembler* assembler, + compiler::Node* string, + compiler::Node* from, + compiler::Node* to, + compiler::Node* context) { + return assembler->SubString(context, string, from, to); +} + // ES6 section 7.1.13 ToObject (argument) void ToObjectStub::GenerateAssembly(CodeStubAssembler* assembler) const { typedef compiler::Node Node; diff --git a/src/code-stubs.h b/src/code-stubs.h index 92bc298ebd..7b9d76bfdb 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -3094,13 +3094,24 @@ class StoreBufferOverflowStub : public PlatformCodeStub { DEFINE_PLATFORM_CODE_STUB(StoreBufferOverflow, PlatformCodeStub); }; - -class SubStringStub : public PlatformCodeStub { +class SubStringStub : public TurboFanCodeStub { public: - explicit SubStringStub(Isolate* isolate) : PlatformCodeStub(isolate) {} + explicit SubStringStub(Isolate* isolate) : TurboFanCodeStub(isolate) {} + + static compiler::Node* Generate(CodeStubAssembler* assembler, + compiler::Node* string, compiler::Node* from, + compiler::Node* to, compiler::Node* context); + + void GenerateAssembly(CodeStubAssembler* assembler) const override { + assembler->Return(Generate(assembler, + assembler->Parameter(Descriptor::kString), + assembler->Parameter(Descriptor::kFrom), + assembler->Parameter(Descriptor::kTo), + assembler->Parameter(Descriptor::kContext))); + } DEFINE_CALL_INTERFACE_DESCRIPTOR(SubString); - DEFINE_PLATFORM_CODE_STUB(SubString, PlatformCodeStub); + DEFINE_CODE_STUB(SubString, TurboFanCodeStub); }; class ToStringStub final : public PlatformCodeStub { diff --git a/src/full-codegen/full-codegen.cc b/src/full-codegen/full-codegen.cc index 93c1a1817e..25d7f920f1 100644 --- a/src/full-codegen/full-codegen.cc +++ b/src/full-codegen/full-codegen.cc @@ -568,6 +568,7 @@ void FullCodeGenerator::EmitSubString(CallRuntime* expr) { VisitForStackValue(args->at(1)); VisitForStackValue(args->at(2)); __ CallStub(&stub); + RestoreContext(); OperandStackDepthDecrement(3); context()->Plug(result_register()); } diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 55dcc9dab3..daee72d184 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -2065,227 +2065,6 @@ void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, __ bind(&done); } - -void SubStringStub::Generate(MacroAssembler* masm) { - Label runtime; - - // Stack frame on entry. - // esp[0]: return address - // esp[4]: to - // esp[8]: from - // esp[12]: string - - // Make sure first argument is a string. - __ mov(eax, Operand(esp, 3 * kPointerSize)); - STATIC_ASSERT(kSmiTag == 0); - __ JumpIfSmi(eax, &runtime); - Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); - __ j(NegateCondition(is_string), &runtime); - - // eax: string - // ebx: instance type - - // Calculate length of sub string using the smi values. - __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index. - __ JumpIfNotSmi(ecx, &runtime); - __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index. - __ JumpIfNotSmi(edx, &runtime); - __ sub(ecx, edx); - __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); - Label not_original_string; - // Shorter than original string's length: an actual substring. - __ j(below, ¬_original_string, Label::kNear); - // Longer than original string's length or negative: unsafe arguments. - __ j(above, &runtime); - // Return original string. - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(3 * kPointerSize); - __ bind(¬_original_string); - - Label single_char; - __ cmp(ecx, Immediate(Smi::FromInt(1))); - __ j(equal, &single_char); - - // eax: string - // ebx: instance type - // ecx: sub string length (smi) - // edx: from index (smi) - // Deal with different string types: update the index if necessary - // and put the underlying string into edi. - Label underlying_unpacked, sliced_string, seq_or_external_string; - // If the string is not indirect, it can only be sequential or external. - STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); - STATIC_ASSERT(kIsIndirectStringMask != 0); - __ test(ebx, Immediate(kIsIndirectStringMask)); - __ j(zero, &seq_or_external_string, Label::kNear); - - Factory* factory = isolate()->factory(); - __ test(ebx, Immediate(kSlicedNotConsMask)); - __ j(not_zero, &sliced_string, Label::kNear); - // Cons string. Check whether it is flat, then fetch first part. - // Flat cons strings have an empty second part. - __ cmp(FieldOperand(eax, ConsString::kSecondOffset), - factory->empty_string()); - __ j(not_equal, &runtime); - __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset)); - // Update instance type. - __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); - __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); - __ jmp(&underlying_unpacked, Label::kNear); - - __ bind(&sliced_string); - // Sliced string. Fetch parent and adjust start index by offset. - __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset)); - __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset)); - // Update instance type. - __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); - __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); - __ jmp(&underlying_unpacked, Label::kNear); - - __ bind(&seq_or_external_string); - // Sequential or external string. Just move string to the expected register. - __ mov(edi, eax); - - __ bind(&underlying_unpacked); - - if (FLAG_string_slices) { - Label copy_routine; - // edi: underlying subject string - // ebx: instance type of underlying subject string - // edx: adjusted start index (smi) - // ecx: length (smi) - __ cmp(ecx, Immediate(Smi::FromInt(SlicedString::kMinLength))); - // Short slice. Copy instead of slicing. - __ j(less, ©_routine); - // Allocate new sliced string. At this point we do not reload the instance - // type including the string encoding because we simply rely on the info - // provided by the original string. It does not matter if the original - // string's encoding is wrong because we always have to recheck encoding of - // the newly created string's parent anyways due to externalized strings. - Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ test(ebx, Immediate(kStringEncodingMask)); - __ j(zero, &two_byte_slice, Label::kNear); - __ AllocateOneByteSlicedString(eax, ebx, no_reg, &runtime); - __ jmp(&set_slice_header, Label::kNear); - __ bind(&two_byte_slice); - __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime); - __ bind(&set_slice_header); - __ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx); - __ mov(FieldOperand(eax, SlicedString::kHashFieldOffset), - Immediate(String::kEmptyHashField)); - __ mov(FieldOperand(eax, SlicedString::kParentOffset), edi); - __ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(3 * kPointerSize); - - __ bind(©_routine); - } - - // edi: underlying subject string - // ebx: instance type of underlying subject string - // edx: adjusted start index (smi) - // ecx: length (smi) - // The subject string can only be external or sequential string of either - // encoding at this point. - Label two_byte_sequential, runtime_drop_two, sequential_string; - STATIC_ASSERT(kExternalStringTag != 0); - STATIC_ASSERT(kSeqStringTag == 0); - __ test_b(ebx, Immediate(kExternalStringTag)); - __ j(zero, &sequential_string); - - // Handle external string. - // Rule out short external strings. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ test_b(ebx, Immediate(kShortExternalStringMask)); - __ j(not_zero, &runtime); - __ mov(edi, FieldOperand(edi, ExternalString::kResourceDataOffset)); - // Move the pointer so that offset-wise, it looks like a sequential string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); - __ sub(edi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - - __ bind(&sequential_string); - // Stash away (adjusted) index and (underlying) string. - __ push(edx); - __ push(edi); - __ SmiUntag(ecx); - STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); - __ test_b(ebx, Immediate(kStringEncodingMask)); - __ j(zero, &two_byte_sequential); - - // Sequential one byte string. Allocate the result. - __ AllocateOneByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two); - - // eax: result string - // ecx: result string length - // Locate first character of result. - __ mov(edi, eax); - __ add(edi, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - // Load string argument and locate character of sub string start. - __ pop(edx); - __ pop(ebx); - __ SmiUntag(ebx); - __ lea(edx, FieldOperand(edx, ebx, times_1, SeqOneByteString::kHeaderSize)); - - // eax: result string - // ecx: result length - // edi: first character of result - // edx: character of sub string start - StringHelper::GenerateCopyCharacters( - masm, edi, edx, ecx, ebx, String::ONE_BYTE_ENCODING); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(3 * kPointerSize); - - __ bind(&two_byte_sequential); - // Sequential two-byte string. Allocate the result. - __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two); - - // eax: result string - // ecx: result string length - // Locate first character of result. - __ mov(edi, eax); - __ add(edi, - Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - // Load string argument and locate character of sub string start. - __ pop(edx); - __ pop(ebx); - // As from is a smi it is 2 times the value which matches the size of a two - // byte character. - STATIC_ASSERT(kSmiTag == 0); - STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); - __ lea(edx, FieldOperand(edx, ebx, times_1, SeqTwoByteString::kHeaderSize)); - - // eax: result string - // ecx: result length - // edi: first character of result - // edx: character of sub string start - StringHelper::GenerateCopyCharacters( - masm, edi, edx, ecx, ebx, String::TWO_BYTE_ENCODING); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(3 * kPointerSize); - - // Drop pushed values on the stack before tail call. - __ bind(&runtime_drop_two); - __ Drop(2); - - // Just jump to runtime to create the sub string. - __ bind(&runtime); - __ TailCallRuntime(Runtime::kSubString); - - __ bind(&single_char); - // eax: string - // ebx: instance type - // ecx: sub string length (smi) - // edx: from index (smi) - StringCharAtGenerator generator(eax, edx, ecx, eax, &runtime, &runtime, - &runtime, RECEIVER_IS_STRING); - generator.GenerateFast(masm); - __ ret(3 * kPointerSize); - generator.SkipSlow(masm, &runtime); -} - void ToStringStub::Generate(MacroAssembler* masm) { // The ToString stub takes one argument in eax. Label is_number; diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc index 68cb356d00..7ab85dcec8 100644 --- a/src/mips/code-stubs-mips.cc +++ b/src/mips/code-stubs-mips.cc @@ -2268,229 +2268,6 @@ void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, __ bind(&done); } - -void SubStringStub::Generate(MacroAssembler* masm) { - Label runtime; - // Stack frame on entry. - // ra: return address - // sp[0]: to - // sp[4]: from - // sp[8]: string - - // This stub is called from the native-call %_SubString(...), so - // nothing can be assumed about the arguments. It is tested that: - // "string" is a sequential string, - // both "from" and "to" are smis, and - // 0 <= from <= to <= string.length. - // If any of these assumptions fail, we call the runtime system. - - const int kToOffset = 0 * kPointerSize; - const int kFromOffset = 1 * kPointerSize; - const int kStringOffset = 2 * kPointerSize; - - __ lw(a2, MemOperand(sp, kToOffset)); - __ lw(a3, MemOperand(sp, kFromOffset)); - STATIC_ASSERT(kFromOffset == kToOffset + 4); - STATIC_ASSERT(kSmiTag == 0); - STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); - - // Utilize delay slots. SmiUntag doesn't emit a jump, everything else is - // safe in this case. - __ UntagAndJumpIfNotSmi(a2, a2, &runtime); - __ UntagAndJumpIfNotSmi(a3, a3, &runtime); - // Both a2 and a3 are untagged integers. - - __ Branch(&runtime, lt, a3, Operand(zero_reg)); // From < 0. - - __ Branch(&runtime, gt, a3, Operand(a2)); // Fail if from > to. - __ Subu(a2, a2, a3); - - // Make sure first argument is a string. - __ lw(v0, MemOperand(sp, kStringOffset)); - __ JumpIfSmi(v0, &runtime); - __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset)); - __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset)); - __ And(t0, a1, Operand(kIsNotStringMask)); - - __ Branch(&runtime, ne, t0, Operand(zero_reg)); - - Label single_char; - __ Branch(&single_char, eq, a2, Operand(1)); - - // Short-cut for the case of trivial substring. - Label return_v0; - // v0: original string - // a2: result string length - __ lw(t0, FieldMemOperand(v0, String::kLengthOffset)); - __ sra(t0, t0, 1); - // Return original string. - __ Branch(&return_v0, eq, a2, Operand(t0)); - // Longer than original string's length or negative: unsafe arguments. - __ Branch(&runtime, hi, a2, Operand(t0)); - // Shorter than original string's length: an actual substring. - - // Deal with different string types: update the index if necessary - // and put the underlying string into t1. - // v0: original string - // a1: instance type - // a2: length - // a3: from index (untagged) - Label underlying_unpacked, sliced_string, seq_or_external_string; - // If the string is not indirect, it can only be sequential or external. - STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); - STATIC_ASSERT(kIsIndirectStringMask != 0); - __ And(t0, a1, Operand(kIsIndirectStringMask)); - __ Branch(USE_DELAY_SLOT, &seq_or_external_string, eq, t0, Operand(zero_reg)); - // t0 is used as a scratch register and can be overwritten in either case. - __ And(t0, a1, Operand(kSlicedNotConsMask)); - __ Branch(&sliced_string, ne, t0, Operand(zero_reg)); - // Cons string. Check whether it is flat, then fetch first part. - __ lw(t1, FieldMemOperand(v0, ConsString::kSecondOffset)); - __ LoadRoot(t0, Heap::kempty_stringRootIndex); - __ Branch(&runtime, ne, t1, Operand(t0)); - __ lw(t1, FieldMemOperand(v0, ConsString::kFirstOffset)); - // Update instance type. - __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset)); - __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset)); - __ jmp(&underlying_unpacked); - - __ bind(&sliced_string); - // Sliced string. Fetch parent and correct start index by offset. - __ lw(t1, FieldMemOperand(v0, SlicedString::kParentOffset)); - __ lw(t0, FieldMemOperand(v0, SlicedString::kOffsetOffset)); - __ sra(t0, t0, 1); // Add offset to index. - __ Addu(a3, a3, t0); - // Update instance type. - __ lw(a1, FieldMemOperand(t1, HeapObject::kMapOffset)); - __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset)); - __ jmp(&underlying_unpacked); - - __ bind(&seq_or_external_string); - // Sequential or external string. Just move string to the expected register. - __ mov(t1, v0); - - __ bind(&underlying_unpacked); - - if (FLAG_string_slices) { - Label copy_routine; - // t1: underlying subject string - // a1: instance type of underlying subject string - // a2: length - // a3: adjusted start index (untagged) - // Short slice. Copy instead of slicing. - __ Branch(©_routine, lt, a2, Operand(SlicedString::kMinLength)); - // Allocate new sliced string. At this point we do not reload the instance - // type including the string encoding because we simply rely on the info - // provided by the original string. It does not matter if the original - // string's encoding is wrong because we always have to recheck encoding of - // the newly created string's parent anyways due to externalized strings. - Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ And(t0, a1, Operand(kStringEncodingMask)); - __ Branch(&two_byte_slice, eq, t0, Operand(zero_reg)); - __ AllocateOneByteSlicedString(v0, a2, t2, t3, &runtime); - __ jmp(&set_slice_header); - __ bind(&two_byte_slice); - __ AllocateTwoByteSlicedString(v0, a2, t2, t3, &runtime); - __ bind(&set_slice_header); - __ sll(a3, a3, 1); - __ sw(t1, FieldMemOperand(v0, SlicedString::kParentOffset)); - __ sw(a3, FieldMemOperand(v0, SlicedString::kOffsetOffset)); - __ jmp(&return_v0); - - __ bind(©_routine); - } - - // t1: underlying subject string - // a1: instance type of underlying subject string - // a2: length - // a3: adjusted start index (untagged) - Label two_byte_sequential, sequential_string, allocate_result; - STATIC_ASSERT(kExternalStringTag != 0); - STATIC_ASSERT(kSeqStringTag == 0); - __ And(t0, a1, Operand(kExternalStringTag)); - __ Branch(&sequential_string, eq, t0, Operand(zero_reg)); - - // Handle external string. - // Rule out short external strings. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ And(t0, a1, Operand(kShortExternalStringTag)); - __ Branch(&runtime, ne, t0, Operand(zero_reg)); - __ lw(t1, FieldMemOperand(t1, ExternalString::kResourceDataOffset)); - // t1 already points to the first character of underlying string. - __ jmp(&allocate_result); - - __ bind(&sequential_string); - // Locate first character of underlying subject string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); - __ Addu(t1, t1, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - - __ bind(&allocate_result); - // Sequential acii string. Allocate the result. - STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); - __ And(t0, a1, Operand(kStringEncodingMask)); - __ Branch(&two_byte_sequential, eq, t0, Operand(zero_reg)); - - // Allocate and copy the resulting ASCII string. - __ AllocateOneByteString(v0, a2, t0, t2, t3, &runtime); - - // Locate first character of substring to copy. - __ Addu(t1, t1, a3); - - // Locate first character of result. - __ Addu(a1, v0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - - // v0: result string - // a1: first character of result string - // a2: result string length - // t1: first character of substring to copy - STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); - StringHelper::GenerateCopyCharacters( - masm, a1, t1, a2, a3, String::ONE_BYTE_ENCODING); - __ jmp(&return_v0); - - // Allocate and copy the resulting two-byte string. - __ bind(&two_byte_sequential); - __ AllocateTwoByteString(v0, a2, t0, t2, t3, &runtime); - - // Locate first character of substring to copy. - STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); - __ Lsa(t1, t1, a3, 1); - // Locate first character of result. - __ Addu(a1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - - // v0: result string. - // a1: first character of result. - // a2: result length. - // t1: first character of substring to copy. - STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); - StringHelper::GenerateCopyCharacters( - masm, a1, t1, a2, a3, String::TWO_BYTE_ENCODING); - - __ bind(&return_v0); - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->sub_string_native(), 1, a3, t0); - __ DropAndRet(3); - - // Just jump to runtime to create the sub string. - __ bind(&runtime); - __ TailCallRuntime(Runtime::kSubString); - - __ bind(&single_char); - // v0: original string - // a1: instance type - // a2: length - // a3: from index (untagged) - __ SmiTag(a3, a3); - StringCharAtGenerator generator(v0, a3, a2, v0, &runtime, &runtime, &runtime, - RECEIVER_IS_STRING); - generator.GenerateFast(masm); - __ DropAndRet(3); - generator.SkipSlow(masm, &runtime); -} - - void ToStringStub::Generate(MacroAssembler* masm) { // The ToString stub takes on argument in a0. Label is_number; diff --git a/src/mips64/code-stubs-mips64.cc b/src/mips64/code-stubs-mips64.cc index c0c05747df..b9356c9e92 100644 --- a/src/mips64/code-stubs-mips64.cc +++ b/src/mips64/code-stubs-mips64.cc @@ -2271,229 +2271,6 @@ void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, __ bind(&done); } - -void SubStringStub::Generate(MacroAssembler* masm) { - Label runtime; - // Stack frame on entry. - // ra: return address - // sp[0]: to - // sp[4]: from - // sp[8]: string - - // This stub is called from the native-call %_SubString(...), so - // nothing can be assumed about the arguments. It is tested that: - // "string" is a sequential string, - // both "from" and "to" are smis, and - // 0 <= from <= to <= string.length. - // If any of these assumptions fail, we call the runtime system. - - const int kToOffset = 0 * kPointerSize; - const int kFromOffset = 1 * kPointerSize; - const int kStringOffset = 2 * kPointerSize; - - __ ld(a2, MemOperand(sp, kToOffset)); - __ ld(a3, MemOperand(sp, kFromOffset)); - - STATIC_ASSERT(kSmiTag == 0); - - // Utilize delay slots. SmiUntag doesn't emit a jump, everything else is - // safe in this case. - __ JumpIfNotSmi(a2, &runtime); - __ JumpIfNotSmi(a3, &runtime); - // Both a2 and a3 are untagged integers. - - __ SmiUntag(a2, a2); - __ SmiUntag(a3, a3); - __ Branch(&runtime, lt, a3, Operand(zero_reg)); // From < 0. - - __ Branch(&runtime, gt, a3, Operand(a2)); // Fail if from > to. - __ Dsubu(a2, a2, a3); - - // Make sure first argument is a string. - __ ld(v0, MemOperand(sp, kStringOffset)); - __ JumpIfSmi(v0, &runtime); - __ ld(a1, FieldMemOperand(v0, HeapObject::kMapOffset)); - __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset)); - __ And(a4, a1, Operand(kIsNotStringMask)); - - __ Branch(&runtime, ne, a4, Operand(zero_reg)); - - Label single_char; - __ Branch(&single_char, eq, a2, Operand(1)); - - // Short-cut for the case of trivial substring. - Label return_v0; - // v0: original string - // a2: result string length - __ ld(a4, FieldMemOperand(v0, String::kLengthOffset)); - __ SmiUntag(a4); - // Return original string. - __ Branch(&return_v0, eq, a2, Operand(a4)); - // Longer than original string's length or negative: unsafe arguments. - __ Branch(&runtime, hi, a2, Operand(a4)); - // Shorter than original string's length: an actual substring. - - // Deal with different string types: update the index if necessary - // and put the underlying string into a5. - // v0: original string - // a1: instance type - // a2: length - // a3: from index (untagged) - Label underlying_unpacked, sliced_string, seq_or_external_string; - // If the string is not indirect, it can only be sequential or external. - STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); - STATIC_ASSERT(kIsIndirectStringMask != 0); - __ And(a4, a1, Operand(kIsIndirectStringMask)); - __ Branch(USE_DELAY_SLOT, &seq_or_external_string, eq, a4, Operand(zero_reg)); - // a4 is used as a scratch register and can be overwritten in either case. - __ And(a4, a1, Operand(kSlicedNotConsMask)); - __ Branch(&sliced_string, ne, a4, Operand(zero_reg)); - // Cons string. Check whether it is flat, then fetch first part. - __ ld(a5, FieldMemOperand(v0, ConsString::kSecondOffset)); - __ LoadRoot(a4, Heap::kempty_stringRootIndex); - __ Branch(&runtime, ne, a5, Operand(a4)); - __ ld(a5, FieldMemOperand(v0, ConsString::kFirstOffset)); - // Update instance type. - __ ld(a1, FieldMemOperand(a5, HeapObject::kMapOffset)); - __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset)); - __ jmp(&underlying_unpacked); - - __ bind(&sliced_string); - // Sliced string. Fetch parent and correct start index by offset. - __ ld(a5, FieldMemOperand(v0, SlicedString::kParentOffset)); - __ ld(a4, FieldMemOperand(v0, SlicedString::kOffsetOffset)); - __ SmiUntag(a4); // Add offset to index. - __ Daddu(a3, a3, a4); - // Update instance type. - __ ld(a1, FieldMemOperand(a5, HeapObject::kMapOffset)); - __ lbu(a1, FieldMemOperand(a1, Map::kInstanceTypeOffset)); - __ jmp(&underlying_unpacked); - - __ bind(&seq_or_external_string); - // Sequential or external string. Just move string to the expected register. - __ mov(a5, v0); - - __ bind(&underlying_unpacked); - - if (FLAG_string_slices) { - Label copy_routine; - // a5: underlying subject string - // a1: instance type of underlying subject string - // a2: length - // a3: adjusted start index (untagged) - // Short slice. Copy instead of slicing. - __ Branch(©_routine, lt, a2, Operand(SlicedString::kMinLength)); - // Allocate new sliced string. At this point we do not reload the instance - // type including the string encoding because we simply rely on the info - // provided by the original string. It does not matter if the original - // string's encoding is wrong because we always have to recheck encoding of - // the newly created string's parent anyways due to externalized strings. - Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ And(a4, a1, Operand(kStringEncodingMask)); - __ Branch(&two_byte_slice, eq, a4, Operand(zero_reg)); - __ AllocateOneByteSlicedString(v0, a2, a6, a7, &runtime); - __ jmp(&set_slice_header); - __ bind(&two_byte_slice); - __ AllocateTwoByteSlicedString(v0, a2, a6, a7, &runtime); - __ bind(&set_slice_header); - __ SmiTag(a3); - __ sd(a5, FieldMemOperand(v0, SlicedString::kParentOffset)); - __ sd(a3, FieldMemOperand(v0, SlicedString::kOffsetOffset)); - __ jmp(&return_v0); - - __ bind(©_routine); - } - - // a5: underlying subject string - // a1: instance type of underlying subject string - // a2: length - // a3: adjusted start index (untagged) - Label two_byte_sequential, sequential_string, allocate_result; - STATIC_ASSERT(kExternalStringTag != 0); - STATIC_ASSERT(kSeqStringTag == 0); - __ And(a4, a1, Operand(kExternalStringTag)); - __ Branch(&sequential_string, eq, a4, Operand(zero_reg)); - - // Handle external string. - // Rule out short external strings. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ And(a4, a1, Operand(kShortExternalStringTag)); - __ Branch(&runtime, ne, a4, Operand(zero_reg)); - __ ld(a5, FieldMemOperand(a5, ExternalString::kResourceDataOffset)); - // a5 already points to the first character of underlying string. - __ jmp(&allocate_result); - - __ bind(&sequential_string); - // Locate first character of underlying subject string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); - __ Daddu(a5, a5, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - - __ bind(&allocate_result); - // Sequential acii string. Allocate the result. - STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); - __ And(a4, a1, Operand(kStringEncodingMask)); - __ Branch(&two_byte_sequential, eq, a4, Operand(zero_reg)); - - // Allocate and copy the resulting one_byte string. - __ AllocateOneByteString(v0, a2, a4, a6, a7, &runtime); - - // Locate first character of substring to copy. - __ Daddu(a5, a5, a3); - - // Locate first character of result. - __ Daddu(a1, v0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - - // v0: result string - // a1: first character of result string - // a2: result string length - // a5: first character of substring to copy - STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); - StringHelper::GenerateCopyCharacters( - masm, a1, a5, a2, a3, String::ONE_BYTE_ENCODING); - __ jmp(&return_v0); - - // Allocate and copy the resulting two-byte string. - __ bind(&two_byte_sequential); - __ AllocateTwoByteString(v0, a2, a4, a6, a7, &runtime); - - // Locate first character of substring to copy. - STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); - __ Dlsa(a5, a5, a3, 1); - // Locate first character of result. - __ Daddu(a1, v0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - - // v0: result string. - // a1: first character of result. - // a2: result length. - // a5: first character of substring to copy. - STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); - StringHelper::GenerateCopyCharacters( - masm, a1, a5, a2, a3, String::TWO_BYTE_ENCODING); - - __ bind(&return_v0); - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->sub_string_native(), 1, a3, a4); - __ DropAndRet(3); - - // Just jump to runtime to create the sub string. - __ bind(&runtime); - __ TailCallRuntime(Runtime::kSubString); - - __ bind(&single_char); - // v0: original string - // a1: instance type - // a2: length - // a3: from index (untagged) - __ SmiTag(a3); - StringCharAtGenerator generator(v0, a3, a2, v0, &runtime, &runtime, &runtime, - RECEIVER_IS_STRING); - generator.GenerateFast(masm); - __ DropAndRet(3); - generator.SkipSlow(masm, &runtime); -} - void ToStringStub::Generate(MacroAssembler* masm) { // The ToString stub takes on argument in a0. Label is_number; diff --git a/src/ppc/code-stubs-ppc.cc b/src/ppc/code-stubs-ppc.cc index 82318685df..1a1c28d25c 100644 --- a/src/ppc/code-stubs-ppc.cc +++ b/src/ppc/code-stubs-ppc.cc @@ -2207,230 +2207,6 @@ void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, Register dest, __ bind(&done); } - -void SubStringStub::Generate(MacroAssembler* masm) { - Label runtime; - - // Stack frame on entry. - // lr: return address - // sp[0]: to - // sp[4]: from - // sp[8]: string - - // This stub is called from the native-call %_SubString(...), so - // nothing can be assumed about the arguments. It is tested that: - // "string" is a sequential string, - // both "from" and "to" are smis, and - // 0 <= from <= to <= string.length. - // If any of these assumptions fail, we call the runtime system. - - const int kToOffset = 0 * kPointerSize; - const int kFromOffset = 1 * kPointerSize; - const int kStringOffset = 2 * kPointerSize; - - __ LoadP(r5, MemOperand(sp, kToOffset)); - __ LoadP(r6, MemOperand(sp, kFromOffset)); - - // If either to or from had the smi tag bit set, then fail to generic runtime - __ JumpIfNotSmi(r5, &runtime); - __ JumpIfNotSmi(r6, &runtime); - __ SmiUntag(r5); - __ SmiUntag(r6, SetRC); - // Both r5 and r6 are untagged integers. - - // We want to bailout to runtime here if From is negative. - __ blt(&runtime, cr0); // From < 0. - - __ cmpl(r6, r5); - __ bgt(&runtime); // Fail if from > to. - __ sub(r5, r5, r6); - - // Make sure first argument is a string. - __ LoadP(r3, MemOperand(sp, kStringOffset)); - __ JumpIfSmi(r3, &runtime); - Condition is_string = masm->IsObjectStringType(r3, r4); - __ b(NegateCondition(is_string), &runtime, cr0); - - Label single_char; - __ cmpi(r5, Operand(1)); - __ b(eq, &single_char); - - // Short-cut for the case of trivial substring. - Label return_r3; - // r3: original string - // r5: result string length - __ LoadP(r7, FieldMemOperand(r3, String::kLengthOffset)); - __ SmiUntag(r0, r7); - __ cmpl(r5, r0); - // Return original string. - __ beq(&return_r3); - // Longer than original string's length or negative: unsafe arguments. - __ bgt(&runtime); - // Shorter than original string's length: an actual substring. - - // Deal with different string types: update the index if necessary - // and put the underlying string into r8. - // r3: original string - // r4: instance type - // r5: length - // r6: from index (untagged) - Label underlying_unpacked, sliced_string, seq_or_external_string; - // If the string is not indirect, it can only be sequential or external. - STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); - STATIC_ASSERT(kIsIndirectStringMask != 0); - __ andi(r0, r4, Operand(kIsIndirectStringMask)); - __ beq(&seq_or_external_string, cr0); - - __ andi(r0, r4, Operand(kSlicedNotConsMask)); - __ bne(&sliced_string, cr0); - // Cons string. Check whether it is flat, then fetch first part. - __ LoadP(r8, FieldMemOperand(r3, ConsString::kSecondOffset)); - __ CompareRoot(r8, Heap::kempty_stringRootIndex); - __ bne(&runtime); - __ LoadP(r8, FieldMemOperand(r3, ConsString::kFirstOffset)); - // Update instance type. - __ LoadP(r4, FieldMemOperand(r8, HeapObject::kMapOffset)); - __ lbz(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); - __ b(&underlying_unpacked); - - __ bind(&sliced_string); - // Sliced string. Fetch parent and correct start index by offset. - __ LoadP(r8, FieldMemOperand(r3, SlicedString::kParentOffset)); - __ LoadP(r7, FieldMemOperand(r3, SlicedString::kOffsetOffset)); - __ SmiUntag(r4, r7); - __ add(r6, r6, r4); // Add offset to index. - // Update instance type. - __ LoadP(r4, FieldMemOperand(r8, HeapObject::kMapOffset)); - __ lbz(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); - __ b(&underlying_unpacked); - - __ bind(&seq_or_external_string); - // Sequential or external string. Just move string to the expected register. - __ mr(r8, r3); - - __ bind(&underlying_unpacked); - - if (FLAG_string_slices) { - Label copy_routine; - // r8: underlying subject string - // r4: instance type of underlying subject string - // r5: length - // r6: adjusted start index (untagged) - __ cmpi(r5, Operand(SlicedString::kMinLength)); - // Short slice. Copy instead of slicing. - __ blt(©_routine); - // Allocate new sliced string. At this point we do not reload the instance - // type including the string encoding because we simply rely on the info - // provided by the original string. It does not matter if the original - // string's encoding is wrong because we always have to recheck encoding of - // the newly created string's parent anyways due to externalized strings. - Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ andi(r0, r4, Operand(kStringEncodingMask)); - __ beq(&two_byte_slice, cr0); - __ AllocateOneByteSlicedString(r3, r5, r9, r10, &runtime); - __ b(&set_slice_header); - __ bind(&two_byte_slice); - __ AllocateTwoByteSlicedString(r3, r5, r9, r10, &runtime); - __ bind(&set_slice_header); - __ SmiTag(r6); - __ StoreP(r8, FieldMemOperand(r3, SlicedString::kParentOffset), r0); - __ StoreP(r6, FieldMemOperand(r3, SlicedString::kOffsetOffset), r0); - __ b(&return_r3); - - __ bind(©_routine); - } - - // r8: underlying subject string - // r4: instance type of underlying subject string - // r5: length - // r6: adjusted start index (untagged) - Label two_byte_sequential, sequential_string, allocate_result; - STATIC_ASSERT(kExternalStringTag != 0); - STATIC_ASSERT(kSeqStringTag == 0); - __ andi(r0, r4, Operand(kExternalStringTag)); - __ beq(&sequential_string, cr0); - - // Handle external string. - // Rule out short external strings. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ andi(r0, r4, Operand(kShortExternalStringTag)); - __ bne(&runtime, cr0); - __ LoadP(r8, FieldMemOperand(r8, ExternalString::kResourceDataOffset)); - // r8 already points to the first character of underlying string. - __ b(&allocate_result); - - __ bind(&sequential_string); - // Locate first character of underlying subject string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); - __ addi(r8, r8, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - - __ bind(&allocate_result); - // Sequential acii string. Allocate the result. - STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); - __ andi(r0, r4, Operand(kStringEncodingMask)); - __ beq(&two_byte_sequential, cr0); - - // Allocate and copy the resulting one-byte string. - __ AllocateOneByteString(r3, r5, r7, r9, r10, &runtime); - - // Locate first character of substring to copy. - __ add(r8, r8, r6); - // Locate first character of result. - __ addi(r4, r3, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - - // r3: result string - // r4: first character of result string - // r5: result string length - // r8: first character of substring to copy - STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); - StringHelper::GenerateCopyCharacters(masm, r4, r8, r5, r6, - String::ONE_BYTE_ENCODING); - __ b(&return_r3); - - // Allocate and copy the resulting two-byte string. - __ bind(&two_byte_sequential); - __ AllocateTwoByteString(r3, r5, r7, r9, r10, &runtime); - - // Locate first character of substring to copy. - __ ShiftLeftImm(r4, r6, Operand(1)); - __ add(r8, r8, r4); - // Locate first character of result. - __ addi(r4, r3, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - - // r3: result string. - // r4: first character of result. - // r5: result length. - // r8: first character of substring to copy. - STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); - StringHelper::GenerateCopyCharacters(masm, r4, r8, r5, r6, - String::TWO_BYTE_ENCODING); - - __ bind(&return_r3); - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->sub_string_native(), 1, r6, r7); - __ Drop(3); - __ Ret(); - - // Just jump to runtime to create the sub string. - __ bind(&runtime); - __ TailCallRuntime(Runtime::kSubString); - - __ bind(&single_char); - // r3: original string - // r4: instance type - // r5: length - // r6: from index (untagged) - __ SmiTag(r6, r6); - StringCharAtGenerator generator(r3, r6, r5, r3, &runtime, &runtime, &runtime, - RECEIVER_IS_STRING); - generator.GenerateFast(masm); - __ Drop(3); - __ Ret(); - generator.SkipSlow(masm, &runtime); -} - void ToStringStub::Generate(MacroAssembler* masm) { // The ToString stub takes one argument in r3. Label is_number; diff --git a/src/s390/code-stubs-s390.cc b/src/s390/code-stubs-s390.cc index 111b317bd7..e867bf9e11 100644 --- a/src/s390/code-stubs-s390.cc +++ b/src/s390/code-stubs-s390.cc @@ -2202,235 +2202,6 @@ void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, Register dest, __ bind(&done); } -void SubStringStub::Generate(MacroAssembler* masm) { - Label runtime; - - // Stack frame on entry. - // lr: return address - // sp[0]: to - // sp[4]: from - // sp[8]: string - - // This stub is called from the native-call %_SubString(...), so - // nothing can be assumed about the arguments. It is tested that: - // "string" is a sequential string, - // both "from" and "to" are smis, and - // 0 <= from <= to <= string.length. - // If any of these assumptions fail, we call the runtime system. - - const int kToOffset = 0 * kPointerSize; - const int kFromOffset = 1 * kPointerSize; - const int kStringOffset = 2 * kPointerSize; - - __ LoadP(r4, MemOperand(sp, kToOffset)); - __ LoadP(r5, MemOperand(sp, kFromOffset)); - - // If either to or from had the smi tag bit set, then fail to generic runtime - __ JumpIfNotSmi(r4, &runtime); - __ JumpIfNotSmi(r5, &runtime); - __ SmiUntag(r4); - __ SmiUntag(r5); - // Both r4 and r5 are untagged integers. - - // We want to bailout to runtime here if From is negative. - __ blt(&runtime); // From < 0. - - __ CmpLogicalP(r5, r4); - __ bgt(&runtime); // Fail if from > to. - __ SubP(r4, r4, r5); - - // Make sure first argument is a string. - __ LoadP(r2, MemOperand(sp, kStringOffset)); - __ JumpIfSmi(r2, &runtime); - Condition is_string = masm->IsObjectStringType(r2, r3); - __ b(NegateCondition(is_string), &runtime); - - Label single_char; - __ CmpP(r4, Operand(1)); - __ b(eq, &single_char); - - // Short-cut for the case of trivial substring. - Label return_r2; - // r2: original string - // r4: result string length - __ LoadP(r6, FieldMemOperand(r2, String::kLengthOffset)); - __ SmiUntag(r0, r6); - __ CmpLogicalP(r4, r0); - // Return original string. - __ beq(&return_r2); - // Longer than original string's length or negative: unsafe arguments. - __ bgt(&runtime); - // Shorter than original string's length: an actual substring. - - // Deal with different string types: update the index if necessary - // and put the underlying string into r7. - // r2: original string - // r3: instance type - // r4: length - // r5: from index (untagged) - Label underlying_unpacked, sliced_string, seq_or_external_string; - // If the string is not indirect, it can only be sequential or external. - STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); - STATIC_ASSERT(kIsIndirectStringMask != 0); - __ mov(r0, Operand(kIsIndirectStringMask)); - __ AndP(r0, r3); - __ beq(&seq_or_external_string); - - __ mov(r0, Operand(kSlicedNotConsMask)); - __ AndP(r0, r3); - __ bne(&sliced_string); - // Cons string. Check whether it is flat, then fetch first part. - __ LoadP(r7, FieldMemOperand(r2, ConsString::kSecondOffset)); - __ CompareRoot(r7, Heap::kempty_stringRootIndex); - __ bne(&runtime); - __ LoadP(r7, FieldMemOperand(r2, ConsString::kFirstOffset)); - // Update instance type. - __ LoadP(r3, FieldMemOperand(r7, HeapObject::kMapOffset)); - __ LoadlB(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); - __ b(&underlying_unpacked); - - __ bind(&sliced_string); - // Sliced string. Fetch parent and correct start index by offset. - __ LoadP(r7, FieldMemOperand(r2, SlicedString::kParentOffset)); - __ LoadP(r6, FieldMemOperand(r2, SlicedString::kOffsetOffset)); - __ SmiUntag(r3, r6); - __ AddP(r5, r3); // Add offset to index. - // Update instance type. - __ LoadP(r3, FieldMemOperand(r7, HeapObject::kMapOffset)); - __ LoadlB(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); - __ b(&underlying_unpacked); - - __ bind(&seq_or_external_string); - // Sequential or external string. Just move string to the expected register. - __ LoadRR(r7, r2); - - __ bind(&underlying_unpacked); - - if (FLAG_string_slices) { - Label copy_routine; - // r7: underlying subject string - // r3: instance type of underlying subject string - // r4: length - // r5: adjusted start index (untagged) - __ CmpP(r4, Operand(SlicedString::kMinLength)); - // Short slice. Copy instead of slicing. - __ blt(©_routine); - // Allocate new sliced string. At this point we do not reload the instance - // type including the string encoding because we simply rely on the info - // provided by the original string. It does not matter if the original - // string's encoding is wrong because we always have to recheck encoding of - // the newly created string's parent anyways due to externalized strings. - Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ mov(r0, Operand(kStringEncodingMask)); - __ AndP(r0, r3); - __ beq(&two_byte_slice); - __ AllocateOneByteSlicedString(r2, r4, r8, r9, &runtime); - __ b(&set_slice_header); - __ bind(&two_byte_slice); - __ AllocateTwoByteSlicedString(r2, r4, r8, r9, &runtime); - __ bind(&set_slice_header); - __ SmiTag(r5); - __ StoreP(r7, FieldMemOperand(r2, SlicedString::kParentOffset)); - __ StoreP(r5, FieldMemOperand(r2, SlicedString::kOffsetOffset)); - __ b(&return_r2); - - __ bind(©_routine); - } - - // r7: underlying subject string - // r3: instance type of underlying subject string - // r4: length - // r5: adjusted start index (untagged) - Label two_byte_sequential, sequential_string, allocate_result; - STATIC_ASSERT(kExternalStringTag != 0); - STATIC_ASSERT(kSeqStringTag == 0); - __ mov(r0, Operand(kExternalStringTag)); - __ AndP(r0, r3); - __ beq(&sequential_string); - - // Handle external string. - // Rule out short external strings. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ mov(r0, Operand(kShortExternalStringTag)); - __ AndP(r0, r3); - __ bne(&runtime); - __ LoadP(r7, FieldMemOperand(r7, ExternalString::kResourceDataOffset)); - // r7 already points to the first character of underlying string. - __ b(&allocate_result); - - __ bind(&sequential_string); - // Locate first character of underlying subject string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); - __ AddP(r7, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - - __ bind(&allocate_result); - // Sequential acii string. Allocate the result. - STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); - __ mov(r0, Operand(kStringEncodingMask)); - __ AndP(r0, r3); - __ beq(&two_byte_sequential); - - // Allocate and copy the resulting one-byte string. - __ AllocateOneByteString(r2, r4, r6, r8, r9, &runtime); - - // Locate first character of substring to copy. - __ AddP(r7, r5); - // Locate first character of result. - __ AddP(r3, r2, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - - // r2: result string - // r3: first character of result string - // r4: result string length - // r7: first character of substring to copy - STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); - StringHelper::GenerateCopyCharacters(masm, r3, r7, r4, r5, - String::ONE_BYTE_ENCODING); - __ b(&return_r2); - - // Allocate and copy the resulting two-byte string. - __ bind(&two_byte_sequential); - __ AllocateTwoByteString(r2, r4, r6, r8, r9, &runtime); - - // Locate first character of substring to copy. - __ ShiftLeftP(r3, r5, Operand(1)); - __ AddP(r7, r3); - // Locate first character of result. - __ AddP(r3, r2, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - - // r2: result string. - // r3: first character of result. - // r4: result length. - // r7: first character of substring to copy. - STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); - StringHelper::GenerateCopyCharacters(masm, r3, r7, r4, r5, - String::TWO_BYTE_ENCODING); - - __ bind(&return_r2); - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->sub_string_native(), 1, r5, r6); - __ Drop(3); - __ Ret(); - - // Just jump to runtime to create the sub string. - __ bind(&runtime); - __ TailCallRuntime(Runtime::kSubString); - - __ bind(&single_char); - // r2: original string - // r3: instance type - // r4: length - // r5: from index (untagged) - __ SmiTag(r5, r5); - StringCharAtGenerator generator(r2, r5, r4, r2, &runtime, &runtime, &runtime, - RECEIVER_IS_STRING); - generator.GenerateFast(masm); - __ Drop(3); - __ Ret(); - generator.SkipSlow(masm, &runtime); -} - void ToStringStub::Generate(MacroAssembler* masm) { // The ToString stub takes one argument in r2. Label done; diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 56f208c540..6dddab1f6c 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -2011,227 +2011,6 @@ void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, __ bind(&done); } - -void SubStringStub::Generate(MacroAssembler* masm) { - Label runtime; - - // Stack frame on entry. - // rsp[0] : return address - // rsp[8] : to - // rsp[16] : from - // rsp[24] : string - - enum SubStringStubArgumentIndices { - STRING_ARGUMENT_INDEX, - FROM_ARGUMENT_INDEX, - TO_ARGUMENT_INDEX, - SUB_STRING_ARGUMENT_COUNT - }; - - StackArgumentsAccessor args(rsp, SUB_STRING_ARGUMENT_COUNT, - ARGUMENTS_DONT_CONTAIN_RECEIVER); - - // Make sure first argument is a string. - __ movp(rax, args.GetArgumentOperand(STRING_ARGUMENT_INDEX)); - STATIC_ASSERT(kSmiTag == 0); - __ testl(rax, Immediate(kSmiTagMask)); - __ j(zero, &runtime); - Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); - __ j(NegateCondition(is_string), &runtime); - - // rax: string - // rbx: instance type - // Calculate length of sub string using the smi values. - __ movp(rcx, args.GetArgumentOperand(TO_ARGUMENT_INDEX)); - __ movp(rdx, args.GetArgumentOperand(FROM_ARGUMENT_INDEX)); - __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime); - - __ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen. - __ cmpp(rcx, FieldOperand(rax, String::kLengthOffset)); - Label not_original_string; - // Shorter than original string's length: an actual substring. - __ j(below, ¬_original_string, Label::kNear); - // Longer than original string's length or negative: unsafe arguments. - __ j(above, &runtime); - // Return original string. - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); - __ bind(¬_original_string); - - Label single_char; - __ SmiCompare(rcx, Smi::FromInt(1)); - __ j(equal, &single_char); - - __ SmiToInteger32(rcx, rcx); - - // rax: string - // rbx: instance type - // rcx: sub string length - // rdx: from index (smi) - // Deal with different string types: update the index if necessary - // and put the underlying string into edi. - Label underlying_unpacked, sliced_string, seq_or_external_string; - // If the string is not indirect, it can only be sequential or external. - STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); - STATIC_ASSERT(kIsIndirectStringMask != 0); - __ testb(rbx, Immediate(kIsIndirectStringMask)); - __ j(zero, &seq_or_external_string, Label::kNear); - - __ testb(rbx, Immediate(kSlicedNotConsMask)); - __ j(not_zero, &sliced_string, Label::kNear); - // Cons string. Check whether it is flat, then fetch first part. - // Flat cons strings have an empty second part. - __ CompareRoot(FieldOperand(rax, ConsString::kSecondOffset), - Heap::kempty_stringRootIndex); - __ j(not_equal, &runtime); - __ movp(rdi, FieldOperand(rax, ConsString::kFirstOffset)); - // Update instance type. - __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); - __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); - __ jmp(&underlying_unpacked, Label::kNear); - - __ bind(&sliced_string); - // Sliced string. Fetch parent and correct start index by offset. - __ addp(rdx, FieldOperand(rax, SlicedString::kOffsetOffset)); - __ movp(rdi, FieldOperand(rax, SlicedString::kParentOffset)); - // Update instance type. - __ movp(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); - __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); - __ jmp(&underlying_unpacked, Label::kNear); - - __ bind(&seq_or_external_string); - // Sequential or external string. Just move string to the correct register. - __ movp(rdi, rax); - - __ bind(&underlying_unpacked); - - if (FLAG_string_slices) { - Label copy_routine; - // rdi: underlying subject string - // rbx: instance type of underlying subject string - // rdx: adjusted start index (smi) - // rcx: length - // If coming from the make_two_character_string path, the string - // is too short to be sliced anyways. - __ cmpp(rcx, Immediate(SlicedString::kMinLength)); - // Short slice. Copy instead of slicing. - __ j(less, ©_routine); - // Allocate new sliced string. At this point we do not reload the instance - // type including the string encoding because we simply rely on the info - // provided by the original string. It does not matter if the original - // string's encoding is wrong because we always have to recheck encoding of - // the newly created string's parent anyways due to externalized strings. - Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ testb(rbx, Immediate(kStringEncodingMask)); - __ j(zero, &two_byte_slice, Label::kNear); - __ AllocateOneByteSlicedString(rax, rbx, r14, &runtime); - __ jmp(&set_slice_header, Label::kNear); - __ bind(&two_byte_slice); - __ AllocateTwoByteSlicedString(rax, rbx, r14, &runtime); - __ bind(&set_slice_header); - __ Integer32ToSmi(rcx, rcx); - __ movp(FieldOperand(rax, SlicedString::kLengthOffset), rcx); - __ movp(FieldOperand(rax, SlicedString::kHashFieldOffset), - Immediate(String::kEmptyHashField)); - __ movp(FieldOperand(rax, SlicedString::kParentOffset), rdi); - __ movp(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(3 * kPointerSize); - - __ bind(©_routine); - } - - // rdi: underlying subject string - // rbx: instance type of underlying subject string - // rdx: adjusted start index (smi) - // rcx: length - // The subject string can only be external or sequential string of either - // encoding at this point. - Label two_byte_sequential, sequential_string; - STATIC_ASSERT(kExternalStringTag != 0); - STATIC_ASSERT(kSeqStringTag == 0); - __ testb(rbx, Immediate(kExternalStringTag)); - __ j(zero, &sequential_string); - - // Handle external string. - // Rule out short external strings. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ testb(rbx, Immediate(kShortExternalStringMask)); - __ j(not_zero, &runtime); - __ movp(rdi, FieldOperand(rdi, ExternalString::kResourceDataOffset)); - // Move the pointer so that offset-wise, it looks like a sequential string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); - __ subp(rdi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - - __ bind(&sequential_string); - STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); - __ testb(rbx, Immediate(kStringEncodingMask)); - __ j(zero, &two_byte_sequential); - - // Allocate the result. - __ AllocateOneByteString(rax, rcx, r11, r14, r15, &runtime); - - // rax: result string - // rcx: result string length - { // Locate character of sub string start. - SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_1); - __ leap(r14, Operand(rdi, smi_as_index.reg, smi_as_index.scale, - SeqOneByteString::kHeaderSize - kHeapObjectTag)); - } - // Locate first character of result. - __ leap(rdi, FieldOperand(rax, SeqOneByteString::kHeaderSize)); - - // rax: result string - // rcx: result length - // r14: first character of result - // rsi: character of sub string start - StringHelper::GenerateCopyCharacters( - masm, rdi, r14, rcx, String::ONE_BYTE_ENCODING); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); - - __ bind(&two_byte_sequential); - // Allocate the result. - __ AllocateTwoByteString(rax, rcx, r11, r14, r15, &runtime); - - // rax: result string - // rcx: result string length - { // Locate character of sub string start. - SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_2); - __ leap(r14, Operand(rdi, smi_as_index.reg, smi_as_index.scale, - SeqOneByteString::kHeaderSize - kHeapObjectTag)); - } - // Locate first character of result. - __ leap(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); - - // rax: result string - // rcx: result length - // rdi: first character of result - // r14: character of sub string start - StringHelper::GenerateCopyCharacters( - masm, rdi, r14, rcx, String::TWO_BYTE_ENCODING); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); - - // Just jump to runtime to create the sub string. - __ bind(&runtime); - __ TailCallRuntime(Runtime::kSubString); - - __ bind(&single_char); - // rax: string - // rbx: instance type - // rcx: sub string length (smi) - // rdx: from index (smi) - StringCharAtGenerator generator(rax, rdx, rcx, rax, &runtime, &runtime, - &runtime, RECEIVER_IS_STRING); - generator.GenerateFast(masm); - __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); - generator.SkipSlow(masm, &runtime); -} - void ToStringStub::Generate(MacroAssembler* masm) { // The ToString stub takes one argument in rax. Label is_number; diff --git a/src/x87/code-stubs-x87.cc b/src/x87/code-stubs-x87.cc index 1d72ab3a68..498bd58d5c 100644 --- a/src/x87/code-stubs-x87.cc +++ b/src/x87/code-stubs-x87.cc @@ -1907,227 +1907,6 @@ void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, __ bind(&done); } - -void SubStringStub::Generate(MacroAssembler* masm) { - Label runtime; - - // Stack frame on entry. - // esp[0]: return address - // esp[4]: to - // esp[8]: from - // esp[12]: string - - // Make sure first argument is a string. - __ mov(eax, Operand(esp, 3 * kPointerSize)); - STATIC_ASSERT(kSmiTag == 0); - __ JumpIfSmi(eax, &runtime); - Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); - __ j(NegateCondition(is_string), &runtime); - - // eax: string - // ebx: instance type - - // Calculate length of sub string using the smi values. - __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index. - __ JumpIfNotSmi(ecx, &runtime); - __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index. - __ JumpIfNotSmi(edx, &runtime); - __ sub(ecx, edx); - __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); - Label not_original_string; - // Shorter than original string's length: an actual substring. - __ j(below, ¬_original_string, Label::kNear); - // Longer than original string's length or negative: unsafe arguments. - __ j(above, &runtime); - // Return original string. - Counters* counters = isolate()->counters(); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(3 * kPointerSize); - __ bind(¬_original_string); - - Label single_char; - __ cmp(ecx, Immediate(Smi::FromInt(1))); - __ j(equal, &single_char); - - // eax: string - // ebx: instance type - // ecx: sub string length (smi) - // edx: from index (smi) - // Deal with different string types: update the index if necessary - // and put the underlying string into edi. - Label underlying_unpacked, sliced_string, seq_or_external_string; - // If the string is not indirect, it can only be sequential or external. - STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); - STATIC_ASSERT(kIsIndirectStringMask != 0); - __ test(ebx, Immediate(kIsIndirectStringMask)); - __ j(zero, &seq_or_external_string, Label::kNear); - - Factory* factory = isolate()->factory(); - __ test(ebx, Immediate(kSlicedNotConsMask)); - __ j(not_zero, &sliced_string, Label::kNear); - // Cons string. Check whether it is flat, then fetch first part. - // Flat cons strings have an empty second part. - __ cmp(FieldOperand(eax, ConsString::kSecondOffset), - factory->empty_string()); - __ j(not_equal, &runtime); - __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset)); - // Update instance type. - __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); - __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); - __ jmp(&underlying_unpacked, Label::kNear); - - __ bind(&sliced_string); - // Sliced string. Fetch parent and adjust start index by offset. - __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset)); - __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset)); - // Update instance type. - __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); - __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); - __ jmp(&underlying_unpacked, Label::kNear); - - __ bind(&seq_or_external_string); - // Sequential or external string. Just move string to the expected register. - __ mov(edi, eax); - - __ bind(&underlying_unpacked); - - if (FLAG_string_slices) { - Label copy_routine; - // edi: underlying subject string - // ebx: instance type of underlying subject string - // edx: adjusted start index (smi) - // ecx: length (smi) - __ cmp(ecx, Immediate(Smi::FromInt(SlicedString::kMinLength))); - // Short slice. Copy instead of slicing. - __ j(less, ©_routine); - // Allocate new sliced string. At this point we do not reload the instance - // type including the string encoding because we simply rely on the info - // provided by the original string. It does not matter if the original - // string's encoding is wrong because we always have to recheck encoding of - // the newly created string's parent anyways due to externalized strings. - Label two_byte_slice, set_slice_header; - STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); - STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); - __ test(ebx, Immediate(kStringEncodingMask)); - __ j(zero, &two_byte_slice, Label::kNear); - __ AllocateOneByteSlicedString(eax, ebx, no_reg, &runtime); - __ jmp(&set_slice_header, Label::kNear); - __ bind(&two_byte_slice); - __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime); - __ bind(&set_slice_header); - __ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx); - __ mov(FieldOperand(eax, SlicedString::kHashFieldOffset), - Immediate(String::kEmptyHashField)); - __ mov(FieldOperand(eax, SlicedString::kParentOffset), edi); - __ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(3 * kPointerSize); - - __ bind(©_routine); - } - - // edi: underlying subject string - // ebx: instance type of underlying subject string - // edx: adjusted start index (smi) - // ecx: length (smi) - // The subject string can only be external or sequential string of either - // encoding at this point. - Label two_byte_sequential, runtime_drop_two, sequential_string; - STATIC_ASSERT(kExternalStringTag != 0); - STATIC_ASSERT(kSeqStringTag == 0); - __ test_b(ebx, Immediate(kExternalStringTag)); - __ j(zero, &sequential_string); - - // Handle external string. - // Rule out short external strings. - STATIC_ASSERT(kShortExternalStringTag != 0); - __ test_b(ebx, Immediate(kShortExternalStringMask)); - __ j(not_zero, &runtime); - __ mov(edi, FieldOperand(edi, ExternalString::kResourceDataOffset)); - // Move the pointer so that offset-wise, it looks like a sequential string. - STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); - __ sub(edi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - - __ bind(&sequential_string); - // Stash away (adjusted) index and (underlying) string. - __ push(edx); - __ push(edi); - __ SmiUntag(ecx); - STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0); - __ test_b(ebx, Immediate(kStringEncodingMask)); - __ j(zero, &two_byte_sequential); - - // Sequential one byte string. Allocate the result. - __ AllocateOneByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two); - - // eax: result string - // ecx: result string length - // Locate first character of result. - __ mov(edi, eax); - __ add(edi, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); - // Load string argument and locate character of sub string start. - __ pop(edx); - __ pop(ebx); - __ SmiUntag(ebx); - __ lea(edx, FieldOperand(edx, ebx, times_1, SeqOneByteString::kHeaderSize)); - - // eax: result string - // ecx: result length - // edi: first character of result - // edx: character of sub string start - StringHelper::GenerateCopyCharacters( - masm, edi, edx, ecx, ebx, String::ONE_BYTE_ENCODING); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(3 * kPointerSize); - - __ bind(&two_byte_sequential); - // Sequential two-byte string. Allocate the result. - __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two); - - // eax: result string - // ecx: result string length - // Locate first character of result. - __ mov(edi, eax); - __ add(edi, - Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); - // Load string argument and locate character of sub string start. - __ pop(edx); - __ pop(ebx); - // As from is a smi it is 2 times the value which matches the size of a two - // byte character. - STATIC_ASSERT(kSmiTag == 0); - STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); - __ lea(edx, FieldOperand(edx, ebx, times_1, SeqTwoByteString::kHeaderSize)); - - // eax: result string - // ecx: result length - // edi: first character of result - // edx: character of sub string start - StringHelper::GenerateCopyCharacters( - masm, edi, edx, ecx, ebx, String::TWO_BYTE_ENCODING); - __ IncrementCounter(counters->sub_string_native(), 1); - __ ret(3 * kPointerSize); - - // Drop pushed values on the stack before tail call. - __ bind(&runtime_drop_two); - __ Drop(2); - - // Just jump to runtime to create the sub string. - __ bind(&runtime); - __ TailCallRuntime(Runtime::kSubString); - - __ bind(&single_char); - // eax: string - // ebx: instance type - // ecx: sub string length (smi) - // edx: from index (smi) - StringCharAtGenerator generator(eax, edx, ecx, eax, &runtime, &runtime, - &runtime, RECEIVER_IS_STRING); - generator.GenerateFast(masm); - __ ret(3 * kPointerSize); - generator.SkipSlow(masm, &runtime); -} - void ToStringStub::Generate(MacroAssembler* masm) { // The ToString stub takes one argument in eax. Label is_number;