| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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, ¬_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(¬_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 Loading... |
| 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 Loading... |
| 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, ¬_string); | |
| 4575 __ CompareObjectType(arg, scratch1, scratch1, FIRST_NONSTRING_TYPE); | |
| 4576 __ b(lt, &done); | |
| 4577 | |
| 4578 // Check the number to string cache. | |
| 4579 __ bind(¬_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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |