~ubuntu-branches/ubuntu/saucy/libv8/saucy

« back to all changes in this revision

Viewing changes to src/arm/code-stubs-arm.cc

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2012-04-07 16:26:13 UTC
  • mfrom: (15.1.27 sid)
  • Revision ID: package-import@ubuntu.com-20120407162613-dqo1m6w9r3fh8tst
Tags: 3.8.9.16-3
* mipsel build fixes :
  + v8_use_mips_abi_hardfloat=false, this lowers EABI requirements.
  + v8_can_use_fpu_instructions=false, detect if FPU is present.
  + set -Wno-unused-but-set-variable only on mipsel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
156
156
  // Load the function from the stack.
157
157
  __ ldr(r3, MemOperand(sp, 0));
158
158
 
159
 
  // Setup the object header.
 
159
  // Set up the object header.
160
160
  __ LoadRoot(r2, Heap::kFunctionContextMapRootIndex);
161
161
  __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
162
162
  __ mov(r2, Operand(Smi::FromInt(length)));
163
163
  __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset));
164
164
 
165
 
  // Setup the fixed slots.
 
165
  // Set up the fixed slots.
166
166
  __ mov(r1, Operand(Smi::FromInt(0)));
167
167
  __ str(r3, MemOperand(r0, Context::SlotOffset(Context::CLOSURE_INDEX)));
168
168
  __ str(cp, MemOperand(r0, Context::SlotOffset(Context::PREVIOUS_INDEX)));
207
207
  // Load the serialized scope info from the stack.
208
208
  __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
209
209
 
210
 
  // Setup the object header.
 
210
  // Set up the object header.
211
211
  __ LoadRoot(r2, Heap::kBlockContextMapRootIndex);
212
212
  __ str(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
213
213
  __ mov(r2, Operand(Smi::FromInt(length)));
229
229
  __ ldr(r3, ContextOperand(r3, Context::CLOSURE_INDEX));
230
230
  __ bind(&after_sentinel);
231
231
 
232
 
  // Setup the fixed slots.
 
232
  // Set up the fixed slots.
233
233
  __ str(r3, ContextOperand(r0, Context::CLOSURE_INDEX));
234
234
  __ str(cp, ContextOperand(r0, Context::PREVIOUS_INDEX));
235
235
  __ str(r1, ContextOperand(r0, Context::EXTENSION_INDEX));
717
717
    // Get the absolute value of the object (as an unsigned integer).
718
718
    __ rsb(int_scratch, int_scratch, Operand::Zero(), SetCC, mi);
719
719
 
720
 
    // Get mantisssa[51:20].
 
720
    // Get mantissa[51:20].
721
721
 
722
722
    // Get the position of the first set bit.
723
723
    __ CountLeadingZeros(dst1, int_scratch, scratch2);
951
951
  // non zero bits left. So we need the (30 - exponent) last bits of the
952
952
  // 31 higher bits of the mantissa to be null.
953
953
  // Because bits [21:0] are null, we can check instead that the
954
 
  // (32 - exponent) last bits of the 32 higher bits of the mantisssa are null.
 
954
  // (32 - exponent) last bits of the 32 higher bits of the mantissa are null.
955
955
 
956
956
  // Get the 32 higher bits of the mantissa in dst.
957
957
  __ Ubfx(dst,
3455
3455
 
3456
3456
 
3457
3457
void MathPowStub::Generate(MacroAssembler* masm) {
3458
 
  Label call_runtime;
3459
 
 
3460
 
  if (CpuFeatures::IsSupported(VFP3)) {
3461
 
    CpuFeatures::Scope scope(VFP3);
3462
 
 
3463
 
    Label base_not_smi;
3464
 
    Label exponent_not_smi;
3465
 
    Label convert_exponent;
3466
 
 
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;
3477
 
 
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;
 
3470
 
 
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));
3481
3479
 
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);
 
3481
 
 
3482
    __ JumpIfSmi(base, &base_is_smi);
 
3483
    __ ldr(scratch, FieldMemOperand(base, JSObject::kMapOffset));
 
3484
    __ cmp(scratch, heapnumbermap);
 
3485
    __ b(ne, &call_runtime);
 
3486
 
 
3487
    __ vldr(double_base, FieldMemOperand(base, HeapNumber::kValueOffset));
 
3488
    __ jmp(&unpack_exponent);
 
3489
 
 
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);
3489
 
 
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));
3496
 
 
3497
 
    __ bind(&convert_exponent);
 
3494
    __ bind(&unpack_exponent);
 
3495
 
3498
3496
    __ JumpIfNotSmi(exponent, &exponent_not_smi);
3499
3497
    __ SmiUntag(exponent);
3500
 
 
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,
3506
 
                          scratch,
3507
 
                          scratch2,
3508
 
                          heapnumbermap,
3509
 
                          &call_runtime);
3510
 
    __ push(lr);
3511
 
    __ PrepareCallCFunction(1, 1, scratch);
3512
 
    __ SetCallCDoubleArguments(double_base, exponent);
3513
 
    {
3514
 
      AllowExternalCallThatCantCauseGC scope(masm);
3515
 
      __ CallCFunction(
3516
 
          ExternalReference::power_double_int_function(masm->isolate()),
3517
 
          1, 1);
3518
 
      __ pop(lr);
3519
 
      __ GetCFunctionDoubleResult(double_result);
3520
 
    }
3521
 
    __ vstr(double_result,
3522
 
            FieldMemOperand(heapnumber, HeapNumber::kValueOffset));
3523
 
    __ mov(r0, heapnumber);
3524
 
    __ Ret(2 * kPointerSize);
 
3498
    __ jmp(&int_exponent);
3525
3499
 
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));
3533
 
 
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,
3539
 
                          scratch,
3540
 
                          scratch2,
3541
 
                          heapnumbermap,
3542
 
                          &call_runtime);
 
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);
 
3511
 
 
3512
    __ bind(&exponent_not_smi);
 
3513
    __ vldr(double_exponent,
 
3514
            FieldMemOperand(exponent, HeapNumber::kValueOffset));
 
3515
  }
 
3516
 
 
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);
 
3526
 
 
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;
 
3532
 
 
3533
      // Test for 0.5.
 
3534
      __ vmov(double_scratch, 0.5);
 
3535
      __ VFPCompareAndSetFlags(double_exponent, double_scratch);
 
3536
      __ b(ne, &not_plus_half);
 
3537
 
 
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);
 
3543
      __ b(eq, &done);
 
3544
 
 
3545
      // Add +0 to convert -0 to +0.
 
3546
      __ vadd(double_scratch, double_base, kDoubleRegZero);
 
3547
      __ vsqrt(double_result, double_scratch);
 
3548
      __ jmp(&done);
 
3549
 
 
3550
      __ bind(&not_plus_half);
 
3551
      __ vmov(double_scratch, -0.5);
 
3552
      __ VFPCompareAndSetFlags(double_exponent, double_scratch);
 
3553
      __ b(ne, &call_runtime);
 
3554
 
 
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);
 
3560
      __ b(eq, &done);
 
3561
 
 
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);
 
3567
      __ jmp(&done);
 
3568
    }
 
3569
 
3543
3570
    __ push(lr);
3544
 
    __ PrepareCallCFunction(0, 2, scratch);
3545
 
    __ SetCallCDoubleArguments(double_base, double_exponent);
3546
3571
    {
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()),
3550
3577
          0, 2);
3551
 
      __ pop(lr);
3552
 
      __ GetCFunctionDoubleResult(double_result);
3553
3578
    }
 
3579
    __ pop(lr);
 
3580
    __ GetCFunctionDoubleResult(double_result);
 
3581
    __ jmp(&done);
 
