Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(232)

Side by Side Diff: src/arm/code-stubs-arm.cc

Issue 143633007: A64: Synchronize with r18764. (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/a64
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/arm/code-stubs-arm.h ('k') | src/arm/codegen-arm.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 Isolate* isolate, 42 Isolate* isolate,
43 CodeStubInterfaceDescriptor* descriptor) { 43 CodeStubInterfaceDescriptor* descriptor) {
44 static Register registers[] = { r2 }; 44 static Register registers[] = { r2 };
45 descriptor->register_param_count_ = 1; 45 descriptor->register_param_count_ = 1;
46 descriptor->register_params_ = registers; 46 descriptor->register_params_ = registers;
47 descriptor->deoptimization_handler_ = 47 descriptor->deoptimization_handler_ =
48 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry; 48 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry;
49 } 49 }
50 50
51 51
52 void FastNewContextStub::InitializeInterfaceDescriptor(
53 Isolate* isolate,
54 CodeStubInterfaceDescriptor* descriptor) {
55 static Register registers[] = { r1 };
56 descriptor->register_param_count_ = 1;
57 descriptor->register_params_ = registers;
58 descriptor->deoptimization_handler_ = NULL;
59 }
60
61
52 void ToNumberStub::InitializeInterfaceDescriptor( 62 void ToNumberStub::InitializeInterfaceDescriptor(
53 Isolate* isolate, 63 Isolate* isolate,
54 CodeStubInterfaceDescriptor* descriptor) { 64 CodeStubInterfaceDescriptor* descriptor) {
55 static Register registers[] = { r0 }; 65 static Register registers[] = { r0 };
56 descriptor->register_param_count_ = 1; 66 descriptor->register_param_count_ = 1;
57 descriptor->register_params_ = registers; 67 descriptor->register_params_ = registers;
58 descriptor->deoptimization_handler_ = NULL; 68 descriptor->deoptimization_handler_ = NULL;
59 } 69 }
60 70
61 71
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
193 } 203 }
194 204
195 205
196 static void InitializeArrayConstructorDescriptor( 206 static void InitializeArrayConstructorDescriptor(
197 Isolate* isolate, 207 Isolate* isolate,
198 CodeStubInterfaceDescriptor* descriptor, 208 CodeStubInterfaceDescriptor* descriptor,
199 int constant_stack_parameter_count) { 209 int constant_stack_parameter_count) {
200 // register state 210 // register state
201 // r0 -- number of arguments 211 // r0 -- number of arguments
202 // r1 -- function 212 // r1 -- function
203 // r2 -- type info cell with elements kind 213 // r2 -- allocation site with elements kind
204 static Register registers_variable_args[] = { r1, r2, r0 }; 214 static Register registers_variable_args[] = { r1, r2, r0 };
205 static Register registers_no_args[] = { r1, r2 }; 215 static Register registers_no_args[] = { r1, r2 };
206 216
207 if (constant_stack_parameter_count == 0) { 217 if (constant_stack_parameter_count == 0) {
208 descriptor->register_param_count_ = 2; 218 descriptor->register_param_count_ = 2;
209 descriptor->register_params_ = registers_no_args; 219 descriptor->register_params_ = registers_no_args;
210 } else { 220 } else {
211 // stack param count needs (constructor pointer, and single argument) 221 // stack param count needs (constructor pointer, and single argument)
212 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS; 222 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
213 descriptor->stack_parameter_count_ = r0; 223 descriptor->stack_parameter_count_ = r0;
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 Isolate* isolate, 353 Isolate* isolate,
344 CodeStubInterfaceDescriptor* descriptor) { 354 CodeStubInterfaceDescriptor* descriptor) {
345 static Register registers[] = { r2, r1, r0 }; 355 static Register registers[] = { r2, r1, r0 };
346 descriptor->register_param_count_ = 3; 356 descriptor->register_param_count_ = 3;
347 descriptor->register_params_ = registers; 357 descriptor->register_params_ = registers;
348 descriptor->deoptimization_handler_ = 358 descriptor->deoptimization_handler_ =
349 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); 359 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite);
350 } 360 }
351 361
352 362
353 void NewStringAddStub::InitializeInterfaceDescriptor( 363 void StringAddStub::InitializeInterfaceDescriptor(
354 Isolate* isolate, 364 Isolate* isolate,
355 CodeStubInterfaceDescriptor* descriptor) { 365 CodeStubInterfaceDescriptor* descriptor) {
356 static Register registers[] = { r1, r0 }; 366 static Register registers[] = { r1, r0 };
357 descriptor->register_param_count_ = 2; 367 descriptor->register_param_count_ = 2;
358 descriptor->register_params_ = registers; 368 descriptor->register_params_ = registers;
359 descriptor->deoptimization_handler_ = 369 descriptor->deoptimization_handler_ =
360 Runtime::FunctionForId(Runtime::kStringAdd)->entry; 370 Runtime::FunctionForId(Runtime::kStringAdd)->entry;
361 } 371 }
362 372
363 373
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 __ push(descriptor->register_params_[i]); 464 __ push(descriptor->register_params_[i]);
455 } 465 }
456 ExternalReference miss = descriptor->miss_handler(); 466 ExternalReference miss = descriptor->miss_handler();
457 __ CallExternalReference(miss, descriptor->register_param_count_); 467 __ CallExternalReference(miss, descriptor->register_param_count_);
458 } 468 }
459 469
460 __ Ret(); 470 __ Ret();
461 } 471 }
462 472
463 473
464 void FastNewContextStub::Generate(MacroAssembler* masm) {
465 // Try to allocate the context in new space.
466 Label gc;
467 int length = slots_ + Context::MIN_CONTEXT_SLOTS;
468
469 // Attempt to allocate the context in new space.
470 __ Allocate(FixedArray::SizeFor(length), r0, r1, r2, &gc, TAG_OBJECT);
471
472 // Load the function from the stack.
473 __ ldr(r3, MemOperand(sp, 0));
474
475 // Set up the object header.
476 __ LoadRoot(r1, Heap::kFunctionContextMapRootIndex);
477 __ mov(r2, Operand(Smi::FromInt(length)));
478 __ str(r2, FieldMemOperand(r0, FixedArray::kLengthOffset));
479 __ str(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
480
481 // Set up the fixed slots, copy the global object from the previous context.
482 __ ldr(r2, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
483 __ mov(r1, Operand(Smi::FromInt(0)));
484 __ str(r3, MemOperand(r0, Context::SlotOffset(Context::CLOSURE_INDEX)));
485 __ str(cp, MemOperand(r0, Context::SlotOffset(Context::PREVIOUS_INDEX)));
486 __ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX)));
487 __ str(r2, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
488
489 // Initialize the rest of the slots to undefined.
490 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
491 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) {
492 __ str(r1, MemOperand(r0, Context::SlotOffset(i)));
493 }
494
495 // Remove the on-stack argument and return.
496 __ mov(cp, r0);
497 __ pop();
498 __ Ret();
499
500 // Need to collect. Call into runtime system.
501 __ bind(&gc);
502 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1);
503 }
504
505
506 void FastNewBlockContextStub::Generate(MacroAssembler* masm) { 474 void FastNewBlockContextStub::Generate(MacroAssembler* masm) {
507 // Stack layout on entry: 475 // Stack layout on entry:
508 // 476 //
509 // [sp]: function. 477 // [sp]: function.
510 // [sp + kPointerSize]: serialized scope info 478 // [sp + kPointerSize]: serialized scope info
511 479
512 // Try to allocate the context in new space. 480 // Try to allocate the context in new space.
513 Label gc; 481 Label gc;
514 int length = slots_ + Context::MIN_CONTEXT_SLOTS; 482 int length = slots_ + Context::MIN_CONTEXT_SLOTS;
515 __ Allocate(FixedArray::SizeFor(length), r0, r1, r2, &gc, TAG_OBJECT); 483 __ Allocate(FixedArray::SizeFor(length), r0, r1, r2, &gc, TAG_OBJECT);
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 } 626 }
659 627
660 628
661 void DoubleToIStub::Generate(MacroAssembler* masm) { 629 void DoubleToIStub::Generate(MacroAssembler* masm) {
662 Label out_of_range, only_low, negate, done; 630 Label out_of_range, only_low, negate, done;
663 Register input_reg = source(); 631 Register input_reg = source();
664 Register result_reg = destination(); 632 Register result_reg = destination();
665 633
666 int double_offset = offset(); 634 int double_offset = offset();
667 // Account for saved regs if input is sp. 635 // Account for saved regs if input is sp.
668 if (input_reg.is(sp)) double_offset += 2 * kPointerSize; 636 if (input_reg.is(sp)) double_offset += 3 * kPointerSize;
669 637
670 // Immediate values for this stub fit in instructions, so it's safe to use ip. 638 Register scratch = GetRegisterThatIsNotOneOf(input_reg, result_reg);
671 Register scratch = ip;
672 Register scratch_low = 639 Register scratch_low =
673 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch); 640 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch);
674 Register scratch_high = 641 Register scratch_high =
675 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch, scratch_low); 642 GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch, scratch_low);
676 LowDwVfpRegister double_scratch = kScratchDoubleReg; 643 LowDwVfpRegister double_scratch = kScratchDoubleReg;
677 644
678 __ Push(scratch_high, scratch_low); 645 __ Push(scratch_high, scratch_low, scratch);
679 646
680 if (!skip_fastpath()) { 647 if (!skip_fastpath()) {
681 // Load double input. 648 // Load double input.
682 __ vldr(double_scratch, MemOperand(input_reg, double_offset)); 649 __ vldr(double_scratch, MemOperand(input_reg, double_offset));
683 __ vmov(scratch_low, scratch_high, double_scratch); 650 __ vmov(scratch_low, scratch_high, double_scratch);
684 651
685 // Do fast-path convert from double to int. 652 // Do fast-path convert from double to int.
686 __ vcvt_s32_f64(double_scratch.low(), double_scratch); 653 __ vcvt_s32_f64(double_scratch.low(), double_scratch);
687 __ vmov(result_reg, double_scratch.low()); 654 __ vmov(result_reg, double_scratch.low());
688 655
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
751 // scratch_high LSR 31 equals zero. 718 // scratch_high LSR 31 equals zero.
752 // New result = (result eor 0) + 0 = result. 719 // New result = (result eor 0) + 0 = result.
753 // If the input was negative, we have to negate the result. 720 // If the input was negative, we have to negate the result.
754 // Input_high ASR 31 equals 0xffffffff and scratch_high LSR 31 equals 1. 721 // Input_high ASR 31 equals 0xffffffff and scratch_high LSR 31 equals 1.
755 // New result = (result eor 0xffffffff) + 1 = 0 - result. 722 // New result = (result eor 0xffffffff) + 1 = 0 - result.
756 __ eor(result_reg, result_reg, Operand(scratch_high, ASR, 31)); 723 __ eor(result_reg, result_reg, Operand(scratch_high, ASR, 31));
757 __ add(result_reg, result_reg, Operand(scratch_high, LSR, 31)); 724 __ add(result_reg, result_reg, Operand(scratch_high, LSR, 31));
758 725
759 __ bind(&done); 726 __ bind(&done);
760 727
761 __ Pop(scratch_high, scratch_low); 728 __ Pop(scratch_high, scratch_low, scratch);
762 __ Ret(); 729 __ Ret();
763 } 730 }
764 731
765 732
766 void WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime( 733 void WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(
767 Isolate* isolate) { 734 Isolate* isolate) {
768 WriteInt32ToHeapNumberStub stub1(r1, r0, r2); 735 WriteInt32ToHeapNumberStub stub1(r1, r0, r2);
769 WriteInt32ToHeapNumberStub stub2(r2, r0, r3); 736 WriteInt32ToHeapNumberStub stub2(r2, r0, r3);
770 stub1.GetCode(isolate); 737 stub1.GetCode(isolate);
771 stub2.GetCode(isolate); 738 stub2.GetCode(isolate);
(...skipping 2690 matching lines...) Expand 10 before | Expand all | Expand 10 after
3462 __ push(code_); 3429 __ push(code_);
3463 __ CallRuntime(Runtime::kCharFromCode, 1); 3430 __ CallRuntime(Runtime::kCharFromCode, 1);
3464 __ Move(result_, r0); 3431 __ Move(result_, r0);
3465 call_helper.AfterCall(masm); 3432 call_helper.AfterCall(masm);
3466 __ jmp(&exit_); 3433 __ jmp(&exit_);
3467 3434
3468 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); 3435 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
3469 } 3436 }
3470 3437
3471 3438
3472 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm,
3473 Register dest,
3474 Register src,
3475 Register count,
3476 Register scratch,
3477 bool ascii) {
3478 Label loop;
3479 Label done;
3480 // This loop just copies one character at a time, as it is only used for very
3481 // short strings.
3482 if (!ascii) {
3483 __ add(count, count, Operand(count), SetCC);
3484 } else {
3485 __ cmp(count, Operand::Zero());
3486 }
3487 __ b(eq, &done);
3488
3489 __ bind(&loop);
3490 __ ldrb(scratch, MemOperand(src, 1, PostIndex));
3491 // Perform sub between load and dependent store to get the load time to
3492 // complete.
3493 __ sub(count, count, Operand(1), SetCC);
3494 __ strb(scratch, MemOperand(dest, 1, PostIndex));
3495 // last iteration.
3496 __ b(gt, &loop);
3497
3498 __ bind(&done);
3499 }
3500
3501
3502 enum CopyCharactersFlags { 3439 enum CopyCharactersFlags {
3503 COPY_ASCII = 1, 3440 COPY_ASCII = 1,
3504 DEST_ALWAYS_ALIGNED = 2 3441 DEST_ALWAYS_ALIGNED = 2
3505 }; 3442 };
3506 3443
3507 3444
3508 void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, 3445 void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm,
3509 Register dest, 3446 Register dest,
3510 Register src, 3447 Register src,
3511 Register count, 3448 Register count,
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
3639 __ cmp(dest, Operand(limit)); 3576 __ cmp(dest, Operand(limit));
3640 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt); 3577 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt);
3641 __ b(ge, &done); 3578 __ b(ge, &done);
3642 __ strb(scratch1, MemOperand(dest, 1, PostIndex)); 3579 __ strb(scratch1, MemOperand(dest, 1, PostIndex));
3643 __ b(&byte_loop); 3580 __ b(&byte_loop);
3644 3581
3645 __ bind(&done); 3582 __ bind(&done);
3646 } 3583 }
3647 3584
3648 3585
3649 void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm,
3650 Register c1,
3651 Register c2,
3652 Register scratch1,
3653 Register scratch2,
3654 Register scratch3,
3655 Register scratch4,
3656 Register scratch5,
3657 Label* not_found) {
3658 // Register scratch3 is the general scratch register in this function.
3659 Register scratch = scratch3;
3660
3661 // Make sure that both characters are not digits as such strings has a
3662 // different hash algorithm. Don't try to look for these in the string table.
3663 Label not_array_index;
3664 __ sub(scratch, c1, Operand(static_cast<int>('0')));
3665 __ cmp(scratch, Operand(static_cast<int>('9' - '0')));
3666 __ b(hi, &not_array_index);
3667 __ sub(scratch, c2, Operand(static_cast<int>('0')));
3668 __ cmp(scratch, Operand(static_cast<int>('9' - '0')));
3669
3670 // If check failed combine both characters into single halfword.
3671 // This is required by the contract of the method: code at the
3672 // not_found branch expects this combination in c1 register
3673 __ orr(c1, c1, Operand(c2, LSL, kBitsPerByte), LeaveCC, ls);
3674 __ b(ls, not_found);
3675
3676 __ bind(&not_array_index);
3677 // Calculate the two character string hash.
3678 Register hash = scratch1;
3679 StringHelper::GenerateHashInit(masm, hash, c1);
3680 StringHelper::GenerateHashAddCharacter(masm, hash, c2);
3681 StringHelper::GenerateHashGetHash(masm, hash);
3682
3683 // Collect the two characters in a register.
3684 Register chars = c1;
3685 __ orr(chars, chars, Operand(c2, LSL, kBitsPerByte));
3686
3687 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
3688 // hash: hash of two character string.
3689
3690 // Load string table
3691 // Load address of first element of the string table.
3692 Register string_table = c2;
3693 __ LoadRoot(string_table, Heap::kStringTableRootIndex);
3694
3695 Register undefined = scratch4;
3696 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
3697
3698 // Calculate capacity mask from the string table capacity.
3699 Register mask = scratch2;
3700 __ ldr(mask, FieldMemOperand(string_table, StringTable::kCapacityOffset));
3701 __ mov(mask, Operand(mask, ASR, 1));
3702 __ sub(mask, mask, Operand(1));
3703
3704 // Calculate untagged address of the first element of the string table.
3705 Register first_string_table_element = string_table;
3706 __ add(first_string_table_element, string_table,
3707 Operand(StringTable::kElementsStartOffset - kHeapObjectTag));
3708
3709 // Registers
3710 // chars: two character string, char 1 in byte 0 and char 2 in byte 1.
3711 // hash: hash of two character string
3712 // mask: capacity mask
3713 // first_string_table_element: address of the first element of
3714 // the string table
3715 // undefined: the undefined object
3716 // scratch: -
3717
3718 // Perform a number of probes in the string table.
3719 const int kProbes = 4;
3720 Label found_in_string_table;
3721 Label next_probe[kProbes];
3722 Register candidate = scratch5; // Scratch register contains candidate.
3723 for (int i = 0; i < kProbes; i++) {
3724 // Calculate entry in string table.
3725 if (i > 0) {
3726 __ add(candidate, hash, Operand(StringTable::GetProbeOffset(i)));
3727 } else {
3728 __ mov(candidate, hash);
3729 }
3730
3731 __ and_(candidate, candidate, Operand(mask));
3732
3733 // Load the entry from the symble table.
3734 STATIC_ASSERT(StringTable::kEntrySize == 1);
3735 __ ldr(candidate,
3736 MemOperand(first_string_table_element,
3737 candidate,
3738 LSL,
3739 kPointerSizeLog2));
3740
3741 // If entry is undefined no string with this hash can be found.
3742 Label is_string;
3743 __ CompareObjectType(candidate, scratch, scratch, ODDBALL_TYPE);
3744 __ b(ne, &is_string);
3745
3746 __ cmp(undefined, candidate);
3747 __ b(eq, not_found);
3748 // Must be the hole (deleted entry).
3749 if (FLAG_debug_code) {
3750 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
3751 __ cmp(ip, candidate);
3752 __ Assert(eq, kOddballInStringTableIsNotUndefinedOrTheHole);
3753 }
3754 __ jmp(&next_probe[i]);
3755
3756 __ bind(&is_string);
3757
3758 // Check that the candidate is a non-external ASCII string. The instance
3759 // type is still in the scratch register from the CompareObjectType
3760 // operation.
3761 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &next_probe[i]);
3762
3763 // If length is not 2 the string is not a candidate.
3764 __ ldr(scratch, FieldMemOperand(candidate, String::kLengthOffset));
3765 __ cmp(scratch, Operand(Smi::FromInt(2)));
3766 __ b(ne, &next_probe[i]);
3767
3768 // Check if the two characters match.
3769 // Assumes that word load is little endian.
3770 __ ldrh(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize));
3771 __ cmp(chars, scratch);
3772 __ b(eq, &found_in_string_table);
3773 __ bind(&next_probe[i]);
3774 }
3775
3776 // No matching 2 character string found by probing.
3777 __ jmp(not_found);
3778
3779 // Scratch register contains result when we fall through to here.
3780 Register result = candidate;
3781 __ bind(&found_in_string_table);
3782 __ Move(r0, result);
3783 }
3784
3785
3786 void StringHelper::GenerateHashInit(MacroAssembler* masm, 3586 void StringHelper::GenerateHashInit(MacroAssembler* masm,
3787 Register hash, 3587 Register hash,
3788 Register character) { 3588 Register character) {
3789 // hash = character + (character << 10); 3589 // hash = character + (character << 10);
3790 __ LoadRoot(hash, Heap::kHashSeedRootIndex); 3590 __ LoadRoot(hash, Heap::kHashSeedRootIndex);
3791 // Untag smi seed and add the character. 3591 // Untag smi seed and add the character.
3792 __ add(hash, character, Operand(hash, LSR, kSmiTagSize)); 3592 __ add(hash, character, Operand(hash, LSR, kSmiTagSize));
3793 // hash += hash << 10; 3593 // hash += hash << 10;
3794 __ add(hash, hash, Operand(hash, LSL, 10)); 3594 __ add(hash, hash, Operand(hash, LSL, 10));
3795 // hash ^= hash >> 6; 3595 // hash ^= hash >> 6;
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after
4190 __ add(sp, sp, Operand(2 * kPointerSize)); 3990 __ add(sp, sp, Operand(2 * kPointerSize));
4191 GenerateCompareFlatAsciiStrings(masm, r1, r0, r2, r3, r4, r5); 3991 GenerateCompareFlatAsciiStrings(masm, r1, r0, r2, r3, r4, r5);
4192 3992
4193 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 3993 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
4194 // tagged as a small integer. 3994 // tagged as a small integer.
4195 __ bind(&runtime); 3995 __ bind(&runtime);
4196 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 3996 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
4197 } 3997 }
4198 3998
4199 3999
4000 void ArrayPushStub::Generate(MacroAssembler* masm) {
4001 Register receiver = r0;
4002 Register scratch = r1;
4003
4004 int argc = arguments_count();
4005
4006 if (argc == 0) {
4007 // Nothing to do, just return the length.
4008 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset));
4009 __ Drop(argc + 1);
4010 __ Ret();
4011 return;
4012 }
4013
4014 Isolate* isolate = masm->isolate();
4015
4016 if (argc != 1) {
4017 __ TailCallExternalReference(
4018 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
4019 return;
4020 }
4021
4022 Label call_builtin, attempt_to_grow_elements, with_write_barrier;
4023
4024 Register elements = r6;
4025 Register end_elements = r5;
4026 // Get the elements array of the object.
4027 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
4028
4029 if (IsFastSmiOrObjectElementsKind(elements_kind())) {
4030 // Check that the elements are in fast mode and writable.
4031 __ CheckMap(elements,
4032 scratch,
4033 Heap::kFixedArrayMapRootIndex,
4034 &call_builtin,
4035 DONT_DO_SMI_CHECK);
4036 }
4037
4038 // Get the array's length into scratch and calculate new length.
4039 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
4040 __ add(scratch, scratch, Operand(Smi::FromInt(argc)));
4041
4042 // Get the elements' length.
4043 __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
4044
4045 // Check if we could survive without allocation.
4046 __ cmp(scratch, r4);
4047
4048 const int kEndElementsOffset =
4049 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize;
4050
4051 if (IsFastSmiOrObjectElementsKind(elements_kind())) {
4052 __ b(gt, &attempt_to_grow_elements);
4053
4054 // Check if value is a smi.
4055 __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize));
4056 __ JumpIfNotSmi(r4, &with_write_barrier);
4057
4058 // Store the value.
4059 // We may need a register containing the address end_elements below, so
4060 // write back the value in end_elements.
4061 __ add(end_elements, elements, Operand::PointerOffsetFromSmiKey(scratch));
4062 __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex));
4063 } else {
4064 // Check if we could survive without allocation.
4065 __ cmp(scratch, r4);
4066 __ b(gt, &call_builtin);
4067
4068 __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize));
4069 __ StoreNumberToDoubleElements(r4, scratch, elements, r5, d0,
4070 &call_builtin, argc * kDoubleSize);
4071 }
4072
4073 // Save new length.
4074 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
4075 __ Drop(argc + 1);
4076 __ mov(r0, scratch);
4077 __ Ret();
4078
4079 if (IsFastDoubleElementsKind(elements_kind())) {
4080 __ bind(&call_builtin);
4081 __ TailCallExternalReference(
4082 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
4083 return;
4084 }
4085
4086 __ bind(&with_write_barrier);
4087
4088 if (IsFastSmiElementsKind(elements_kind())) {
4089 if (FLAG_trace_elements_transitions) __ jmp(&call_builtin);
4090
4091 __ ldr(r9, FieldMemOperand(r4, HeapObject::kMapOffset));
4092 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
4093 __ cmp(r9, ip);
4094 __ b(eq, &call_builtin);
4095
4096 ElementsKind target_kind = IsHoleyElementsKind(elements_kind())
4097 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
4098 __ ldr(r3, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
4099 __ ldr(r3, FieldMemOperand(r3, GlobalObject::kNativeContextOffset));
4100 __ ldr(r3, ContextOperand(r3, Context::JS_ARRAY_MAPS_INDEX));
4101 const int header_size = FixedArrayBase::kHeaderSize;
4102 // Verify that the object can be transitioned in place.
4103 const int origin_offset = header_size + elements_kind() * kPointerSize;
4104 __ ldr(r2, FieldMemOperand(receiver, origin_offset));
4105 __ ldr(ip, FieldMemOperand(r3, HeapObject::kMapOffset));
4106 __ cmp(r2, ip);
4107 __ b(ne, &call_builtin);
4108
4109 const int target_offset = header_size + target_kind * kPointerSize;
4110 __ ldr(r3, FieldMemOperand(r3, target_offset));
4111 __ mov(r2, receiver);
4112 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
4113 masm, DONT_TRACK_ALLOCATION_SITE, NULL);
4114 }
4115
4116 // Save new length.
4117 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
4118
4119 // Store the value.
4120 // We may need a register containing the address end_elements below, so write
4121 // back the value in end_elements.
4122 __ add(end_elements, elements, Operand::PointerOffsetFromSmiKey(scratch));
4123 __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex));
4124
4125 __ RecordWrite(elements,
4126 end_elements,
4127 r4,
4128 kLRHasNotBeenSaved,
4129 kDontSaveFPRegs,
4130 EMIT_REMEMBERED_SET,
4131 OMIT_SMI_CHECK);
4132 __ Drop(argc + 1);
4133 __ mov(r0, scratch);
4134 __ Ret();
4135
4136 __ bind(&attempt_to_grow_elements);
4137 // scratch: array's length + 1.
4138
4139 if (!FLAG_inline_new) {
4140 __ bind(&call_builtin);
4141 __ TailCallExternalReference(
4142 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
4143 return;
4144 }
4145
4146 __ ldr(r2, MemOperand(sp, (argc - 1) * kPointerSize));
4147 // Growing elements that are SMI-only requires special handling in case the
4148 // new element is non-Smi. For now, delegate to the builtin.
4149 if (IsFastSmiElementsKind(elements_kind())) {
4150 __ JumpIfNotSmi(r2, &call_builtin);
4151 }
4152
4153 // We could be lucky and the elements array could be at the top of new-space.
4154 // In this case we can just grow it in place by moving the allocation pointer
4155 // up.
4156 ExternalReference new_space_allocation_top =
4157 ExternalReference::new_space_allocation_top_address(isolate);
4158 ExternalReference new_space_allocation_limit =
4159 ExternalReference::new_space_allocation_limit_address(isolate);
4160
4161 const int kAllocationDelta = 4;
4162 ASSERT(kAllocationDelta >= argc);
4163 // Load top and check if it is the end of elements.
4164 __ add(end_elements, elements, Operand::PointerOffsetFromSmiKey(scratch));
4165 __ add(end_elements, end_elements, Operand(kEndElementsOffset));
4166 __ mov(r4, Operand(new_space_allocation_top));
4167 __ ldr(r3, MemOperand(r4));
4168 __ cmp(end_elements, r3);
4169 __ b(ne, &call_builtin);
4170
4171 __ mov(r9, Operand(new_space_allocation_limit));
4172 __ ldr(r9, MemOperand(r9));
4173 __ add(r3, r3, Operand(kAllocationDelta * kPointerSize));
4174 __ cmp(r3, r9);
4175 __ b(hi, &call_builtin);
4176
4177 // We fit and could grow elements.
4178 // Update new_space_allocation_top.
4179 __ str(r3, MemOperand(r4));
4180 // Push the argument.
4181 __ str(r2, MemOperand(end_elements));
4182 // Fill the rest with holes.
4183 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
4184 for (int i = 1; i < kAllocationDelta; i++) {
4185 __ str(r3, MemOperand(end_elements, i * kPointerSize));
4186 }
4187
4188 // Update elements' and array's sizes.
4189 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset));
4190 __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
4191 __ add(r4, r4, Operand(Smi::FromInt(kAllocationDelta)));
4192 __ str(r4, FieldMemOperand(elements, FixedArray::kLengthOffset));
4193
4194 // Elements are in new space, so write barrier is not required.
4195 __ Drop(argc + 1);
4196 __ mov(r0, scratch);
4197 __ Ret();
4198
4199 __ bind(&call_builtin);
4200 __ TailCallExternalReference(
4201 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1);
4202 }
4203
4204
4200 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { 4205 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
4201 // ----------- S t a t e ------------- 4206 // ----------- S t a t e -------------
4202 // -- r1 : left 4207 // -- r1 : left
4203 // -- r0 : right 4208 // -- r0 : right
4204 // -- lr : return address 4209 // -- lr : return address
4205 // ----------------------------------- 4210 // -----------------------------------
4206 Isolate* isolate = masm->isolate(); 4211 Isolate* isolate = masm->isolate();
4207 4212
4208 // Load r2 with the allocation site. We stick an undefined dummy value here 4213 // Load r2 with the allocation site. We stick an undefined dummy value here
4209 // and replace it with the real allocation site later when we instantiate this 4214 // and replace it with the real allocation site later when we instantiate this
(...skipping 12 matching lines...) Expand all
4222 __ Assert(eq, kExpectedAllocationSite); 4227 __ Assert(eq, kExpectedAllocationSite);
4223 } 4228 }
4224 4229
4225 // Tail call into the stub that handles binary operations with allocation 4230 // Tail call into the stub that handles binary operations with allocation
4226 // sites. 4231 // sites.
4227 BinaryOpWithAllocationSiteStub stub(state_); 4232 BinaryOpWithAllocationSiteStub stub(state_);
4228 __ TailCallStub(&stub); 4233 __ TailCallStub(&stub);
4229 } 4234 }
4230 4235
4231 4236
4232 void StringAddStub::Generate(MacroAssembler* masm) {
4233 Label call_runtime, call_builtin;
4234 Builtins::JavaScript builtin_id = Builtins::ADD;
4235
4236 Counters* counters = masm->isolate()->counters();
4237
4238 // Stack on entry:
4239 // sp[0]: second argument (right).
4240 // sp[4]: first argument (left).
4241
4242 // Load the two arguments.
4243 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument.
4244 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument.
4245
4246 // Make sure that both arguments are strings if not known in advance.
4247 // Otherwise, at least one of the arguments is definitely a string,
4248 // and we convert the one that is not known to be a string.
4249 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
4250 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT);
4251 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT);
4252 __ JumpIfEitherSmi(r0, r1, &call_runtime);
4253 // Load instance types.
4254 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
4255 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
4256 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
4257 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
4258 STATIC_ASSERT(kStringTag == 0);
4259 // If either is not a string, go to runtime.
4260 __ tst(r4, Operand(kIsNotStringMask));
4261 __ tst(r5, Operand(kIsNotStringMask), eq);
4262 __ b(ne, &call_runtime);
4263 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
4264 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0);
4265 GenerateConvertArgument(
4266 masm, 1 * kPointerSize, r0, r2, r3, r4, r5, &call_builtin);
4267 builtin_id = Builtins::STRING_ADD_RIGHT;
4268 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
4269 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0);
4270 GenerateConvertArgument(
4271 masm, 0 * kPointerSize, r1, r2, r3, r4, r5, &call_builtin);
4272 builtin_id = Builtins::STRING_ADD_LEFT;
4273 }
4274
4275 // Both arguments are strings.
4276 // r0: first string
4277 // r1: second string
4278 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
4279 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
4280 {
4281 Label strings_not_empty;
4282 // Check if either of the strings are empty. In that case return the other.
4283 __ ldr(r2, FieldMemOperand(r0, String::kLengthOffset));
4284 __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset));
4285 STATIC_ASSERT(kSmiTag == 0);
4286 __ cmp(r2, Operand(Smi::FromInt(0))); // Test if first string is empty.
4287 __ mov(r0, Operand(r1), LeaveCC, eq); // If first is empty, return second.
4288 STATIC_ASSERT(kSmiTag == 0);
4289 // Else test if second string is empty.
4290 __ cmp(r3, Operand(Smi::FromInt(0)), ne);
4291 __ b(ne, &strings_not_empty); // If either string was empty, return r0.
4292
4293 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
4294 __ add(sp, sp, Operand(2 * kPointerSize));
4295 __ Ret();
4296
4297 __ bind(&strings_not_empty);
4298 }
4299
4300 __ SmiUntag(r2);
4301 __ SmiUntag(r3);
4302 // Both strings are non-empty.
4303 // r0: first string
4304 // r1: second string
4305 // r2: length of first string
4306 // r3: length of second string
4307 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
4308 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
4309 // Look at the length of the result of adding the two strings.
4310 Label string_add_flat_result, longer_than_two;
4311 // Adding two lengths can't overflow.
4312 STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2);
4313 __ add(r6, r2, Operand(r3));
4314 // Use the string table when adding two one character strings, as it
4315 // helps later optimizations to return a string here.
4316 __ cmp(r6, Operand(2));
4317 __ b(ne, &longer_than_two);
4318
4319 // Check that both strings are non-external ASCII strings.
4320 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
4321 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
4322 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
4323 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
4324 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
4325 }
4326 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r3,
4327 &call_runtime);
4328
4329 // Get the two characters forming the sub string.
4330 __ ldrb(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize));
4331 __ ldrb(r3, FieldMemOperand(r1, SeqOneByteString::kHeaderSize));
4332
4333 // Try to lookup two character string in string table. If it is not found
4334 // just allocate a new one.
4335 Label make_two_character_string;
4336 StringHelper::GenerateTwoCharacterStringTableProbe(
4337 masm, r2, r3, r6, r0, r4, r5, r9, &make_two_character_string);
4338 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
4339 __ add(sp, sp, Operand(2 * kPointerSize));
4340 __ Ret();
4341
4342 __ bind(&make_two_character_string);
4343 // Resulting string has length 2 and first chars of two strings
4344 // are combined into single halfword in r2 register.
4345 // So we can fill resulting string without two loops by a single
4346 // halfword store instruction (which assumes that processor is
4347 // in a little endian mode)
4348 __ mov(r6, Operand(2));
4349 __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime);
4350 __ strh(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize));
4351 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
4352 __ add(sp, sp, Operand(2 * kPointerSize));
4353 __ Ret();
4354
4355 __ bind(&longer_than_two);
4356 // Check if resulting string will be flat.
4357 __ cmp(r6, Operand(ConsString::kMinLength));
4358 __ b(lt, &string_add_flat_result);
4359 // Handle exceptionally long strings in the runtime system.
4360 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0);
4361 ASSERT(IsPowerOf2(String::kMaxLength + 1));
4362 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not.
4363 __ cmp(r6, Operand(String::kMaxLength + 1));
4364 __ b(hs, &call_runtime);
4365
4366 // If result is not supposed to be flat, allocate a cons string object.
4367 // If both strings are ASCII the result is an ASCII cons string.
4368 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
4369 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
4370 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
4371 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
4372 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
4373 }
4374 Label non_ascii, allocated, ascii_data;
4375 STATIC_ASSERT(kTwoByteStringTag == 0);
4376 __ tst(r4, Operand(kStringEncodingMask));
4377 __ tst(r5, Operand(kStringEncodingMask), ne);
4378 __ b(eq, &non_ascii);
4379
4380 // Allocate an ASCII cons string.
4381 __ bind(&ascii_data);
4382 __ AllocateAsciiConsString(r3, r6, r4, r5, &call_runtime);
4383 __ bind(&allocated);
4384 // Fill the fields of the cons string.
4385 Label skip_write_barrier, after_writing;
4386 ExternalReference high_promotion_mode = ExternalReference::
4387 new_space_high_promotion_mode_active_address(masm->isolate());
4388 __ mov(r4, Operand(high_promotion_mode));
4389 __ ldr(r4, MemOperand(r4, 0));
4390 __ cmp(r4, Operand::Zero());
4391 __ b(eq, &skip_write_barrier);
4392
4393 __ str(r0, FieldMemOperand(r3, ConsString::kFirstOffset));
4394 __ RecordWriteField(r3,
4395 ConsString::kFirstOffset,
4396 r0,
4397 r4,
4398 kLRHasNotBeenSaved,
4399 kDontSaveFPRegs);
4400 __ str(r1, FieldMemOperand(r3, ConsString::kSecondOffset));
4401 __ RecordWriteField(r3,
4402 ConsString::kSecondOffset,
4403 r1,
4404 r4,
4405 kLRHasNotBeenSaved,
4406 kDontSaveFPRegs);
4407 __ jmp(&after_writing);
4408
4409 __ bind(&skip_write_barrier);
4410 __ str(r0, FieldMemOperand(r3, ConsString::kFirstOffset));
4411 __ str(r1, FieldMemOperand(r3, ConsString::kSecondOffset));
4412
4413 __ bind(&after_writing);
4414
4415 __ mov(r0, Operand(r3));
4416 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
4417 __ add(sp, sp, Operand(2 * kPointerSize));
4418 __ Ret();
4419
4420 __ bind(&non_ascii);
4421 // At least one of the strings is two-byte. Check whether it happens
4422 // to contain only one byte characters.
4423 // r4: first instance type.
4424 // r5: second instance type.
4425 __ tst(r4, Operand(kOneByteDataHintMask));
4426 __ tst(r5, Operand(kOneByteDataHintMask), ne);
4427 __ b(ne, &ascii_data);
4428 __ eor(r4, r4, Operand(r5));
4429 STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0);
4430 __ and_(r4, r4, Operand(kOneByteStringTag | kOneByteDataHintTag));
4431 __ cmp(r4, Operand(kOneByteStringTag | kOneByteDataHintTag));
4432 __ b(eq, &ascii_data);
4433
4434 // Allocate a two byte cons string.
4435 __ AllocateTwoByteConsString(r3, r6, r4, r5, &call_runtime);
4436 __ jmp(&allocated);
4437
4438 // We cannot encounter sliced strings or cons strings here since:
4439 STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength);
4440 // Handle creating a flat result from either external or sequential strings.
4441 // Locate the first characters' locations.
4442 // r0: first string
4443 // r1: second string
4444 // r2: length of first string
4445 // r3: length of second string
4446 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS)
4447 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS)
4448 // r6: sum of lengths.
4449 Label first_prepared, second_prepared;
4450 __ bind(&string_add_flat_result);
4451 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) {
4452 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
4453 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset));
4454 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
4455 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset));
4456 }
4457
4458 // Check whether both strings have same encoding
4459 __ eor(ip, r4, Operand(r5));
4460 ASSERT(__ ImmediateFitsAddrMode1Instruction(kStringEncodingMask));
4461 __ tst(ip, Operand(kStringEncodingMask));
4462 __ b(ne, &call_runtime);
4463
4464 STATIC_ASSERT(kSeqStringTag == 0);
4465 __ tst(r4, Operand(kStringRepresentationMask));
4466 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
4467 __ add(r6,
4468 r0,
4469 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag),
4470 LeaveCC,
4471 eq);
4472 __ b(eq, &first_prepared);
4473 // External string: rule out short external string and load string resource.
4474 STATIC_ASSERT(kShortExternalStringTag != 0);
4475 __ tst(r4, Operand(kShortExternalStringMask));
4476 __ b(ne, &call_runtime);
4477 __ ldr(r6, FieldMemOperand(r0, ExternalString::kResourceDataOffset));
4478 __ bind(&first_prepared);
4479
4480 STATIC_ASSERT(kSeqStringTag == 0);
4481 __ tst(r5, Operand(kStringRepresentationMask));
4482 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
4483 __ add(r1,
4484 r1,
4485 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag),
4486 LeaveCC,
4487 eq);
4488 __ b(eq, &second_prepared);
4489 // External string: rule out short external string and load string resource.
4490 STATIC_ASSERT(kShortExternalStringTag != 0);
4491 __ tst(r5, Operand(kShortExternalStringMask));
4492 __ b(ne, &call_runtime);
4493 __ ldr(r1, FieldMemOperand(r1, ExternalString::kResourceDataOffset));
4494 __ bind(&second_prepared);
4495
4496 Label non_ascii_string_add_flat_result;
4497 // r6: first character of first string
4498 // r1: first character of second string
4499 // r2: length of first string.
4500 // r3: length of second string.
4501 // Both strings have the same encoding.
4502 STATIC_ASSERT(kTwoByteStringTag == 0);
4503 __ tst(r5, Operand(kStringEncodingMask));
4504 __ b(eq, &non_ascii_string_add_flat_result);
4505
4506 __ add(r2, r2, Operand(r3));
4507 __ AllocateAsciiString(r0, r2, r4, r5, r9, &call_runtime);
4508 __ sub(r2, r2, Operand(r3));
4509 __ add(r5, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
4510 // r0: result string.
4511 // r6: first character of first string.
4512 // r1: first character of second string.
4513 // r2: length of first string.
4514 // r3: length of second string.
4515 // r5: first character of result.
4516 StringHelper::GenerateCopyCharacters(masm, r5, r6, r2, r4, true);
4517 // r5: next character of result.
4518 StringHelper::GenerateCopyCharacters(masm, r5, r1, r3, r4, true);
4519 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
4520 __ add(sp, sp, Operand(2 * kPointerSize));
4521 __ Ret();
4522
4523 __ bind(&non_ascii_string_add_flat_result);
4524 __ add(r2, r2, Operand(r3));
4525 __ AllocateTwoByteString(r0, r2, r4, r5, r9, &call_runtime);
4526 __ sub(r2, r2, Operand(r3));
4527 __ add(r5, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
4528 // r0: result string.
4529 // r6: first character of first string.
4530 // r1: first character of second string.
4531 // r2: length of first string.
4532 // r3: length of second string.
4533 // r5: first character of result.
4534 StringHelper::GenerateCopyCharacters(masm, r5, r6, r2, r4, false);
4535 // r5: next character of result.
4536 StringHelper::GenerateCopyCharacters(masm, r5, r1, r3, r4, false);
4537 __ IncrementCounter(counters->string_add_native(), 1, r2, r3);
4538 __ add(sp, sp, Operand(2 * kPointerSize));
4539 __ Ret();
4540
4541 // Just jump to runtime to add the two strings.
4542 __ bind(&call_runtime);
4543 __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
4544
4545 if (call_builtin.is_linked()) {
4546 __ bind(&call_builtin);
4547 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION);
4548 }
4549 }
4550
4551
4552 void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
4553 __ push(r0);
4554 __ push(r1);
4555 }
4556
4557
4558 void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm) {
4559 __ pop(r1);
4560 __ pop(r0);
4561 }
4562
4563
4564 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm,
4565 int stack_offset,
4566 Register arg,
4567 Register scratch1,
4568 Register scratch2,
4569 Register scratch3,
4570 Register scratch4,
4571 Label* slow) {
4572 // First check if the argument is already a string.
4573 Label not_string, done;
4574 __ JumpIfSmi(arg, &not_string);
4575 __ CompareObjectType(arg, scratch1, scratch1, FIRST_NONSTRING_TYPE);
4576 __ b(lt, &done);
4577
4578 // Check the number to string cache.
4579 __ bind(&not_string);
4580 // Puts the cached result into scratch1.
4581 __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, scratch4, slow);
4582 __ mov(arg, scratch1);
4583 __ str(arg, MemOperand(sp, stack_offset));
4584 __ bind(&done);
4585 }
4586
4587
4588 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { 4237 void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
4589 ASSERT(state_ == CompareIC::SMI); 4238 ASSERT(state_ == CompareIC::SMI);
4590 Label miss; 4239 Label miss;
4591 __ orr(r2, r1, r0); 4240 __ orr(r2, r1, r0);
4592 __ JumpIfNotSmi(r2, &miss); 4241 __ JumpIfNotSmi(r2, &miss);
4593 4242
4594 if (GetCondition() == eq) { 4243 if (GetCondition() == eq) {
4595 // For equality we do not care about the sign of the result. 4244 // For equality we do not care about the sign of the result.
4596 __ sub(r0, r0, r1, SetCC); 4245 __ sub(r0, r0, r1, SetCC);
4597 } else { 4246 } else {
(...skipping 975 matching lines...) Expand 10 before | Expand all | Expand 10 after
5573 // If we reached this point there is a problem. 5222 // If we reached this point there is a problem.
5574 __ Abort(kUnexpectedElementsKindInArrayConstructor); 5223 __ Abort(kUnexpectedElementsKindInArrayConstructor);
5575 } else { 5224 } else {
5576 UNREACHABLE(); 5225 UNREACHABLE();
5577 } 5226 }
5578 } 5227 }
5579 5228
5580 5229
5581 static void CreateArrayDispatchOneArgument(MacroAssembler* masm, 5230 static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
5582 AllocationSiteOverrideMode mode) { 5231 AllocationSiteOverrideMode mode) {
5583 // r2 - type info cell (if mode != DISABLE_ALLOCATION_SITES) 5232 // r2 - allocation site (if mode != DISABLE_ALLOCATION_SITES)
5584 // r3 - kind (if mode != DISABLE_ALLOCATION_SITES) 5233 // r3 - kind (if mode != DISABLE_ALLOCATION_SITES)
5585 // r0 - number of arguments 5234 // r0 - number of arguments
5586 // r1 - constructor? 5235 // r1 - constructor?
5587 // sp[0] - last argument 5236 // sp[0] - last argument
5588 Label normal_sequence; 5237 Label normal_sequence;
5589 if (mode == DONT_OVERRIDE) { 5238 if (mode == DONT_OVERRIDE) {
5590 ASSERT(FAST_SMI_ELEMENTS == 0); 5239 ASSERT(FAST_SMI_ELEMENTS == 0);
5591 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 5240 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
5592 ASSERT(FAST_ELEMENTS == 2); 5241 ASSERT(FAST_ELEMENTS == 2);
5593 ASSERT(FAST_HOLEY_ELEMENTS == 3); 5242 ASSERT(FAST_HOLEY_ELEMENTS == 3);
(...skipping 19 matching lines...) Expand all
5613 __ TailCallStub(&stub_holey); 5262 __ TailCallStub(&stub_holey);
5614 5263
5615 __ bind(&normal_sequence); 5264 __ bind(&normal_sequence);
5616 ArraySingleArgumentConstructorStub stub(initial, 5265 ArraySingleArgumentConstructorStub stub(initial,
5617 DISABLE_ALLOCATION_SITES); 5266 DISABLE_ALLOCATION_SITES);
5618 __ TailCallStub(&stub); 5267 __ TailCallStub(&stub);
5619 } else if (mode == DONT_OVERRIDE) { 5268 } else if (mode == DONT_OVERRIDE) {
5620 // We are going to create a holey array, but our kind is non-holey. 5269 // We are going to create a holey array, but our kind is non-holey.
5621 // Fix kind and retry (only if we have an allocation site in the cell). 5270 // Fix kind and retry (only if we have an allocation site in the cell).
5622 __ add(r3, r3, Operand(1)); 5271 __ add(r3, r3, Operand(1));
5623 __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
5624 5272
5625 if (FLAG_debug_code) { 5273 if (FLAG_debug_code) {
5626 __ ldr(r5, FieldMemOperand(r5, 0)); 5274 __ ldr(r5, FieldMemOperand(r2, 0));
5627 __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex); 5275 __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
5628 __ Assert(eq, kExpectedAllocationSiteInCell); 5276 __ Assert(eq, kExpectedAllocationSite);
5629 __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
5630 } 5277 }
5631 5278
5632 // Save the resulting elements kind in type info. We can't just store r3 5279 // Save the resulting elements kind in type info. We can't just store r3
5633 // in the AllocationSite::transition_info field because elements kind is 5280 // in the AllocationSite::transition_info field because elements kind is
5634 // restricted to a portion of the field...upper bits need to be left alone. 5281 // restricted to a portion of the field...upper bits need to be left alone.
5635 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); 5282 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
5636 __ ldr(r4, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset)); 5283 __ ldr(r4, FieldMemOperand(r2, AllocationSite::kTransitionInfoOffset));
5637 __ add(r4, r4, Operand(Smi::FromInt(kFastElementsKindPackedToHoley))); 5284 __ add(r4, r4, Operand(Smi::FromInt(kFastElementsKindPackedToHoley)));
5638 __ str(r4, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset)); 5285 __ str(r4, FieldMemOperand(r2, AllocationSite::kTransitionInfoOffset));
5639 5286
5640 __ bind(&normal_sequence); 5287 __ bind(&normal_sequence);
5641 int last_index = GetSequenceIndexFromFastElementsKind( 5288 int last_index = GetSequenceIndexFromFastElementsKind(
5642 TERMINAL_FAST_ELEMENTS_KIND); 5289 TERMINAL_FAST_ELEMENTS_KIND);
5643 for (int i = 0; i <= last_index; ++i) { 5290 for (int i = 0; i <= last_index; ++i) {
5644 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); 5291 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
5645 __ cmp(r3, Operand(kind)); 5292 __ cmp(r3, Operand(kind));
5646 ArraySingleArgumentConstructorStub stub(kind); 5293 ArraySingleArgumentConstructorStub stub(kind);
5647 __ TailCallStub(&stub, eq); 5294 __ TailCallStub(&stub, eq);
5648 } 5295 }
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
5752 __ ldr(r3, FieldMemOperand(r2, 0)); 5399 __ ldr(r3, FieldMemOperand(r2, 0));
5753 __ cmp(r3, Operand(cell_map)); 5400 __ cmp(r3, Operand(cell_map));
5754 __ Assert(eq, kExpectedPropertyCellInRegisterEbx); 5401 __ Assert(eq, kExpectedPropertyCellInRegisterEbx);
5755 __ bind(&okay_here); 5402 __ bind(&okay_here);
5756 } 5403 }
5757 5404
5758 Label no_info; 5405 Label no_info;
5759 // Get the elements kind and case on that. 5406 // Get the elements kind and case on that.
5760 __ CompareRoot(r2, Heap::kUndefinedValueRootIndex); 5407 __ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
5761 __ b(eq, &no_info); 5408 __ b(eq, &no_info);
5762 __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset)); 5409 __ ldr(r2, FieldMemOperand(r2, Cell::kValueOffset));
5763 5410
5764 // If the type cell is undefined, or contains anything other than an 5411 // If the type cell is undefined, or contains anything other than an
5765 // AllocationSite, call an array constructor that doesn't use AllocationSites. 5412 // AllocationSite, call an array constructor that doesn't use AllocationSites.
5766 __ ldr(r4, FieldMemOperand(r3, 0)); 5413 __ ldr(r4, FieldMemOperand(r2, 0));
5767 __ CompareRoot(r4, Heap::kAllocationSiteMapRootIndex); 5414 __ CompareRoot(r4, Heap::kAllocationSiteMapRootIndex);
5768 __ b(ne, &no_info); 5415 __ b(ne, &no_info);
5769 5416
5770 __ ldr(r3, FieldMemOperand(r3, AllocationSite::kTransitionInfoOffset)); 5417 __ ldr(r3, FieldMemOperand(r2, AllocationSite::kTransitionInfoOffset));
5771 __ SmiUntag(r3); 5418 __ SmiUntag(r3);
5772 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); 5419 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
5773 __ and_(r3, r3, Operand(AllocationSite::ElementsKindBits::kMask)); 5420 __ and_(r3, r3, Operand(AllocationSite::ElementsKindBits::kMask));
5774 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); 5421 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
5775 5422
5776 __ bind(&no_info); 5423 __ bind(&no_info);
5777 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); 5424 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
5778 } 5425 }
5779 5426
5780 5427
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
5851 __ bind(&fast_elements_case); 5498 __ bind(&fast_elements_case);
5852 GenerateCase(masm, FAST_ELEMENTS); 5499 GenerateCase(masm, FAST_ELEMENTS);
5853 } 5500 }
5854 5501
5855 5502
5856 #undef __ 5503 #undef __
5857 5504
5858 } } // namespace v8::internal 5505 } } // namespace v8::internal
5859 5506
5860 #endif // V8_TARGET_ARCH_ARM 5507 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « src/arm/code-stubs-arm.h ('k') | src/arm/codegen-arm.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698