3457
3457
void MathPowStub::Generate(MacroAssembler* masm) {
3460
if (CpuFeatures::IsSupported(VFP3)) {
3461
CpuFeatures::Scope scope(VFP3);
3464
Label exponent_not_smi;
3465
Label convert_exponent;
3467
const Register base = r0;
3468
const Register exponent = r1;
3469
const Register heapnumbermap = r5;
3470
const Register heapnumber = r6;
3471
const DoubleRegister double_base = d0;
3472
const DoubleRegister double_exponent = d1;
3473
const DoubleRegister double_result = d2;
3474
const SwVfpRegister single_scratch = s0;
3475
const Register scratch = r9;
3476
const Register scratch2 = r7;
3478
__ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
3458
CpuFeatures::Scope vfp3_scope(VFP3);
3459
const Register base = r1;
3460
const Register exponent = r2;
3461
const Register heapnumbermap = r5;
3462
const Register heapnumber = r0;
3463
const DoubleRegister double_base = d1;
3464
const DoubleRegister double_exponent = d2;
3465
const DoubleRegister double_result = d3;
3466
const DoubleRegister double_scratch = d0;
3467
const SwVfpRegister single_scratch = s0;
3468
const Register scratch = r9;
3469
const Register scratch2 = r7;
3471
Label call_runtime, done, exponent_not_smi, int_exponent;
3472
if (exponent_type_ == ON_STACK) {
3473
Label base_is_smi, unpack_exponent;
3474
// The exponent and base are supplied as arguments on the stack.
3475
// This can only happen if the stub is called from non-optimized code.
3476
// Load input parameters from stack to double registers.
3479
3477
__ ldr(base, MemOperand(sp, 1 * kPointerSize));
3480
3478
__ ldr(exponent, MemOperand(sp, 0 * kPointerSize));
3482
// Convert base to double value and store it in d0.
3483
__ JumpIfNotSmi(base, &base_not_smi);
3484
// Base is a Smi. Untag and convert it.
3480
__ LoadRoot(heapnumbermap, Heap::kHeapNumberMapRootIndex);
3482
__ JumpIfSmi(base, &base_is_smi);
3483
__ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset));
3484
__ cmp(scratch, heapnumbermap);
3485
__ b(ne, &call_runtime);
3487
__ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
3488
__ jmp(&unpack_exponent);
3490
__ bind(&base_is_smi);
3485
3491
__ SmiUntag(base);
3486
3492
__ vmov(single_scratch, base);
3487
3493
__ vcvt_f64_s32(double_base, single_scratch);
3488
__ b(&convert_exponent);
3490
__ bind(&base_not_smi);
3491
__ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset));
3492
__ cmp(scratch, heapnumbermap);
3493
__ b(ne, &call_runtime);
3494
// Base is a heapnumber. Load it into double register.
3495
__ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
3497
__ bind(&convert_exponent);
3494
__ bind(&unpack_exponent);
3498
3496
__ JumpIfNotSmi(exponent, &exponent_not_smi);
3499
3497
__ SmiUntag(exponent);
3501
// The base is in a double register and the exponent is
3502
// an untagged smi. Allocate a heap number and call a
3503
// C function for integer exponents. The register containing
3504
// the heap number is callee-saved.
3505
__ AllocateHeapNumber(heapnumber,
3511
__ PrepareCallCFunction(1, 1, scratch);
3512
__ SetCallCDoubleArguments(double_base, exponent);
3514
AllowExternalCallThatCantCauseGC scope(masm);
3516
ExternalReference::power_double_int_function(masm->isolate()),
3519
__ GetCFunctionDoubleResult(double_result);
3521
__ vstr(double_result,
3522
FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
3523
__ mov(r0, heapnumber);
3524
__ Ret(2 * kPointerSize);
3498
__ jmp(&int_exponent);
3526
3500
__ bind(&exponent_not_smi);
3527
3501
__ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset));
3528
3502
__ cmp(scratch, heapnumbermap);
3529
3503
__ b(ne, &call_runtime);
3530
// Exponent is a heapnumber. Load it into double register.
3531
__ vldr(double_exponent,
3532
FieldMemOperand(exponent, HeapNumber::kValueOffset));
3534
// The base and the exponent are in double registers.
3535
// Allocate a heap number and call a C function for
3536
// double exponents. The register containing
3537
// the heap number is callee-saved.
3538
__ AllocateHeapNumber(heapnumber,
3504
__ vldr(double_exponent,
3505
FieldMemOperand(exponent, HeapNumber::kValueOffset));
3506
} else if (exponent_type_ == TAGGED) {
3507
// Base is already in double_base.
3508
__ JumpIfNotSmi(exponent, &exponent_not_smi);
3509
__ SmiUntag(exponent);
3510
__ jmp(&int_exponent);
3512
__ bind(&exponent_not_smi);
3513
__ vldr(double_exponent,
3514
FieldMemOperand(exponent, HeapNumber::kValueOffset));
3517
if (exponent_type_ != INTEGER) {
3518
Label int_exponent_convert;
3519
// Detect integer exponents stored as double.
3520
__ vcvt_u32_f64(single_scratch, double_exponent);
3521
// We do not check for NaN or Infinity here because comparing numbers on
3522
// ARM correctly distinguishes NaNs. We end up calling the built-in.
3523
__ vcvt_f64_u32(double_scratch, single_scratch);
3524
__ VFPCompareAndSetFlags(double_scratch, double_exponent);
3525
__ b(eq, &int_exponent_convert);
3527
if (exponent_type_ == ON_STACK) {
3528
// Detect square root case. Crankshaft detects constant +/-0.5 at
3529
// compile time and uses DoMathPowHalf instead. We then skip this check
3530
// for non-constant cases of +/-0.5 as these hardly occur.
3531
Label not_plus_half;
3534
__ vmov(double_scratch, 0.5);
3535
__ VFPCompareAndSetFlags(double_exponent, double_scratch);
3536
__ b(ne, ¬_plus_half);
3538
// Calculates square root of base. Check for the special case of
3539
// Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13).
3540
__ vmov(double_scratch, -V8_INFINITY);
3541
__ VFPCompareAndSetFlags(double_base, double_scratch);
3542
__ vneg(double_result, double_scratch, eq);
3545
// Add +0 to convert -0 to +0.
3546
__ vadd(double_scratch, double_base, kDoubleRegZero);
3547
__ vsqrt(double_result, double_scratch);
3550
__ bind(¬_plus_half);
3551
__ vmov(double_scratch, -0.5);
3552
__ VFPCompareAndSetFlags(double_exponent, double_scratch);
3553
__ b(ne, &call_runtime);
3555
// Calculates square root of base. Check for the special case of
3556
// Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13).
3557
__ vmov(double_scratch, -V8_INFINITY);
3558
__ VFPCompareAndSetFlags(double_base, double_scratch);
3559
__ vmov(double_result, kDoubleRegZero, eq);
3562
// Add +0 to convert -0 to +0.
3563
__ vadd(double_scratch, double_base, kDoubleRegZero);
3564
__ vmov(double_result, 1);
3565
__ vsqrt(double_scratch, double_scratch);
3566
__ vdiv(double_result, double_result, double_scratch);
3544
__ PrepareCallCFunction(0, 2, scratch);
3545
__ SetCallCDoubleArguments(double_base, double_exponent);
3547
3572
AllowExternalCallThatCantCauseGC scope(masm);
3573
__ PrepareCallCFunction(0, 2, scratch);
3574
__ SetCallCDoubleArguments(double_base, double_exponent);
3548
3575
__ CallCFunction(
3549
3576
ExternalReference::power_double_double_function(masm->isolate()),
3552
__ GetCFunctionDoubleResult(double_result);
3580
__ GetCFunctionDoubleResult(double_result);
3583
__ bind(&int_exponent_convert);
3584
__ vcvt_u32_f64(single_scratch, double_exponent);
3585
__ vmov(exponent, single_scratch);
3588
// Calculate power with integer exponent.
3589
__ bind(&int_exponent);
3591
__ mov(scratch, exponent); // Back up exponent.
3592
__ vmov(double_scratch, double_base); // Back up base.
3593
__ vmov(double_result, 1.0);
3595
// Get absolute value of exponent.
3596
__ cmp(scratch, Operand(0));
3597
__ mov(scratch2, Operand(0), LeaveCC, mi);
3598
__ sub(scratch, scratch2, scratch, LeaveCC, mi);
3601
__ bind(&while_true);
3602
__ mov(scratch, Operand(scratch, ASR, 1), SetCC);
3603
__ vmul(double_result, double_result, double_scratch, cs);
3604
__ vmul(double_scratch, double_scratch, double_scratch, ne);
3605
__ b(ne, &while_true);
3607
__ cmp(exponent, Operand(0));
3609
__ vmov(double_scratch, 1.0);
3610
__ vdiv(double_result, double_scratch, double_result);
3611
// Test whether result is zero. Bail out to check for subnormal result.
3612
// Due to subnormals, x^-y == (1/x)^y does not hold in all cases.
3613
__ VFPCompareAndSetFlags(double_result, 0.0);
3615
// double_exponent may not containe the exponent value if the input was a
3616
// smi. We set it with exponent value before bailing out.
3617
__ vmov(single_scratch, exponent);
3618
__ vcvt_f64_s32(double_exponent, single_scratch);
3620
// Returning or bailing out.
3621
Counters* counters = masm->isolate()->counters();
3622
if (exponent_type_ == ON_STACK) {
3623
// The arguments are still on the stack.
3624
__ bind(&call_runtime);
3625
__ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3627
// The stub is called from non-optimized code, which expects the result
3628
// as heap number in exponent.
3630
__ AllocateHeapNumber(
3631
heapnumber, scratch, scratch2, heapnumbermap, &call_runtime);
3554
3632
__ vstr(double_result,
3555
3633
FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
3556
__ mov(r0, heapnumber);
3557
__ Ret(2 * kPointerSize);
3634
ASSERT(heapnumber.is(r0));
3635
__ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
3640
AllowExternalCallThatCantCauseGC scope(masm);
3641
__ PrepareCallCFunction(0, 2, scratch);
3642
__ SetCallCDoubleArguments(double_base, double_exponent);
3644
ExternalReference::power_double_double_function(masm->isolate()),
3648
__ GetCFunctionDoubleResult(double_result);
3651
__ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
3560
__ bind(&call_runtime);
3561
__ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
5694
5789
static const int kFromOffset = 1 * kPointerSize;
5695
5790
static const int kStringOffset = 2 * kPointerSize;
5697
// Check bounds and smi-ness.
5701
__ Ldrd(to, from, MemOperand(sp, kToOffset));
5792
__ Ldrd(r2, r3, MemOperand(sp, kToOffset));
5702
5793
STATIC_ASSERT(kFromOffset == kToOffset + 4);
5703
5794
STATIC_ASSERT(kSmiTag == 0);
5704
5795
STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
5706
5797
// I.e., arithmetic shift right by one un-smi-tags.
5707
__ mov(r2, Operand(to, ASR, 1), SetCC);
5708
__ mov(r3, Operand(from, ASR, 1), SetCC, cc);
5798
__ mov(r2, Operand(r2, ASR, 1), SetCC);
5799
__ mov(r3, Operand(r3, ASR, 1), SetCC, cc);
5709
5800
// If either to or from had the smi tag bit set, then carry is set now.
5710
5801
__ b(cs, &runtime); // Either "from" or "to" is not a smi.
5711
5802
__ b(mi, &runtime); // From is negative.
5713
// Both to and from are smis.
5804
// Both r2 and r3 are untagged integers.
5714
5805
__ sub(r2, r2, Operand(r3), SetCC);
5715
5806
__ b(mi, &runtime); // Fail if from > to.
5716
// Special handling of sub-strings of length 1 and 2. One character strings
5717
// are handled in the runtime system (looked up in the single character
5718
// cache). Two character strings are looked for in the symbol cache in
5720
__ cmp(r2, Operand(2));
5723
// r2: result string length
5724
// r3: from index (untagged smi)
5725
// r6 (a.k.a. to): to (smi)
5726
// r7 (a.k.a. from): from offset (smi)
5727
// Make sure first argument is a sequential (or flat) string.
5808
// Make sure first argument is a string.
5728
5809
__ ldr(r0, MemOperand(sp, kStringOffset));
5729
5810
STATIC_ASSERT(kSmiTag == 0);
5730
5811
__ JumpIfSmi(r0, &runtime);
5739
5820
__ cmp(r2, Operand(r4, ASR, 1));
5740
5821
__ b(eq, &return_r0);
5743
if (FLAG_string_slices) {
5744
__ cmp(r2, Operand(SlicedString::kMinLength));
5745
__ b(ge, &create_slice);
5748
// r0: original string
5749
// r1: instance type
5750
// r2: result string length
5751
// r3: from index (untagged smi)
5752
// r6 (a.k.a. to): to (smi)
5753
// r7 (a.k.a. from): from offset (smi)
5755
__ and_(r4, r1, Operand(kStringRepresentationMask));
5756
STATIC_ASSERT(kSeqStringTag < kConsStringTag);
5757
STATIC_ASSERT(kConsStringTag < kExternalStringTag);
5758
STATIC_ASSERT(kConsStringTag < kSlicedStringTag);
5759
__ cmp(r4, Operand(kConsStringTag));
5760
__ b(gt, &runtime); // Slices and external strings go to runtime.
5761
__ b(lt, &seq_string); // Sequential strings are handled directly.
5763
// Cons string. Try to recurse (once) on the first substring.
5764
// (This adds a little more generality than necessary to handle flattened
5765
// cons strings, but not much).
5766
__ ldr(r0, FieldMemOperand(r0, ConsString::kFirstOffset));
5767
__ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
5768
__ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset));
5769
__ tst(r1, Operand(kStringRepresentationMask));
5770
STATIC_ASSERT(kSeqStringTag == 0);
5771
__ b(ne, &runtime); // Cons, slices and external strings go to runtime.
5773
// Definitly a sequential string.
5774
__ bind(&seq_string);
5776
// r0: original string
5777
// r1: instance type
5778
// r2: result string length
5779
// r3: from index (untagged smi)
5780
// r6 (a.k.a. to): to (smi)
5781
// r7 (a.k.a. from): from offset (smi)
5782
__ ldr(r4, FieldMemOperand(r0, String::kLengthOffset));
5783
__ cmp(r4, Operand(to));
5784
__ b(lt, &runtime); // Fail if to > length.
5787
// r0: original string or left hand side of the original cons string.
5788
// r1: instance type
5789
// r2: result string length
5790
// r3: from index (untagged smi)
5791
// r7 (a.k.a. from): from offset (smi)
5792
// Check for flat ASCII string.
5793
Label non_ascii_flat;
5794
__ tst(r1, Operand(kStringEncodingMask));
5795
STATIC_ASSERT(kTwoByteStringTag == 0);
5796
__ b(eq, &non_ascii_flat);
5798
5823
Label result_longer_than_two;
5824
// Check for special case of two character ASCII string, in which case
5825
// we do a lookup in the symbol table first.
5799
5826
__ cmp(r2, Operand(2));
5800
5827
__ b(gt, &result_longer_than_two);
5802
// Sub string of length 2 requested.
5830
__ JumpIfInstanceTypeIsNotSequentialAscii(r1, r1, &runtime);
5803
5832
// Get the two characters forming the sub string.
5804
5833
__ add(r0, r0, Operand(r3));
5805
5834
__ ldrb(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
5820
5848
__ jmp(&return_r0);
5822
5850
__ bind(&result_longer_than_two);
5824
// Locate 'from' character of string.
5825
__ add(r5, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5826
__ add(r5, r5, Operand(from, ASR, 1));
5828
// Allocate the result.
5829
__ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime);
5831
// r0: result string
5832
// r2: result string length
5833
// r5: first character of substring to copy
5834
// r7 (a.k.a. from): from offset (smi)
5835
// Locate first character of result.
5836
__ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5838
// r0: result string
5839
// r1: first character of result string
5840
// r2: result string length
5841
// r5: first character of substring to copy
5842
STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
5843
StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
5844
COPY_ASCII | DEST_ALWAYS_ALIGNED);
5847
__ bind(&non_ascii_flat);
5851
// Deal with different string types: update the index if necessary
5852
// and put the underlying string into r5.
5848
5853
// r0: original string
5849
// r2: result string length
5850
// r7 (a.k.a. from): from offset (smi)
5851
// Check for flat two byte string.
5853
// Locate 'from' character of string.
5854
__ add(r5, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
5855
// As "from" is a smi it is 2 times the value which matches the size of a two
5857
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
5858
__ add(r5, r5, Operand(from));
5860
// Allocate the result.
5861
__ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime);
5863
// r0: result string
5864
// r2: result string length
5865
// r5: first character of substring to copy
5866
// Locate first character of result.
5867
__ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
5871
// r0: result string.
5872
// r1: first character of result.
5873
// r2: result length.
5874
// r5: first character of substring to copy.
5875
STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
5876
StringHelper::GenerateCopyCharactersLong(
5877
masm, r1, r5, r2, r3, r4, r6, r7, r9, DEST_ALWAYS_ALIGNED);
5854
// r1: instance type
5856
// r3: from index (untagged)
5857
Label underlying_unpacked, sliced_string, seq_or_external_string;
5858
// If the string is not indirect, it can only be sequential or external.
5859
STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
5860
STATIC_ASSERT(kIsIndirectStringMask != 0);
5861
__ tst(r1, Operand(kIsIndirectStringMask));
5862
__ b(eq, &seq_or_external_string);
5864
__ tst(r1, Operand(kSlicedNotConsMask));
5865
__ b(ne, &sliced_string);
5866
// Cons string. Check whether it is flat, then fetch first part.
5867
__ ldr(r5, FieldMemOperand(r0, ConsString::kSecondOffset));
5868
__ CompareRoot(r5, Heap::kEmptyStringRootIndex);
5870
__ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset));
5871
// Update instance type.
5872
__ ldr(r1, FieldMemOperand(r5, HeapObject::kMapOffset));
5873
__ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
5874
__ jmp(&underlying_unpacked);
5876
__ bind(&sliced_string);
5877
// Sliced string. Fetch parent and correct start index by offset.
5878
__ ldr(r5, FieldMemOperand(r0, SlicedString::kOffsetOffset));
5879
__ add(r3, r3, Operand(r5, ASR, 1));
5880
__ ldr(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
5881
// Update instance type.
5882
__ ldr(r1, FieldMemOperand(r5, HeapObject::kMapOffset));
5883
__ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
5884
__ jmp(&underlying_unpacked);
5886
__ bind(&seq_or_external_string);
5887
// Sequential or external string. Just move string to the expected register.
5890
__ bind(&underlying_unpacked);
5880
5892
if (FLAG_string_slices) {
5881
__ bind(&create_slice);
5882
// r0: original string
5883
// r1: instance type
5885
// r3: from index (untagged smi)
5886
// r6 (a.k.a. to): to (smi)
5887
// r7 (a.k.a. from): from offset (smi)
5888
Label allocate_slice, sliced_string, seq_or_external_string;
5889
// If the string is not indirect, it can only be sequential or external.
5890
STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
5891
STATIC_ASSERT(kIsIndirectStringMask != 0);
5892
__ tst(r1, Operand(kIsIndirectStringMask));
5893
__ b(eq, &seq_or_external_string);
5895
__ tst(r1, Operand(kSlicedNotConsMask));
5896
__ b(ne, &sliced_string);
5897
// Cons string. Check whether it is flat, then fetch first part.
5898
__ ldr(r5, FieldMemOperand(r0, ConsString::kSecondOffset));
5899
__ LoadRoot(r9, Heap::kEmptyStringRootIndex);
5902
__ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset));
5903
__ jmp(&allocate_slice);
5905
__ bind(&sliced_string);
5906
// Sliced string. Fetch parent and correct start index by offset.
5907
__ ldr(r5, FieldMemOperand(r0, SlicedString::kOffsetOffset));
5909
__ ldr(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
5910
__ jmp(&allocate_slice);
5912
__ bind(&seq_or_external_string);
5913
// Sequential or external string. Just move string to the correct register.
5916
__ bind(&allocate_slice);
5917
// r1: instance type of original string
5919
5894
// r5: underlying subject string
5920
// r7 (a.k.a. from): from offset (smi)
5895
// r1: instance type of underlying subject string
5897
// r3: adjusted start index (untagged)
5898
__ cmp(r2, Operand(SlicedString::kMinLength));
5899
// Short slice. Copy instead of slicing.
5900
__ b(lt, ©_routine);
5921
5901
// Allocate new sliced string. At this point we do not reload the instance
5922
5902
// type including the string encoding because we simply rely on the info
5923
5903
// provided by the original string. It does not matter if the original
5928
5908
STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
5929
5909
__ tst(r1, Operand(kStringEncodingMask));
5930
5910
__ b(eq, &two_byte_slice);
5931
__ AllocateAsciiSlicedString(r0, r2, r3, r4, &runtime);
5911
__ AllocateAsciiSlicedString(r0, r2, r6, r7, &runtime);
5932
5912
__ jmp(&set_slice_header);
5933
5913
__ bind(&two_byte_slice);
5934
__ AllocateTwoByteSlicedString(r0, r2, r3, r4, &runtime);
5914
__ AllocateTwoByteSlicedString(r0, r2, r6, r7, &runtime);
5935
5915
__ bind(&set_slice_header);
5936
__ str(r7, FieldMemOperand(r0, SlicedString::kOffsetOffset));
5916
__ mov(r3, Operand(r3, LSL, 1));
5917
__ str(r3, FieldMemOperand(r0, SlicedString::kOffsetOffset));
5937
5918
__ str(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
5921
__ bind(©_routine);
5924
// r5: underlying subject string
5925
// r1: instance type of underlying subject string
5927
// r3: adjusted start index (untagged)
5928
Label two_byte_sequential, sequential_string, allocate_result;
5929
STATIC_ASSERT(kExternalStringTag != 0);
5930
STATIC_ASSERT(kSeqStringTag == 0);
5931
__ tst(r1, Operand(kExternalStringTag));
5932
__ b(eq, &sequential_string);
5934
// Handle external string.
5935
// Rule out short external strings.
5936
STATIC_CHECK(kShortExternalStringTag != 0);
5937
__ tst(r1, Operand(kShortExternalStringTag));
5939
__ ldr(r5, FieldMemOperand(r5, ExternalString::kResourceDataOffset));
5940
// r5 already points to the first character of underlying string.
5941
__ jmp(&allocate_result);
5943
__ bind(&sequential_string);
5944
// Locate first character of underlying subject string.
5945
STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5946
__ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5948
__ bind(&allocate_result);
5949
// Sequential acii string. Allocate the result.
5950
STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0);
5951
__ tst(r1, Operand(kStringEncodingMask));
5952
__ b(eq, &two_byte_sequential);
5954
// Allocate and copy the resulting ASCII string.
5955
__ AllocateAsciiString(r0, r2, r4, r6, r7, &runtime);
5957
// Locate first character of substring to copy.
5959
// Locate first character of result.
5960
__ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5962
// r0: result string
5963
// r1: first character of result string
5964
// r2: result string length
5965
// r5: first character of substring to copy
5966
STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0);
5967
StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9,
5968
COPY_ASCII | DEST_ALWAYS_ALIGNED);
5971
// Allocate and copy the resulting two-byte string.
5972
__ bind(&two_byte_sequential);
5973
__ AllocateTwoByteString(r0, r2, r4, r6, r7, &runtime);
5975
// Locate first character of substring to copy.
5976
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
5977
__ add(r5, r5, Operand(r3, LSL, 1));
5978
// Locate first character of result.
5979
__ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
5981
// r0: result string.
5982
// r1: first character of result.
5983
// r2: result length.
5984
// r5: first character of substring to copy.
5985
STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
5986
StringHelper::GenerateCopyCharactersLong(
5987
masm, r1, r5, r2, r3, r4, r6, r7, r9, DEST_ALWAYS_ALIGNED);
5940
5989
__ bind(&return_r0);
5990
Counters* counters = masm->isolate()->counters();
5941
5991
__ IncrementCounter(counters->sub_string_native(), 1, r3, r4);
5942
5992
__ add(sp, sp, Operand(3 * kPointerSize));
6287
6340
__ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
6288
6341
__ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
6290
// Check that both strings are sequential.
6344
// Check whether both strings have same encoding
6345
__ eor(r7, r4, Operand(r5));
6346
__ tst(r7, Operand(kStringEncodingMask));
6347
__ b(ne, &call_runtime);
6291
6349
STATIC_ASSERT(kSeqStringTag == 0);
6292
6350
__ tst(r4, Operand(kStringRepresentationMask));
6293
__ tst(r5, Operand(kStringRepresentationMask), eq);
6294
__ b(ne, &string_add_runtime);
6295
// Now check if both strings have the same encoding (ASCII/Two-byte).
6296
// r0: first string.
6297
// r1: second string.
6298
// r2: length of first string.
6299
// r3: length of second string.
6300
// r6: sum of lengths..
6351
STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
6354
Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag),
6357
__ b(eq, &first_prepared);
6358
// External string: rule out short external string and load string resource.
6359
STATIC_ASSERT(kShortExternalStringTag != 0);
6360
__ tst(r4, Operand(kShortExternalStringMask));
6361
__ b(ne, &call_runtime);
6362
__ ldr(r7, FieldMemOperand(r0, ExternalString::kResourceDataOffset));
6363
__ bind(&first_prepared);
6365
STATIC_ASSERT(kSeqStringTag == 0);
6366
__ tst(r5, Operand(kStringRepresentationMask));
6367
STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
6370
Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag),
6373
__ b(eq, &second_prepared);
6374
// External string: rule out short external string and load string resource.
6375
STATIC_ASSERT(kShortExternalStringTag != 0);
6376
__ tst(r5, Operand(kShortExternalStringMask));
6377
__ b(ne, &call_runtime);
6378
__ ldr(r1, FieldMemOperand(r1, ExternalString::kResourceDataOffset));
6379
__ bind(&second_prepared);
6301
6381
Label non_ascii_string_add_flat_result;
6302
ASSERT(IsPowerOf2(kStringEncodingMask)); // Just one bit to test.
6303
__ eor(r7, r4, Operand(r5));
6304
__ tst(r7, Operand(kStringEncodingMask));
6305
__ b(ne, &string_add_runtime);
6306
// And see if it's ASCII or two-byte.
6307
__ tst(r4, Operand(kStringEncodingMask));
6382
// r7: first character of first string
6383
// r1: first character of second string
6384
// r2: length of first string.
6385
// r3: length of second string.
6386
// r6: sum of lengths.
6387
// Both strings have the same encoding.
6388
STATIC_ASSERT(kTwoByteStringTag == 0);
6389
__ tst(r5, Operand(kStringEncodingMask));
6308
6390
__ b(eq, &non_ascii_string_add_flat_result);
6310
// Both strings are sequential ASCII strings. We also know that they are
6311
// short (since the sum of the lengths is less than kMinNonFlatLength).
6312
// r6: length of resulting flat string
6313
__ AllocateAsciiString(r7, r6, r4, r5, r9, &string_add_runtime);
6314
// Locate first character of result.
6315
__ add(r6, r7, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
6316
// Locate first character of first argument.
6317
__ add(r0, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
6318
// r0: first character of first string.
6319
// r1: second string.
6392
__ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime);
6393
__ add(r6, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
6394
// r0: result string.
6395
// r7: first character of first string.
6396
// r1: first character of second string.
6320
6397
// r2: length of first string.
6321
6398
// r3: length of second string.
6322
6399
// r6: first character of result.
6323
// r7: result string.
6324
StringHelper::GenerateCopyCharacters(masm, r6, r0, r2, r4, true);
6326
// Load second argument and locate first character.
6327
__ add(r1, r1, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
6328
// r1: first character of second string.
6329
// r3: length of second string.
6400
StringHelper::GenerateCopyCharacters(masm, r6, r7, r2, r4, true);
6330
6401
// r6: next character of result.
6331
// r7: result string.
6332
6402
StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, true);
6333
__ mov(r0, Operand(r7));
6334
6403
__ IncrementCounter(counters->string_add_native(), 1, r2, r3);
6335
6404
__ add(sp, sp, Operand(2 * kPointerSize));
6338
6407
__ bind(&non_ascii_string_add_flat_result);
6339
// Both strings are sequential two byte strings.
6340
// r0: first string.
6341
// r1: second string.
6342
// r2: length of first string.
6343
// r3: length of second string.
6344
// r6: sum of length of strings.
6345
__ AllocateTwoByteString(r7, r6, r4, r5, r9, &string_add_runtime);
6346
// r0: first string.
6347
// r1: second string.
6348
// r2: length of first string.
6349
// r3: length of second string.
6350
// r7: result string.
6352
// Locate first character of result.
6353
__ add(r6, r7, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
6354
// Locate first character of first argument.
6355
__ add(r0, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
6357
// r0: first character of first string.
6358
// r1: second string.
6408
__ AllocateTwoByteString(r0, r6, r4, r5, r9, &call_runtime);
6409
__ add(r6, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
6410
// r0: result string.
6411
// r7: first character of first string.
6412
// r1: first character of second string.
6359
6413
// r2: length of first string.
6360
6414
// r3: length of second string.
6361
6415
// r6: first character of result.
6362
// r7: result string.
6363
StringHelper::GenerateCopyCharacters(masm, r6, r0, r2, r4, false);
6365
// Locate first character of second argument.
6366
__ add(r1, r1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
6368
// r1: first character of second string.
6369
// r3: length of second string.
6370
// r6: next character of result (after copy of first string).
6371
// r7: result string.
6416
StringHelper::GenerateCopyCharacters(masm, r6, r7, r2, r4, false);
6417
// r6: next character of result.
6372
6418
StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, false);
6374
__ mov(r0, Operand(r7));
6375
6419
__ IncrementCounter(counters->string_add_native(), 1, r2, r3);
6376
6420
__ add(sp, sp, Operand(2 * kPointerSize));
6379
6423
// Just jump to runtime to add the two strings.
6380
__ bind(&string_add_runtime);
6424
__ bind(&call_runtime);
6381
6425
__ TailCallRuntime(Runtime::kStringAdd, 2, 1);
6383
6427
if (call_builtin.is_linked()) {