3582
 
 
3583
    __ bind(&int_exponent_convert);
 
3584
    __ vcvt_u32_f64(single_scratch, double_exponent);
 
3585
    __ vmov(exponent, single_scratch);
 
3586
  }
 
3587
 
 
3588
  // Calculate power with integer exponent.
 
3589
  __ bind(&int_exponent);
 
3590
 
 
3591
  __ mov(scratch, exponent);  // Back up exponent.
 
3592
  __ vmov(double_scratch, double_base);  // Back up base.
 
3593
  __ vmov(double_result, 1.0);
 
3594
 
 
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);
 
3599
 
 
3600
  Label while_true;
 
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);
 
3606
 
 
3607
  __ cmp(exponent, Operand(0));
 
3608
  __ b(ge, &done);
 
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);
 
3614
  __ b(ne, &done);
 
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);
 
3619
 
 
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);
 
3626
 
 
3627
    // The stub is called from non-optimized code, which expects the result
 
3628
    // as heap number in exponent.
 
3629
    __ bind(&done);
 
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);
 
3636
    __ Ret(2);
 
3637
  } else {
 
3638
    __ push(lr);
 
3639
    {
 
3640
      AllowExternalCallThatCantCauseGC scope(masm);
 
3641
      __ PrepareCallCFunction(0, 2, scratch);
 
3642
      __ SetCallCDoubleArguments(double_base, double_exponent);
 
3643
      __ CallCFunction(
 
3644
          ExternalReference::power_double_double_function(masm->isolate()),
 
3645
          0, 2);
 
3646
    }
 
3647
    __ pop(lr);
 
3648
    __ GetCFunctionDoubleResult(double_result);
 
3649
 
 
3650
    __ bind(&done);
 
3651
    __ IncrementCounter(counters->math_pow(), 1, scratch, scratch2);
 
3652
    __ Ret();
3558
3653
  }
3559
 
 
3560
 
  __ bind(&call_runtime);
3561
 
  __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1);
3562
3654
}
3563
3655
 
3564
3656
 
3750
3842
  FrameScope scope(masm, StackFrame::MANUAL);
3751
3843
  __ EnterExitFrame(save_doubles_);
3752
3844
 
3753
 
  // Setup argc and the builtin function in callee-saved registers.
 
3845
  // Set up argc and the builtin function in callee-saved registers.
3754
3846
  __ mov(r4, Operand(r0));
3755
3847
  __ mov(r5, Operand(r1));
3756
3848
 
3827
3919
  // r2: receiver
3828
3920
  // r3: argc
3829
3921
 
3830
 
  // Setup argv in r4.
 
3922
  // Set up argv in r4.
3831
3923
  int offset_to_argv = (kNumCalleeSaved + 1) * kPointerSize;
3832
3924
  if (CpuFeatures::IsSupported(VFP3)) {
3833
3925
    offset_to_argv += kNumDoubleCalleeSaved * kDoubleSize;
3850
3942
  __ ldr(r5, MemOperand(r5));
3851
3943
  __ Push(r8, r7, r6, r5);
3852
3944
 
3853
 
  // Setup frame pointer for the frame to be pushed.
 
3945
  // Set up frame pointer for the frame to be pushed.
3854
3946
  __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
3855
3947
 
3856
3948
  // If this is the outermost JS call, set js_entry_sp value.
4310
4402
    __ str(r3, FieldMemOperand(r0, i));
4311
4403
  }
4312
4404
 
4313
 
  // Setup the callee in-object property.
 
4405
  // Set up the callee in-object property.
4314
4406
  STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
4315
4407
  __ ldr(r3, MemOperand(sp, 2 * kPointerSize));
4316
4408
  const int kCalleeOffset = JSObject::kHeaderSize +
4323
4415
      Heap::kArgumentsLengthIndex * kPointerSize;
4324
4416
  __ str(r2, FieldMemOperand(r0, kLengthOffset));
4325
4417
 
4326
 
  // Setup the elements pointer in the allocated arguments object.
 
4418
  // Set up the elements pointer in the allocated arguments object.
4327
4419
  // If we allocated a parameter map, r4 will point there, otherwise
4328
4420
  // it will point to the backing store.
4329
4421
  __ add(r4, r0, Operand(Heap::kArgumentsObjectSize));
4418
4510
  __ Ret();
4419
4511
 
4420
4512
  // Do the runtime call to allocate the arguments object.
4421
 
  // r2 = argument count (taggged)
 
4513
  // r2 = argument count (tagged)
4422
4514
  __ bind(&runtime);
4423
4515
  __ str(r2, MemOperand(sp, 0 * kPointerSize));  // Patch argument count.
4424
4516
  __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1);
4491
4583
  // Get the parameters pointer from the stack.
4492
4584
  __ ldr(r2, MemOperand(sp, 1 * kPointerSize));
4493
4585
 
4494
 
  // Setup the elements pointer in the allocated arguments object and
 
4586
  // Set up the elements pointer in the allocated arguments object and
4495
4587
  // initialize the header in the elements fixed array.
4496
4588
  __ add(r4, r0, Operand(Heap::kArgumentsObjectSizeStrict));
4497
4589
  __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
4503
4595
 
4504
4596
  // Copy the fixed array slots.
4505
4597
  Label loop;
4506
 
  // Setup r4 to point to the first array slot.
 
4598
  // Set up r4 to point to the first array slot.
4507
4599
  __ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4508
4600
  __ bind(&loop);
4509
4601
  // Pre-decrement r2 with kPointerSize on each iteration.
5118
5210
  // of the original receiver from the call site).
5119
5211
  __ bind(&non_function);
5120
5212
  __ str(r1, MemOperand(sp, argc_ * kPointerSize));
5121
 
  __ mov(r0, Operand(argc_));  // Setup the number of arguments.
 
5213
  __ mov(r0, Operand(argc_));  // Set up the number of arguments.
5122
5214
  __ mov(r2, Operand(0, RelocInfo::NONE));
5123
5215
  __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
5124
5216
  __ SetCallKind(r5, CALL_AS_METHOD);
5639
5731
                                    Register hash,
5640
5732
                                    Register character) {
5641
5733
  // hash = character + (character << 10);
5642
 
  __ add(hash, character, Operand(character, LSL, 10));
 
5734
  __ LoadRoot(hash, Heap::kHashSeedRootIndex);
 
5735
  // Untag smi seed and add the character.
 
5736
  __ add(hash, character, Operand(hash, LSR, kSmiTagSize));
 
5737
  // hash += hash << 10;
 
5738
  __ add(hash, hash, Operand(hash, LSL, 10));
5643
5739
  // hash ^= hash >> 6;
5644
5740
  __ eor(hash, hash, Operand(hash, LSR, 6));
5645
5741
}
5664
5760
  // hash ^= hash >> 11;
5665
5761
  __ eor(hash, hash, Operand(hash, LSR, 11));
5666
5762
  // hash += hash << 15;
5667
 
  __ add(hash, hash, Operand(hash, LSL, 15), SetCC);
 
5763
  __ add(hash, hash, Operand(hash, LSL, 15));
5668
5764
 
5669
 
  uint32_t kHashShiftCutOffMask = (1 << (32 - String::kHashShift)) - 1;
5670
 
  __ and_(hash, hash, Operand(kHashShiftCutOffMask));
 
5765
  __ and_(hash, hash, Operand(String::kHashBitMask), SetCC);
5671
5766
 
5672
5767
  // if (hash == 0) hash = 27;
5673
 
  __ mov(hash, Operand(27), LeaveCC, eq);
 
5768
  __ mov(hash, Operand(StringHasher::kZeroHash), LeaveCC, eq);
5674
5769
}
5675
5770
 
5676
5771
 
