| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 13 matching lines...) Expand all Loading... |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "bootstrapper.h" | 30 #include "bootstrapper.h" |
| 31 #include "codegen-inl.h" | 31 #include "codegen-inl.h" |
| 32 #include "compiler.h" | 32 #include "compiler.h" |
| 33 #include "debug.h" | 33 #include "debug.h" |
| 34 #include "ic-inl.h" |
| 34 #include "parser.h" | 35 #include "parser.h" |
| 35 #include "register-allocator-inl.h" | 36 #include "register-allocator-inl.h" |
| 36 #include "runtime.h" | 37 #include "runtime.h" |
| 37 #include "scopes.h" | 38 #include "scopes.h" |
| 38 | 39 #include "virtual-frame-inl.h" |
| 39 | 40 |
| 40 namespace v8 { | 41 namespace v8 { |
| 41 namespace internal { | 42 namespace internal { |
| 42 | 43 |
| 43 #define __ ACCESS_MASM(masm_) | 44 #define __ ACCESS_MASM(masm_) |
| 44 | 45 |
| 45 static void EmitIdenticalObjectComparison(MacroAssembler* masm, | 46 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
| 46 Label* slow, | 47 Label* slow, |
| 47 Condition cc, | 48 Condition cc, |
| 48 bool never_nan_nan); | 49 bool never_nan_nan); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 masm_(masm), | 127 masm_(masm), |
| 127 info_(NULL), | 128 info_(NULL), |
| 128 frame_(NULL), | 129 frame_(NULL), |
| 129 allocator_(NULL), | 130 allocator_(NULL), |
| 130 cc_reg_(al), | 131 cc_reg_(al), |
| 131 state_(NULL), | 132 state_(NULL), |
| 132 function_return_is_shadowed_(false) { | 133 function_return_is_shadowed_(false) { |
| 133 } | 134 } |
| 134 | 135 |
| 135 | 136 |
| 136 Scope* CodeGenerator::scope() { return info_->function()->scope(); } | |
| 137 | |
| 138 | |
| 139 // Calling conventions: | 137 // Calling conventions: |
| 140 // fp: caller's frame pointer | 138 // fp: caller's frame pointer |
| 141 // sp: stack pointer | 139 // sp: stack pointer |
| 142 // r1: called JS function | 140 // r1: called JS function |
| 143 // cp: callee's context | 141 // cp: callee's context |
| 144 | 142 |
| 145 void CodeGenerator::Generate(CompilationInfo* info) { | 143 void CodeGenerator::Generate(CompilationInfo* info) { |
| 146 // Record the position for debugging purposes. | 144 // Record the position for debugging purposes. |
| 147 CodeForFunctionPosition(info->function()); | 145 CodeForFunctionPosition(info->function()); |
| 146 Comment cmnt(masm_, "[ function compiled by virtual frame code generator"); |
| 148 | 147 |
| 149 // Initialize state. | 148 // Initialize state. |
| 150 info_ = info; | 149 info_ = info; |
| 151 ASSERT(allocator_ == NULL); | 150 ASSERT(allocator_ == NULL); |
| 152 RegisterAllocator register_allocator(this); | 151 RegisterAllocator register_allocator(this); |
| 153 allocator_ = ®ister_allocator; | 152 allocator_ = ®ister_allocator; |
| 154 ASSERT(frame_ == NULL); | 153 ASSERT(frame_ == NULL); |
| 155 frame_ = new VirtualFrame(); | 154 frame_ = new VirtualFrame(); |
| 156 cc_reg_ = al; | 155 cc_reg_ = al; |
| 157 { | 156 { |
| (...skipping 3159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3317 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 3316 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 3318 VirtualFrame::SpilledScope spilled_scope; | 3317 VirtualFrame::SpilledScope spilled_scope; |
| 3319 ASSERT(args->length() == 1); | 3318 ASSERT(args->length() == 1); |
| 3320 LoadAndSpill(args->at(0)); | 3319 LoadAndSpill(args->at(0)); |
| 3321 frame_->EmitPop(r0); | 3320 frame_->EmitPop(r0); |
| 3322 __ tst(r0, Operand(kSmiTagMask | 0x80000000u)); | 3321 __ tst(r0, Operand(kSmiTagMask | 0x80000000u)); |
| 3323 cc_reg_ = eq; | 3322 cc_reg_ = eq; |
| 3324 } | 3323 } |
| 3325 | 3324 |
| 3326 | 3325 |
| 3326 // Generates the Math.pow method - currently just calls runtime. |
| 3327 void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { |
| 3328 ASSERT(args->length() == 2); |
| 3329 Load(args->at(0)); |
| 3330 Load(args->at(1)); |
| 3331 frame_->CallRuntime(Runtime::kMath_pow, 2); |
| 3332 frame_->EmitPush(r0); |
| 3333 } |
| 3334 |
| 3335 |
| 3336 // Generates the Math.sqrt method - currently just calls runtime. |
| 3337 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { |
| 3338 ASSERT(args->length() == 1); |
| 3339 Load(args->at(0)); |
| 3340 frame_->CallRuntime(Runtime::kMath_sqrt, 1); |
| 3341 frame_->EmitPush(r0); |
| 3342 } |
| 3343 |
| 3344 |
| 3327 // This should generate code that performs a charCodeAt() call or returns | 3345 // This should generate code that performs a charCodeAt() call or returns |
| 3328 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 3346 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
| 3329 // It is not yet implemented on ARM, so it always goes to the slow case. | 3347 // It is not yet implemented on ARM, so it always goes to the slow case. |
| 3330 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 3348 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| 3331 VirtualFrame::SpilledScope spilled_scope; | 3349 VirtualFrame::SpilledScope spilled_scope; |
| 3332 ASSERT(args->length() == 2); | 3350 ASSERT(args->length() == 2); |
| 3333 Comment(masm_, "[ GenerateFastCharCodeAt"); | 3351 Comment(masm_, "[ GenerateFastCharCodeAt"); |
| 3334 | 3352 |
| 3335 LoadAndSpill(args->at(0)); | 3353 LoadAndSpill(args->at(0)); |
| 3336 LoadAndSpill(args->at(1)); | 3354 LoadAndSpill(args->at(1)); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3400 __ jmp(&try_again_with_new_string); | 3418 __ jmp(&try_again_with_new_string); |
| 3401 | 3419 |
| 3402 __ bind(&slow); | 3420 __ bind(&slow); |
| 3403 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 3421 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
| 3404 | 3422 |
| 3405 __ bind(&end); | 3423 __ bind(&end); |
| 3406 frame_->EmitPush(r0); | 3424 frame_->EmitPush(r0); |
| 3407 } | 3425 } |
| 3408 | 3426 |
| 3409 | 3427 |
| 3428 void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) { |
| 3429 Comment(masm_, "[ GenerateCharFromCode"); |
| 3430 ASSERT(args->length() == 1); |
| 3431 |
| 3432 LoadAndSpill(args->at(0)); |
| 3433 frame_->EmitPop(r0); |
| 3434 |
| 3435 JumpTarget slow_case; |
| 3436 JumpTarget exit; |
| 3437 |
| 3438 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
| 3439 ASSERT(kSmiTag == 0); |
| 3440 ASSERT(kSmiShiftSize == 0); |
| 3441 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
| 3442 __ tst(r0, Operand(kSmiTagMask | |
| 3443 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
| 3444 slow_case.Branch(nz); |
| 3445 |
| 3446 ASSERT(kSmiTag == 0); |
| 3447 __ mov(r1, Operand(Factory::single_character_string_cache())); |
| 3448 __ add(r1, r1, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 3449 __ ldr(r1, MemOperand(r1, FixedArray::kHeaderSize - kHeapObjectTag)); |
| 3450 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
| 3451 __ cmp(r1, ip); |
| 3452 slow_case.Branch(eq); |
| 3453 |
| 3454 frame_->EmitPush(r1); |
| 3455 exit.Jump(); |
| 3456 |
| 3457 slow_case.Bind(); |
| 3458 frame_->EmitPush(r0); |
| 3459 frame_->CallRuntime(Runtime::kCharFromCode, 1); |
| 3460 frame_->EmitPush(r0); |
| 3461 |
| 3462 exit.Bind(); |
| 3463 } |
| 3464 |
| 3465 |
| 3410 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 3466 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 3411 VirtualFrame::SpilledScope spilled_scope; | 3467 VirtualFrame::SpilledScope spilled_scope; |
| 3412 ASSERT(args->length() == 1); | 3468 ASSERT(args->length() == 1); |
| 3413 LoadAndSpill(args->at(0)); | 3469 LoadAndSpill(args->at(0)); |
| 3414 JumpTarget answer; | 3470 JumpTarget answer; |
| 3415 // We need the CC bits to come out as not_equal in the case where the | 3471 // We need the CC bits to come out as not_equal in the case where the |
| 3416 // object is a smi. This can't be done with the usual test opcode so | 3472 // object is a smi. This can't be done with the usual test opcode so |
| 3417 // we use XOR to get the right CC bits. | 3473 // we use XOR to get the right CC bits. |
| 3418 frame_->EmitPop(r0); | 3474 frame_->EmitPop(r0); |
| 3419 __ and_(r1, r0, Operand(kSmiTagMask)); | 3475 __ and_(r1, r0, Operand(kSmiTagMask)); |
| (...skipping 1083 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4503 } | 4559 } |
| 4504 } | 4560 } |
| 4505 | 4561 |
| 4506 // Return result. The argument boilerplate has been popped already. | 4562 // Return result. The argument boilerplate has been popped already. |
| 4507 __ Ret(); | 4563 __ Ret(); |
| 4508 | 4564 |
| 4509 // Create a new closure through the slower runtime call. | 4565 // Create a new closure through the slower runtime call. |
| 4510 __ bind(&gc); | 4566 __ bind(&gc); |
| 4511 __ push(cp); | 4567 __ push(cp); |
| 4512 __ push(r3); | 4568 __ push(r3); |
| 4513 __ TailCallRuntime(ExternalReference(Runtime::kNewClosure), 2, 1); | 4569 __ TailCallRuntime(Runtime::kNewClosure, 2, 1); |
| 4514 } | 4570 } |
| 4515 | 4571 |
| 4516 | 4572 |
| 4517 void FastNewContextStub::Generate(MacroAssembler* masm) { | 4573 void FastNewContextStub::Generate(MacroAssembler* masm) { |
| 4518 // Try to allocate the context in new space. | 4574 // Try to allocate the context in new space. |
| 4519 Label gc; | 4575 Label gc; |
| 4520 int length = slots_ + Context::MIN_CONTEXT_SLOTS; | 4576 int length = slots_ + Context::MIN_CONTEXT_SLOTS; |
| 4521 | 4577 |
| 4522 // Attempt to allocate the context in new space. | 4578 // Attempt to allocate the context in new space. |
| 4523 __ AllocateInNewSpace(length + (FixedArray::kHeaderSize / kPointerSize), | 4579 __ AllocateInNewSpace(length + (FixedArray::kHeaderSize / kPointerSize), |
| (...skipping 29 matching lines...) Expand all Loading... |
| 4553 __ str(r1, MemOperand(r0, Context::SlotOffset(i))); | 4609 __ str(r1, MemOperand(r0, Context::SlotOffset(i))); |
| 4554 } | 4610 } |
| 4555 | 4611 |
| 4556 // Remove the on-stack argument and return. | 4612 // Remove the on-stack argument and return. |
| 4557 __ mov(cp, r0); | 4613 __ mov(cp, r0); |
| 4558 __ pop(); | 4614 __ pop(); |
| 4559 __ Ret(); | 4615 __ Ret(); |
| 4560 | 4616 |
| 4561 // Need to collect. Call into runtime system. | 4617 // Need to collect. Call into runtime system. |
| 4562 __ bind(&gc); | 4618 __ bind(&gc); |
| 4563 __ TailCallRuntime(ExternalReference(Runtime::kNewContext), 1, 1); | 4619 __ TailCallRuntime(Runtime::kNewContext, 1, 1); |
| 4564 } | 4620 } |
| 4565 | 4621 |
| 4566 | 4622 |
| 4567 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { | 4623 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
| 4568 // Stack layout on entry: | 4624 // Stack layout on entry: |
| 4569 // | 4625 // |
| 4570 // [sp]: constant elements. | 4626 // [sp]: constant elements. |
| 4571 // [sp + kPointerSize]: literal index. | 4627 // [sp + kPointerSize]: literal index. |
| 4572 // [sp + (2 * kPointerSize)]: literals array. | 4628 // [sp + (2 * kPointerSize)]: literals array. |
| 4573 | 4629 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4615 __ ldr(r1, FieldMemOperand(r3, i)); | 4671 __ ldr(r1, FieldMemOperand(r3, i)); |
| 4616 __ str(r1, FieldMemOperand(r2, i)); | 4672 __ str(r1, FieldMemOperand(r2, i)); |
| 4617 } | 4673 } |
| 4618 } | 4674 } |
| 4619 | 4675 |
| 4620 // Return and remove the on-stack parameters. | 4676 // Return and remove the on-stack parameters. |
| 4621 __ add(sp, sp, Operand(3 * kPointerSize)); | 4677 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 4622 __ Ret(); | 4678 __ Ret(); |
| 4623 | 4679 |
| 4624 __ bind(&slow_case); | 4680 __ bind(&slow_case); |
| 4625 ExternalReference runtime(Runtime::kCreateArrayLiteralShallow); | 4681 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
| 4626 __ TailCallRuntime(runtime, 3, 1); | |
| 4627 } | 4682 } |
| 4628 | 4683 |
| 4629 | 4684 |
| 4630 // Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz | 4685 // Count leading zeros in a 32 bit word. On ARM5 and later it uses the clz |
| 4631 // instruction. On pre-ARM5 hardware this routine gives the wrong answer for 0 | 4686 // instruction. On pre-ARM5 hardware this routine gives the wrong answer for 0 |
| 4632 // (31 instead of 32). | 4687 // (31 instead of 32). |
| 4633 static void CountLeadingZeros( | 4688 static void CountLeadingZeros( |
| 4634 MacroAssembler* masm, | 4689 MacroAssembler* masm, |
| 4635 Register source, | 4690 Register source, |
| 4636 Register scratch, | 4691 Register scratch, |
| (...skipping 1547 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6184 break; | 6239 break; |
| 6185 } | 6240 } |
| 6186 | 6241 |
| 6187 default: UNREACHABLE(); | 6242 default: UNREACHABLE(); |
| 6188 } | 6243 } |
| 6189 // This code should be unreachable. | 6244 // This code should be unreachable. |
| 6190 __ stop("Unreachable"); | 6245 __ stop("Unreachable"); |
| 6191 } | 6246 } |
| 6192 | 6247 |
| 6193 | 6248 |
| 6249 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { |
| 6250 return Handle<Code>::null(); |
| 6251 } |
| 6252 |
| 6253 |
| 6194 void StackCheckStub::Generate(MacroAssembler* masm) { | 6254 void StackCheckStub::Generate(MacroAssembler* masm) { |
| 6195 // Do tail-call to runtime routine. Runtime routines expect at least one | 6255 // Do tail-call to runtime routine. Runtime routines expect at least one |
| 6196 // argument, so give it a Smi. | 6256 // argument, so give it a Smi. |
| 6197 __ mov(r0, Operand(Smi::FromInt(0))); | 6257 __ mov(r0, Operand(Smi::FromInt(0))); |
| 6198 __ push(r0); | 6258 __ push(r0); |
| 6199 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1, 1); | 6259 __ TailCallRuntime(Runtime::kStackGuard, 1, 1); |
| 6200 | 6260 |
| 6201 __ StubReturn(1); | 6261 __ StubReturn(1); |
| 6202 } | 6262 } |
| 6203 | 6263 |
| 6204 | 6264 |
| 6205 void GenericUnaryOpStub::Generate(MacroAssembler* masm) { | 6265 void GenericUnaryOpStub::Generate(MacroAssembler* masm) { |
| 6206 Label slow, done; | 6266 Label slow, done; |
| 6207 | 6267 |
| 6208 if (op_ == Token::SUB) { | 6268 if (op_ == Token::SUB) { |
| 6209 // Check whether the value is a smi. | 6269 // Check whether the value is a smi. |
| (...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6798 // Read the argument from the adaptor frame and return it. | 6858 // Read the argument from the adaptor frame and return it. |
| 6799 __ sub(r3, r0, r1); | 6859 __ sub(r3, r0, r1); |
| 6800 __ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); | 6860 __ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| 6801 __ ldr(r0, MemOperand(r3, kDisplacement)); | 6861 __ ldr(r0, MemOperand(r3, kDisplacement)); |
| 6802 __ Jump(lr); | 6862 __ Jump(lr); |
| 6803 | 6863 |
| 6804 // Slow-case: Handle non-smi or out-of-bounds access to arguments | 6864 // Slow-case: Handle non-smi or out-of-bounds access to arguments |
| 6805 // by calling the runtime system. | 6865 // by calling the runtime system. |
| 6806 __ bind(&slow); | 6866 __ bind(&slow); |
| 6807 __ push(r1); | 6867 __ push(r1); |
| 6808 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1, 1); | 6868 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); |
| 6809 } | 6869 } |
| 6810 | 6870 |
| 6811 | 6871 |
| 6812 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { | 6872 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { |
| 6813 // sp[0] : number of parameters | 6873 // sp[0] : number of parameters |
| 6814 // sp[4] : receiver displacement | 6874 // sp[4] : receiver displacement |
| 6815 // sp[8] : function | 6875 // sp[8] : function |
| 6816 | 6876 |
| 6817 // Check if the calling frame is an arguments adaptor frame. | 6877 // Check if the calling frame is an arguments adaptor frame. |
| 6818 Label adaptor_frame, try_allocate, runtime; | 6878 Label adaptor_frame, try_allocate, runtime; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6901 __ cmp(r1, Operand(0)); | 6961 __ cmp(r1, Operand(0)); |
| 6902 __ b(ne, &loop); | 6962 __ b(ne, &loop); |
| 6903 | 6963 |
| 6904 // Return and remove the on-stack parameters. | 6964 // Return and remove the on-stack parameters. |
| 6905 __ bind(&done); | 6965 __ bind(&done); |
| 6906 __ add(sp, sp, Operand(3 * kPointerSize)); | 6966 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 6907 __ Ret(); | 6967 __ Ret(); |
| 6908 | 6968 |
| 6909 // Do the runtime call to allocate the arguments object. | 6969 // Do the runtime call to allocate the arguments object. |
| 6910 __ bind(&runtime); | 6970 __ bind(&runtime); |
| 6911 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1); | 6971 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); |
| 6912 } | 6972 } |
| 6913 | 6973 |
| 6914 | 6974 |
| 6915 void CallFunctionStub::Generate(MacroAssembler* masm) { | 6975 void CallFunctionStub::Generate(MacroAssembler* masm) { |
| 6916 Label slow; | 6976 Label slow; |
| 6917 | 6977 |
| 6918 // If the receiver might be a value (string, number or boolean) check for this | 6978 // If the receiver might be a value (string, number or boolean) check for this |
| 6919 // and box it if it is. | 6979 // and box it if it is. |
| 6920 if (ReceiverMightBeValue()) { | 6980 if (ReceiverMightBeValue()) { |
| 6921 // Get the receiver from the stack. | 6981 // Get the receiver from the stack. |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7192 __ cmp(dest, Operand(limit)); | 7252 __ cmp(dest, Operand(limit)); |
| 7193 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt); | 7253 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt); |
| 7194 __ b(ge, &done); | 7254 __ b(ge, &done); |
| 7195 __ strb(scratch1, MemOperand(dest, 1, PostIndex)); | 7255 __ strb(scratch1, MemOperand(dest, 1, PostIndex)); |
| 7196 __ b(&byte_loop); | 7256 __ b(&byte_loop); |
| 7197 | 7257 |
| 7198 __ bind(&done); | 7258 __ bind(&done); |
| 7199 } | 7259 } |
| 7200 | 7260 |
| 7201 | 7261 |
| 7262 void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
| 7263 Register c1, |
| 7264 Register c2, |
| 7265 Register scratch1, |
| 7266 Register scratch2, |
| 7267 Register scratch3, |
| 7268 Register scratch4, |
| 7269 Register scratch5, |
| 7270 Label* not_found) { |
| 7271 // Register scratch3 is the general scratch register in this function. |
| 7272 Register scratch = scratch3; |
| 7273 |
| 7274 // Make sure that both characters are not digits as such strings has a |
| 7275 // different hash algorithm. Don't try to look for these in the symbol table. |
| 7276 Label not_array_index; |
| 7277 __ sub(scratch, c1, Operand(static_cast<int>('0'))); |
| 7278 __ cmp(scratch, Operand(static_cast<int>('9' - '0'))); |
| 7279 __ b(hi, ¬_array_index); |
| 7280 __ sub(scratch, c2, Operand(static_cast<int>('0'))); |
| 7281 __ cmp(scratch, Operand(static_cast<int>('9' - '0'))); |
| 7282 |
| 7283 // If check failed combine both characters into single halfword. |
| 7284 // This is required by the contract of the method: code at the |
| 7285 // not_found branch expects this combination in c1 register |
| 7286 __ orr(c1, c1, Operand(c2, LSL, kBitsPerByte), LeaveCC, ls); |
| 7287 __ b(ls, not_found); |
| 7288 |
| 7289 __ bind(¬_array_index); |
| 7290 // Calculate the two character string hash. |
| 7291 Register hash = scratch1; |
| 7292 GenerateHashInit(masm, hash, c1); |
| 7293 GenerateHashAddCharacter(masm, hash, c2); |
| 7294 GenerateHashGetHash(masm, hash); |
| 7295 |
| 7296 // Collect the two characters in a register. |
| 7297 Register chars = c1; |
| 7298 __ orr(chars, chars, Operand(c2, LSL, kBitsPerByte)); |
| 7299 |
| 7300 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. |
| 7301 // hash: hash of two character string. |
| 7302 |
| 7303 // Load symbol table |
| 7304 // Load address of first element of the symbol table. |
| 7305 Register symbol_table = c2; |
| 7306 __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex); |
| 7307 |
| 7308 // Load undefined value |
| 7309 Register undefined = scratch4; |
| 7310 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); |
| 7311 |
| 7312 // Calculate capacity mask from the symbol table capacity. |
| 7313 Register mask = scratch2; |
| 7314 __ ldr(mask, FieldMemOperand(symbol_table, SymbolTable::kCapacityOffset)); |
| 7315 __ mov(mask, Operand(mask, ASR, 1)); |
| 7316 __ sub(mask, mask, Operand(1)); |
| 7317 |
| 7318 // Calculate untagged address of the first element of the symbol table. |
| 7319 Register first_symbol_table_element = symbol_table; |
| 7320 __ add(first_symbol_table_element, symbol_table, |
| 7321 Operand(SymbolTable::kElementsStartOffset - kHeapObjectTag)); |
| 7322 |
| 7323 // Registers |
| 7324 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. |
| 7325 // hash: hash of two character string |
| 7326 // mask: capacity mask |
| 7327 // first_symbol_table_element: address of the first element of |
| 7328 // the symbol table |
| 7329 // scratch: - |
| 7330 |
| 7331 // Perform a number of probes in the symbol table. |
| 7332 static const int kProbes = 4; |
| 7333 Label found_in_symbol_table; |
| 7334 Label next_probe[kProbes]; |
| 7335 for (int i = 0; i < kProbes; i++) { |
| 7336 Register candidate = scratch5; // Scratch register contains candidate. |
| 7337 |
| 7338 // Calculate entry in symbol table. |
| 7339 if (i > 0) { |
| 7340 __ add(candidate, hash, Operand(SymbolTable::GetProbeOffset(i))); |
| 7341 } else { |
| 7342 __ mov(candidate, hash); |
| 7343 } |
| 7344 |
| 7345 __ and_(candidate, candidate, Operand(mask)); |
| 7346 |
| 7347 // Load the entry from the symble table. |
| 7348 ASSERT_EQ(1, SymbolTable::kEntrySize); |
| 7349 __ ldr(candidate, |
| 7350 MemOperand(first_symbol_table_element, |
| 7351 candidate, |
| 7352 LSL, |
| 7353 kPointerSizeLog2)); |
| 7354 |
| 7355 // If entry is undefined no string with this hash can be found. |
| 7356 __ cmp(candidate, undefined); |
| 7357 __ b(eq, not_found); |
| 7358 |
| 7359 // If length is not 2 the string is not a candidate. |
| 7360 __ ldr(scratch, FieldMemOperand(candidate, String::kLengthOffset)); |
| 7361 __ cmp(scratch, Operand(2)); |
| 7362 __ b(ne, &next_probe[i]); |
| 7363 |
| 7364 // Check that the candidate is a non-external ascii string. |
| 7365 __ ldr(scratch, FieldMemOperand(candidate, HeapObject::kMapOffset)); |
| 7366 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); |
| 7367 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, |
| 7368 &next_probe[i]); |
| 7369 |
| 7370 // Check if the two characters match. |
| 7371 // Assumes that word load is little endian. |
| 7372 __ ldrh(scratch, FieldMemOperand(candidate, SeqAsciiString::kHeaderSize)); |
| 7373 __ cmp(chars, scratch); |
| 7374 __ b(eq, &found_in_symbol_table); |
| 7375 __ bind(&next_probe[i]); |
| 7376 } |
| 7377 |
| 7378 // No matching 2 character string found by probing. |
| 7379 __ jmp(not_found); |
| 7380 |
| 7381 // Scratch register contains result when we fall through to here. |
| 7382 Register result = scratch; |
| 7383 __ bind(&found_in_symbol_table); |
| 7384 if (!result.is(r0)) { |
| 7385 __ mov(r0, result); |
| 7386 } |
| 7387 } |
| 7388 |
| 7389 |
| 7390 void StringStubBase::GenerateHashInit(MacroAssembler* masm, |
| 7391 Register hash, |
| 7392 Register character) { |
| 7393 // hash = character + (character << 10); |
| 7394 __ add(hash, character, Operand(character, LSL, 10)); |
| 7395 // hash ^= hash >> 6; |
| 7396 __ eor(hash, hash, Operand(hash, ASR, 6)); |
| 7397 } |
| 7398 |
| 7399 |
| 7400 void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, |
| 7401 Register hash, |
| 7402 Register character) { |
| 7403 // hash += character; |
| 7404 __ add(hash, hash, Operand(character)); |
| 7405 // hash += hash << 10; |
| 7406 __ add(hash, hash, Operand(hash, LSL, 10)); |
| 7407 // hash ^= hash >> 6; |
| 7408 __ eor(hash, hash, Operand(hash, ASR, 6)); |
| 7409 } |
| 7410 |
| 7411 |
| 7412 void StringStubBase::GenerateHashGetHash(MacroAssembler* masm, |
| 7413 Register hash) { |
| 7414 // hash += hash << 3; |
| 7415 __ add(hash, hash, Operand(hash, LSL, 3)); |
| 7416 // hash ^= hash >> 11; |
| 7417 __ eor(hash, hash, Operand(hash, ASR, 11)); |
| 7418 // hash += hash << 15; |
| 7419 __ add(hash, hash, Operand(hash, LSL, 15), SetCC); |
| 7420 |
| 7421 // if (hash == 0) hash = 27; |
| 7422 __ mov(hash, Operand(27), LeaveCC, nz); |
| 7423 } |
| 7424 |
| 7425 |
| 7202 void SubStringStub::Generate(MacroAssembler* masm) { | 7426 void SubStringStub::Generate(MacroAssembler* masm) { |
| 7203 Label runtime; | 7427 Label runtime; |
| 7204 | 7428 |
| 7205 // Stack frame on entry. | 7429 // Stack frame on entry. |
| 7206 // lr: return address | 7430 // lr: return address |
| 7207 // sp[0]: to | 7431 // sp[0]: to |
| 7208 // sp[4]: from | 7432 // sp[4]: from |
| 7209 // sp[8]: string | 7433 // sp[8]: string |
| 7210 | 7434 |
| 7211 // This stub is called from the native-call %_SubString(...), so | 7435 // This stub is called from the native-call %_SubString(...), so |
| (...skipping 15 matching lines...) Expand all Loading... |
| 7227 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 7451 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); |
| 7228 // I.e., arithmetic shift right by one un-smi-tags. | 7452 // I.e., arithmetic shift right by one un-smi-tags. |
| 7229 __ mov(r2, Operand(r7, ASR, 1), SetCC); | 7453 __ mov(r2, Operand(r7, ASR, 1), SetCC); |
| 7230 __ mov(r3, Operand(r6, ASR, 1), SetCC, cc); | 7454 __ mov(r3, Operand(r6, ASR, 1), SetCC, cc); |
| 7231 // If either r2 or r6 had the smi tag bit set, then carry is set now. | 7455 // If either r2 or r6 had the smi tag bit set, then carry is set now. |
| 7232 __ b(cs, &runtime); // Either "from" or "to" is not a smi. | 7456 __ b(cs, &runtime); // Either "from" or "to" is not a smi. |
| 7233 __ b(mi, &runtime); // From is negative. | 7457 __ b(mi, &runtime); // From is negative. |
| 7234 | 7458 |
| 7235 __ sub(r2, r2, Operand(r3), SetCC); | 7459 __ sub(r2, r2, Operand(r3), SetCC); |
| 7236 __ b(mi, &runtime); // Fail if from > to. | 7460 __ b(mi, &runtime); // Fail if from > to. |
| 7237 // Handle sub-strings of length 2 and less in the runtime system. | 7461 // Special handling of sub-strings of length 1 and 2. One character strings |
| 7462 // are handled in the runtime system (looked up in the single character |
| 7463 // cache). Two character strings are looked for in the symbol cache. |
| 7238 __ cmp(r2, Operand(2)); | 7464 __ cmp(r2, Operand(2)); |
| 7239 __ b(le, &runtime); | 7465 __ b(lt, &runtime); |
| 7240 | 7466 |
| 7241 // r2: length | 7467 // r2: length |
| 7468 // r3: from index (untaged smi) |
| 7242 // r6: from (smi) | 7469 // r6: from (smi) |
| 7243 // r7: to (smi) | 7470 // r7: to (smi) |
| 7244 | 7471 |
| 7245 // Make sure first argument is a sequential (or flat) string. | 7472 // Make sure first argument is a sequential (or flat) string. |
| 7246 __ ldr(r5, MemOperand(sp, kStringOffset)); | 7473 __ ldr(r5, MemOperand(sp, kStringOffset)); |
| 7247 ASSERT_EQ(0, kSmiTag); | 7474 ASSERT_EQ(0, kSmiTag); |
| 7248 __ tst(r5, Operand(kSmiTagMask)); | 7475 __ tst(r5, Operand(kSmiTagMask)); |
| 7249 __ b(eq, &runtime); | 7476 __ b(eq, &runtime); |
| 7250 Condition is_string = masm->IsObjectStringType(r5, r1); | 7477 Condition is_string = masm->IsObjectStringType(r5, r1); |
| 7251 __ b(NegateCondition(is_string), &runtime); | 7478 __ b(NegateCondition(is_string), &runtime); |
| 7252 | 7479 |
| 7253 // r1: instance type | 7480 // r1: instance type |
| 7254 // r2: length | 7481 // r2: length |
| 7482 // r3: from index (untaged smi) |
| 7255 // r5: string | 7483 // r5: string |
| 7256 // r6: from (smi) | 7484 // r6: from (smi) |
| 7257 // r7: to (smi) | 7485 // r7: to (smi) |
| 7258 Label seq_string; | 7486 Label seq_string; |
| 7259 __ and_(r4, r1, Operand(kStringRepresentationMask)); | 7487 __ and_(r4, r1, Operand(kStringRepresentationMask)); |
| 7260 ASSERT(kSeqStringTag < kConsStringTag); | 7488 ASSERT(kSeqStringTag < kConsStringTag); |
| 7261 ASSERT(kExternalStringTag > kConsStringTag); | 7489 ASSERT(kExternalStringTag > kConsStringTag); |
| 7262 __ cmp(r4, Operand(kConsStringTag)); | 7490 __ cmp(r4, Operand(kConsStringTag)); |
| 7263 __ b(gt, &runtime); // External strings go to runtime. | 7491 __ b(gt, &runtime); // External strings go to runtime. |
| 7264 __ b(lt, &seq_string); // Sequential strings are handled directly. | 7492 __ b(lt, &seq_string); // Sequential strings are handled directly. |
| 7265 | 7493 |
| 7266 // Cons string. Try to recurse (once) on the first substring. | 7494 // Cons string. Try to recurse (once) on the first substring. |
| 7267 // (This adds a little more generality than necessary to handle flattened | 7495 // (This adds a little more generality than necessary to handle flattened |
| 7268 // cons strings, but not much). | 7496 // cons strings, but not much). |
| 7269 __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset)); | 7497 __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset)); |
| 7270 __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); | 7498 __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); |
| 7271 __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 7499 __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
| 7272 __ tst(r1, Operand(kStringRepresentationMask)); | 7500 __ tst(r1, Operand(kStringRepresentationMask)); |
| 7273 ASSERT_EQ(0, kSeqStringTag); | 7501 ASSERT_EQ(0, kSeqStringTag); |
| 7274 __ b(ne, &runtime); // Cons and External strings go to runtime. | 7502 __ b(ne, &runtime); // Cons and External strings go to runtime. |
| 7275 | 7503 |
| 7276 // Definitly a sequential string. | 7504 // Definitly a sequential string. |
| 7277 __ bind(&seq_string); | 7505 __ bind(&seq_string); |
| 7278 | 7506 |
| 7279 // r1: instance type. | 7507 // r1: instance type. |
| 7280 // r2: length | 7508 // r2: length |
| 7509 // r3: from index (untaged smi) |
| 7281 // r5: string | 7510 // r5: string |
| 7282 // r6: from (smi) | 7511 // r6: from (smi) |
| 7283 // r7: to (smi) | 7512 // r7: to (smi) |
| 7284 __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset)); | 7513 __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset)); |
| 7285 __ cmp(r4, Operand(r7, ASR, 1)); | 7514 __ cmp(r4, Operand(r7, ASR, 1)); |
| 7286 __ b(lt, &runtime); // Fail if to > length. | 7515 __ b(lt, &runtime); // Fail if to > length. |
| 7287 | 7516 |
| 7288 // r1: instance type. | 7517 // r1: instance type. |
| 7289 // r2: result string length. | 7518 // r2: result string length. |
| 7519 // r3: from index (untaged smi) |
| 7290 // r5: string. | 7520 // r5: string. |
| 7291 // r6: from offset (smi) | 7521 // r6: from offset (smi) |
| 7292 // Check for flat ascii string. | 7522 // Check for flat ascii string. |
| 7293 Label non_ascii_flat; | 7523 Label non_ascii_flat; |
| 7294 __ tst(r1, Operand(kStringEncodingMask)); | 7524 __ tst(r1, Operand(kStringEncodingMask)); |
| 7295 ASSERT_EQ(0, kTwoByteStringTag); | 7525 ASSERT_EQ(0, kTwoByteStringTag); |
| 7296 __ b(eq, &non_ascii_flat); | 7526 __ b(eq, &non_ascii_flat); |
| 7297 | 7527 |
| 7528 Label result_longer_than_two; |
| 7529 __ cmp(r2, Operand(2)); |
| 7530 __ b(gt, &result_longer_than_two); |
| 7531 |
| 7532 // Sub string of length 2 requested. |
| 7533 // Get the two characters forming the sub string. |
| 7534 __ add(r5, r5, Operand(r3)); |
| 7535 __ ldrb(r3, FieldMemOperand(r5, SeqAsciiString::kHeaderSize)); |
| 7536 __ ldrb(r4, FieldMemOperand(r5, SeqAsciiString::kHeaderSize + 1)); |
| 7537 |
| 7538 // Try to lookup two character string in symbol table. |
| 7539 Label make_two_character_string; |
| 7540 GenerateTwoCharacterSymbolTableProbe(masm, r3, r4, r1, r5, r6, r7, r9, |
| 7541 &make_two_character_string); |
| 7542 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
| 7543 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 7544 __ Ret(); |
| 7545 |
| 7546 // r2: result string length. |
| 7547 // r3: two characters combined into halfword in little endian byte order. |
| 7548 __ bind(&make_two_character_string); |
| 7549 __ AllocateAsciiString(r0, r2, r4, r5, r9, &runtime); |
| 7550 __ strh(r3, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
| 7551 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
| 7552 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 7553 __ Ret(); |
| 7554 |
| 7555 __ bind(&result_longer_than_two); |
| 7556 |
| 7298 // Allocate the result. | 7557 // Allocate the result. |
| 7299 __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime); | 7558 __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime); |
| 7300 | 7559 |
| 7301 // r0: result string. | 7560 // r0: result string. |
| 7302 // r2: result string length. | 7561 // r2: result string length. |
| 7303 // r5: string. | 7562 // r5: string. |
| 7304 // r6: from offset (smi) | 7563 // r6: from offset (smi) |
| 7305 // Locate first character of result. | 7564 // Locate first character of result. |
| 7306 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 7565 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 7307 // Locate 'from' character of string. | 7566 // Locate 'from' character of string. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7345 // r5: first character of string to copy. | 7604 // r5: first character of string to copy. |
| 7346 ASSERT_EQ(0, SeqTwoByteString::kHeaderSize & kObjectAlignmentMask); | 7605 ASSERT_EQ(0, SeqTwoByteString::kHeaderSize & kObjectAlignmentMask); |
| 7347 GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, | 7606 GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, |
| 7348 DEST_ALWAYS_ALIGNED); | 7607 DEST_ALWAYS_ALIGNED); |
| 7349 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); | 7608 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
| 7350 __ add(sp, sp, Operand(3 * kPointerSize)); | 7609 __ add(sp, sp, Operand(3 * kPointerSize)); |
| 7351 __ Ret(); | 7610 __ Ret(); |
| 7352 | 7611 |
| 7353 // Just jump to runtime to create the sub string. | 7612 // Just jump to runtime to create the sub string. |
| 7354 __ bind(&runtime); | 7613 __ bind(&runtime); |
| 7355 __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1); | 7614 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
| 7356 } | 7615 } |
| 7357 | 7616 |
| 7358 | 7617 |
| 7359 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 7618 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
| 7360 Register left, | 7619 Register left, |
| 7361 Register right, | 7620 Register right, |
| 7362 Register scratch1, | 7621 Register scratch1, |
| 7363 Register scratch2, | 7622 Register scratch2, |
| 7364 Register scratch3, | 7623 Register scratch3, |
| 7365 Register scratch4) { | 7624 Register scratch4) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7436 __ JumpIfNotBothSequentialAsciiStrings(r0, r1, r2, r3, &runtime); | 7695 __ JumpIfNotBothSequentialAsciiStrings(r0, r1, r2, r3, &runtime); |
| 7437 | 7696 |
| 7438 // Compare flat ascii strings natively. Remove arguments from stack first. | 7697 // Compare flat ascii strings natively. Remove arguments from stack first. |
| 7439 __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3); | 7698 __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3); |
| 7440 __ add(sp, sp, Operand(2 * kPointerSize)); | 7699 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 7441 GenerateCompareFlatAsciiStrings(masm, r0, r1, r2, r3, r4, r5); | 7700 GenerateCompareFlatAsciiStrings(masm, r0, r1, r2, r3, r4, r5); |
| 7442 | 7701 |
| 7443 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 7702 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
| 7444 // tagged as a small integer. | 7703 // tagged as a small integer. |
| 7445 __ bind(&runtime); | 7704 __ bind(&runtime); |
| 7446 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); | 7705 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 7447 } | 7706 } |
| 7448 | 7707 |
| 7449 | 7708 |
| 7450 void StringAddStub::Generate(MacroAssembler* masm) { | 7709 void StringAddStub::Generate(MacroAssembler* masm) { |
| 7451 Label string_add_runtime; | 7710 Label string_add_runtime; |
| 7452 // Stack on entry: | 7711 // Stack on entry: |
| 7453 // sp[0]: second argument. | 7712 // sp[0]: second argument. |
| 7454 // sp[4]: first argument. | 7713 // sp[4]: first argument. |
| 7455 | 7714 |
| 7456 // Load the two arguments. | 7715 // Load the two arguments. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7496 } | 7755 } |
| 7497 | 7756 |
| 7498 // Both strings are non-empty. | 7757 // Both strings are non-empty. |
| 7499 // r0: first string | 7758 // r0: first string |
| 7500 // r1: second string | 7759 // r1: second string |
| 7501 // r2: length of first string | 7760 // r2: length of first string |
| 7502 // r3: length of second string | 7761 // r3: length of second string |
| 7503 // r4: first string instance type (if string_check_) | 7762 // r4: first string instance type (if string_check_) |
| 7504 // r5: second string instance type (if string_check_) | 7763 // r5: second string instance type (if string_check_) |
| 7505 // Look at the length of the result of adding the two strings. | 7764 // Look at the length of the result of adding the two strings. |
| 7506 Label string_add_flat_result; | 7765 Label string_add_flat_result, longer_than_two; |
| 7507 // Adding two lengths can't overflow. | 7766 // Adding two lengths can't overflow. |
| 7508 ASSERT(String::kMaxLength * 2 > String::kMaxLength); | 7767 ASSERT(String::kMaxLength * 2 > String::kMaxLength); |
| 7509 __ add(r6, r2, Operand(r3)); | 7768 __ add(r6, r2, Operand(r3)); |
| 7510 // Use the runtime system when adding two one character strings, as it | 7769 // Use the runtime system when adding two one character strings, as it |
| 7511 // contains optimizations for this specific case using the symbol table. | 7770 // contains optimizations for this specific case using the symbol table. |
| 7512 __ cmp(r6, Operand(2)); | 7771 __ cmp(r6, Operand(2)); |
| 7513 __ b(eq, &string_add_runtime); | 7772 __ b(ne, &longer_than_two); |
| 7773 |
| 7774 // Check that both strings are non-external ascii strings. |
| 7775 if (!string_check_) { |
| 7776 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 7777 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 7778 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
| 7779 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
| 7780 } |
| 7781 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r7, |
| 7782 &string_add_runtime); |
| 7783 |
| 7784 // Get the two characters forming the sub string. |
| 7785 __ ldrb(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
| 7786 __ ldrb(r3, FieldMemOperand(r1, SeqAsciiString::kHeaderSize)); |
| 7787 |
| 7788 // Try to lookup two character string in symbol table. If it is not found |
| 7789 // just allocate a new one. |
| 7790 Label make_two_character_string; |
| 7791 GenerateTwoCharacterSymbolTableProbe(masm, r2, r3, r6, r7, r4, r5, r9, |
| 7792 &make_two_character_string); |
| 7793 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
| 7794 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 7795 __ Ret(); |
| 7796 |
| 7797 __ bind(&make_two_character_string); |
| 7798 // Resulting string has length 2 and first chars of two strings |
| 7799 // are combined into single halfword in r2 register. |
| 7800 // So we can fill resulting string without two loops by a single |
| 7801 // halfword store instruction (which assumes that processor is |
| 7802 // in a little endian mode) |
| 7803 __ mov(r6, Operand(2)); |
| 7804 __ AllocateAsciiString(r0, r6, r4, r5, r9, &string_add_runtime); |
| 7805 __ strh(r2, FieldMemOperand(r0, SeqAsciiString::kHeaderSize)); |
| 7806 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
| 7807 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 7808 __ Ret(); |
| 7809 |
| 7810 __ bind(&longer_than_two); |
| 7514 // Check if resulting string will be flat. | 7811 // Check if resulting string will be flat. |
| 7515 __ cmp(r6, Operand(String::kMinNonFlatLength)); | 7812 __ cmp(r6, Operand(String::kMinNonFlatLength)); |
| 7516 __ b(lt, &string_add_flat_result); | 7813 __ b(lt, &string_add_flat_result); |
| 7517 // Handle exceptionally long strings in the runtime system. | 7814 // Handle exceptionally long strings in the runtime system. |
| 7518 ASSERT((String::kMaxLength & 0x80000000) == 0); | 7815 ASSERT((String::kMaxLength & 0x80000000) == 0); |
| 7519 ASSERT(IsPowerOf2(String::kMaxLength + 1)); | 7816 ASSERT(IsPowerOf2(String::kMaxLength + 1)); |
| 7520 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. | 7817 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. |
| 7521 __ cmp(r6, Operand(String::kMaxLength + 1)); | 7818 __ cmp(r6, Operand(String::kMaxLength + 1)); |
| 7522 __ b(hs, &string_add_runtime); | 7819 __ b(hs, &string_add_runtime); |
| 7523 | 7820 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7582 ASSERT(IsPowerOf2(kStringEncodingMask)); // Just one bit to test. | 7879 ASSERT(IsPowerOf2(kStringEncodingMask)); // Just one bit to test. |
| 7583 __ eor(r7, r4, Operand(r5)); | 7880 __ eor(r7, r4, Operand(r5)); |
| 7584 __ tst(r7, Operand(kStringEncodingMask)); | 7881 __ tst(r7, Operand(kStringEncodingMask)); |
| 7585 __ b(ne, &string_add_runtime); | 7882 __ b(ne, &string_add_runtime); |
| 7586 // And see if it's ASCII or two-byte. | 7883 // And see if it's ASCII or two-byte. |
| 7587 __ tst(r4, Operand(kStringEncodingMask)); | 7884 __ tst(r4, Operand(kStringEncodingMask)); |
| 7588 __ b(eq, &non_ascii_string_add_flat_result); | 7885 __ b(eq, &non_ascii_string_add_flat_result); |
| 7589 | 7886 |
| 7590 // Both strings are sequential ASCII strings. We also know that they are | 7887 // Both strings are sequential ASCII strings. We also know that they are |
| 7591 // short (since the sum of the lengths is less than kMinNonFlatLength). | 7888 // short (since the sum of the lengths is less than kMinNonFlatLength). |
| 7889 // r6: length of resulting flat string |
| 7592 __ AllocateAsciiString(r7, r6, r4, r5, r9, &string_add_runtime); | 7890 __ AllocateAsciiString(r7, r6, r4, r5, r9, &string_add_runtime); |
| 7593 // Locate first character of result. | 7891 // Locate first character of result. |
| 7594 __ add(r6, r7, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 7892 __ add(r6, r7, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 7595 // Locate first character of first argument. | 7893 // Locate first character of first argument. |
| 7596 __ add(r0, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 7894 __ add(r0, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 7597 // r0: first character of first string. | 7895 // r0: first character of first string. |
| 7598 // r1: second string. | 7896 // r1: second string. |
| 7599 // r2: length of first string. | 7897 // r2: length of first string. |
| 7600 // r3: length of second string. | 7898 // r3: length of second string. |
| 7601 // r6: first character of result. | 7899 // r6: first character of result. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7650 // r7: result string. | 7948 // r7: result string. |
| 7651 GenerateCopyCharacters(masm, r6, r1, r3, r4, false); | 7949 GenerateCopyCharacters(masm, r6, r1, r3, r4, false); |
| 7652 | 7950 |
| 7653 __ mov(r0, Operand(r7)); | 7951 __ mov(r0, Operand(r7)); |
| 7654 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); | 7952 __ IncrementCounter(&Counters::string_add_native, 1, r2, r3); |
| 7655 __ add(sp, sp, Operand(2 * kPointerSize)); | 7953 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 7656 __ Ret(); | 7954 __ Ret(); |
| 7657 | 7955 |
| 7658 // Just jump to runtime to add the two strings. | 7956 // Just jump to runtime to add the two strings. |
| 7659 __ bind(&string_add_runtime); | 7957 __ bind(&string_add_runtime); |
| 7660 __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1); | 7958 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 7661 } | 7959 } |
| 7662 | 7960 |
| 7663 | 7961 |
| 7664 #undef __ | 7962 #undef __ |
| 7665 | 7963 |
| 7666 } } // namespace v8::internal | 7964 } } // namespace v8::internal |
| OLD | NEW |