5694
5789
  static const int kFromOffset = 1 * kPointerSize;
5695
5790
  static const int kStringOffset = 2 * kPointerSize;
5696
5791
 
5697
 
  // Check bounds and smi-ness.
5698
 
  Register to = r6;
5699
 
  Register from = r7;
5700
 
 
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);
5705
5796
 
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.
5712
5803
 
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
5719
 
  // generated code.
5720
 
  __ cmp(r2, Operand(2));
5721
 
  __ b(lt, &runtime);
5722
5807
 
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);
5741
5822
 
5742
 
  Label create_slice;
5743
 
  if (FLAG_string_slices) {
5744
 
    __ cmp(r2, Operand(SlicedString::kMinLength));
5745
 
    __ b(ge, &create_slice);
5746
 
  }
5747
 
 
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)
5754
 
  Label seq_string;
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.
5762
 
 
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.
5772
 
 
5773
 
  // Definitly a sequential string.
5774
 
  __ bind(&seq_string);
5775
 
 
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.
5785
 
  to = no_reg;
5786
 
 
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);
5797
 
 
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);
5801
 
 
5802
 
  // Sub string of length 2 requested.
 
5828
  __ b(lt, &runtime);
 
5829
 
 
5830
  __ JumpIfInstanceTypeIsNotSequentialAscii(r1, r1, &runtime);
 
5831
 
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));
5809
5838
  Label make_two_character_string;
5810
5839
  StringHelper::GenerateTwoCharacterSymbolTableProbe(
5811
5840
      masm, r3, r4, r1, r5, r6, r7, r9, &make_two_character_string);
5812
 
  Counters* counters = masm->isolate()->counters();
5813
5841
  __ jmp(&return_r0);
5814
5842
 
5815
5843
  // r2: result string length.
5820
5848
  __ jmp(&return_r0);
5821
5849
 
5822
5850
  __ bind(&result_longer_than_two);
5823
 
 
5824
 
  // Locate 'from' character of string.
5825
 
  __ add(r5, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
5826
 
  __ add(r5, r5, Operand(from, ASR, 1));
5827
 
 
5828
 
  // Allocate the result.
5829
 
  __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime);
5830
 
 
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));
5837
 
 
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);
5845
 
  __ jmp(&return_r0);
5846
 
 
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.
5852
 
 
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
5856
 
  // byte character.
5857
 
  STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
5858
 
  __ add(r5, r5, Operand(from));
5859
 
 
5860
 
  // Allocate the result.
5861
 
  __ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime);
5862
 
 
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));
5868
 
 
5869
 
  from = no_reg;
5870
 
 
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);
5878
 
  __ jmp(&return_r0);
 
5854
  // r1: instance type
 
5855
  // r2: length
 
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);
 
5863
 
 
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);
 
5869
  __ b(ne, &runtime);
 
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);
 
5875
 
 
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);
 
5885
 
 
5886
  __ bind(&seq_or_external_string);
 
5887
  // Sequential or external string.  Just move string to the expected register.
 
5888
  __ mov(r5, r0);
 
5889
 
 
5890
  __ bind(&underlying_unpacked);
5879
5891
 
5880
5892
  if (FLAG_string_slices) {
5881
 
    __ bind(&create_slice);
5882
 
    // r0: original string
5883
 
    // r1: instance type
5884
 
    // r2: length
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);
5894
 
 
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);
5900
 
    __ cmp(r5, r9);
5901
 
    __ b(ne, &runtime);
5902
 
    __ ldr(r5, FieldMemOperand(r0, ConsString::kFirstOffset));
5903
 
    __ jmp(&allocate_slice);
5904
 
 
5905
 
    __ bind(&sliced_string);
5906
 
    // Sliced string.  Fetch parent and correct start index by offset.
5907
 
    __ ldr(r5, FieldMemOperand(r0, SlicedString::kOffsetOffset));
5908
 
    __ add(r7, r7, r5);
5909
 
    __ ldr(r5, FieldMemOperand(r0, SlicedString::kParentOffset));
5910
 
    __ jmp(&allocate_slice);
5911
 
 
5912
 
    __ bind(&seq_or_external_string);
5913
 
    // Sequential or external string.  Just move string to the correct register.
5914
 
    __ mov(r5, r0);
5915
 
 
5916
 
    __ bind(&allocate_slice);
5917
 
    // r1: instance type of original string
5918
 
    // r2: length
 
5893
    Label copy_routine;
5919
5894
    // r5: underlying subject string
5920
 
    // r7 (a.k.a. from): from offset (smi)
 
5895
    // r1: instance type of underlying subject string
 
5896
    // r2: length
 
5897
    // r3: adjusted start index (untagged)
 
5898
    __ cmp(r2, Operand(SlicedString::kMinLength));
 
5899
    // Short slice.  Copy instead of slicing.
 
5900
    __ b(lt, &copy_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));
 
5919
    __ jmp(&return_r0);
 
5920
 
 
5921
    __ bind(&copy_routine);
5938
5922
  }
5939
5923
 
 
5924
  // r5: underlying subject string
 
5925
  // r1: instance type of underlying subject string
 
5926
  // r2: length
 
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);
 
5933
 
 
5934
  // Handle external string.
 
5935
  // Rule out short external strings.
 
5936
  STATIC_CHECK(kShortExternalStringTag != 0);
 
5937
  __ tst(r1, Operand(kShortExternalStringTag));
 
5938
  __ b(ne, &runtime);
 
5939
  __ ldr(r5, FieldMemOperand(r5, ExternalString::kResourceDataOffset));
 
5940
  // r5 already points to the first character of underlying string.
 
5941
  __ jmp(&allocate_result);
 
5942
 
 
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));
 
5947
 
 
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);
 
5953
 
 
5954
  // Allocate and copy the resulting ASCII string.
 
5955
  __ AllocateAsciiString(r0, r2, r4, r6, r7, &runtime);
 
5956
 
 
5957
  // Locate first character of substring to copy.
 
5958
  __ add(r5, r5, r3);
 
5959
  // Locate first character of result.
 
5960
  __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
 
5961
 
 
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);
 
5969
  __ jmp(&return_r0);
 
5970
 
 
5971
  // Allocate and copy the resulting two-byte string.
 
5972
  __ bind(&two_byte_sequential);
 
5973
  __ AllocateTwoByteString(r0, r2, r4, r6, r7, &runtime);
 
5974
 
 
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));
 
5980
 
 
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);
 
5988
 
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));
5943
5993
  __ Ret();
6094
6144
 
6095
6145
 
6096
6146
void StringAddStub::Generate(MacroAssembler* masm) {
6097
 
  Label string_add_runtime, call_builtin;
 
6147
  Label call_runtime, call_builtin;
6098
6148
  Builtins::JavaScript builtin_id = Builtins::ADD;
6099
6149
 
6100
6150
  Counters* counters = masm->isolate()->counters();
6109
6159
 
6110
6160
  // Make sure that both arguments are strings if not known in advance.
6111
6161
  if (flags_ == NO_STRING_ADD_FLAGS) {
6112
 
    __ JumpIfEitherSmi(r0, r1, &string_add_runtime);
 
6162
    __ JumpIfEitherSmi(r0, r1, &call_runtime);
6113
6163
    // Load instance types.
6114
6164
    __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
6115
6165
    __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
6119
6169
    // If either is not a string, go to runtime.
6120
6170
    __ tst(r4, Operand(kIsNotStringMask));
6121
6171
    __ tst(r5, Operand(kIsNotStringMask), eq);
6122
 
    __ b(ne, &string_add_runtime);
 
6172
    __ b(ne, &call_runtime);
6123
6173
  } else {
6124
6174
    // Here at least one of the arguments is definitely a string.
6125
6175
    // We convert the one that is not known to be a string.
6188
6238
    __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
6189
6239
  }
6190
6240
  __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r7,
6191
 
                                                  &string_add_runtime);
 
6241
                                                  &call_runtime);
6192
6242
 
6193
6243
  // Get the two characters forming the sub string.
6194
6244
  __ ldrb(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
6210
6260
  // halfword store instruction (which assumes that processor is
6211
6261
  // in a little endian mode)
6212
6262
  __ mov(r6, Operand(2));
6213
 
  __ AllocateAsciiString(r0, r6, r4, r5, r9, &string_add_runtime);
 
6263
  __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime);
6214
6264
  __ strh(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize));
6215
6265
  __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
6216
6266
  __ add(sp, sp, Operand(2 * kPointerSize));
6218
6268
 
6219
6269
  __ bind(&longer_than_two);
6220
6270
  // Check if resulting string will be flat.
6221
 
  __ cmp(r6, Operand(String::kMinNonFlatLength));
 
6271
  __ cmp(r6, Operand(ConsString::kMinLength));
6222
6272
  __ b(lt, &string_add_flat_result);
6223
6273
  // Handle exceptionally long strings in the runtime system.
6224
6274
  STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
6225
6275
  ASSERT(IsPowerOf2(String::kMaxLength + 1));
6226
6276
  // kMaxLength + 1 is representable as shifted literal, kMaxLength is not.
6227
6277
  __ cmp(r6, Operand(String::kMaxLength + 1));
6228
 
  __ b(hs, &string_add_runtime);
 
6278
  __ b(hs, &call_runtime);
6229
6279
 
6230
6280
  // If result is not supposed to be flat, allocate a cons string object.
6231
6281
  // If both strings are ASCII the result is an ASCII cons string.
6243
6293
 
6244
6294
  // Allocate an ASCII cons string.
6245
6295
  __ bind(&ascii_data);
6246
 
  __ AllocateAsciiConsString(r7, r6, r4, r5, &string_add_runtime);
 
6296
  __ AllocateAsciiConsString(r7, r6, r4, r5, &call_runtime);
6247
6297
  __ bind(&allocated);
6248
6298
  // Fill the fields of the cons string.
6249
6299
  __ str(r0, FieldMemOperand(r7, ConsString::kFirstOffset));
6268
6318
  __ b(eq, &ascii_data);
6269
6319
 
6270
6320
  // Allocate a two byte cons string.
6271
 
  __ AllocateTwoByteConsString(r7, r6, r4, r5, &string_add_runtime);
 
6321
  __ AllocateTwoByteConsString(r7, r6, r4, r5, &call_runtime);
6272
6322
  __ jmp(&allocated);
6273
6323
 
6274
 
  // Handle creating a flat result. First check that both strings are
6275
 
  // sequential and that they have the same encoding.
 
6324
  // We cannot encounter sliced strings or cons strings here since:
 
6325
  STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
 
6326
  // Handle creating a flat result from either external or sequential strings.
 
6327
  // Locate the first characters' locations.
6276
6328
  // r0: first string
6277
6329
  // r1: second string
6278
6330
  // r2: length of first string
6280
6332
  // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
6281
6333
  // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
6282
6334
  // r6: sum of lengths.
 
6335
  Label first_prepared, second_prepared;
6283
6336
  __ bind(&string_add_flat_result);
6284
6337
  if (flags_ != NO_STRING_ADD_FLAGS) {
6285
6338
    __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
6287
6340
    __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
6288
6341
    __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
6289
6342
  }
6290
 
  // Check that both strings are sequential.
 
6343
 
 
6344
  // Check whether both strings have same encoding
 
6345
  __ eor(r7, r4, Operand(r5));
 
6346
  __ tst(r7, Operand(kStringEncodingMask));
 
6347
  __ b(ne, &call_runtime);
 
6348
 
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);
 
6352
  __ add(r7,
 
6353
         r0,
 
6354
         Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag),
 
6355
         LeaveCC,
 
6356
         eq);
 
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);
 
6364
 
 
6365
  STATIC_ASSERT(kSeqStringTag == 0);
 
6366
  __ tst(r5, Operand(kStringRepresentationMask));
 
6367
  STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize);
 
6368
  __ add(r1,
 
6369
         r1,
 
6370
         Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag),
 
6371
         LeaveCC,
 
6372
         eq);
 
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);
 
6380
 
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);
6309
6391
 
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);
6325
 
 
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));
6336
6405
  __ Ret();
6337
6406
 
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.
6351
 
 
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));
6356
 
 
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);
6364
 
 
6365
 
  // Locate first character of second argument.
6366
 
  __ add(r1, r1, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
6367
 
 
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);
6373
 
 
6374
 
  __ mov(r0, Operand(r7));
6375
6419
  __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
6376
6420
  __ add(sp, sp, Operand(2 * kPointerSize));
6377
6421
  __ Ret();
6378
6422
 
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);
6382
6426
 
6383
6427
  if (call_builtin.is_linked()) {
6629
6673
}
6630
6674
 
6631
6675
 
 
6676
void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) {
 
6677
  Label miss;
 
6678
  __ and_(r2, r1, Operand(r0));
 
6679
  __ JumpIfSmi(r2, &miss);
 
6680
  __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
 
6681
  __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
 
6682
  __ cmp(r2, Operand(known_map_));
 
6683
  __ b(ne, &miss);
 
6684
  __ cmp(r3, Operand(known_map_));
 
6685
  __ b(ne, &miss);
 
6686
 
 
6687
  __ sub(r0, r0, Operand(r1));
 
6688
  __ Ret();
 
6689
 
 
6690
  __ bind(&miss);
 
6691
  GenerateMiss(masm);
 
6692
}
 
6693
 
 
6694
 
 
6695
 
6632
6696
void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
6633
 
  __ Push(r1, r0);
6634
 
  __ push(lr);
 
6697
  {
 
6698
    // Call the runtime system in a fresh internal frame.
 
6699
    ExternalReference miss =
 
6700
        ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate());
6635
6701
 
6636
 
  // Call the runtime system in a fresh internal frame.
6637
 
  ExternalReference miss =
6638
 
      ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate());
6639
 
  {
6640
6702
    FrameScope scope(masm, StackFrame::INTERNAL);
6641
6703
    __ Push(r1, r0);
 
6704
    __ push(lr);
 
6705
    __ Push(r1, r0);
6642
6706
    __ mov(ip, Operand(Smi::FromInt(op_)));
6643
6707
    __ push(ip);
6644
6708
    __ CallExternalReference(miss, 3);
 
6709
    // Compute the entry point of the rewritten stub.
 
6710
    __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
 
6711
    // Restore registers.
 
6712
    __ pop(lr);
 
6713
    __ pop(r0);
 
6714
    __ pop(r1);
6645
6715
  }
6646
 
  // Compute the entry point of the rewritten stub.
6647
 
  __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
6648
 
  // Restore registers.
6649
 
  __ pop(lr);
6650
 
  __ pop(r0);
6651
 
  __ pop(r1);
 
6716
 
6652
6717
  __ Jump(r2);
6653
6718
}
6654
6719
 
7246
7311
  // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS.
7247
7312
  __ bind(&double_elements);
7248
7313
  __ ldr(r5, FieldMemOperand(r1, JSObject::kElementsOffset));
7249
 
  __ StoreNumberToDoubleElements(r0, r3, r1, r5, r6, r7, r9, r10,
 
7314
  __ StoreNumberToDoubleElements(r0, r3, r1, r5, r6, r7, r9, r2,
7250
7315
                                 &slow_elements);
7251
7316
  __ Ret();
7252
7317
}