OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/crankshaft/arm/lithium-codegen-arm.h" | 5 #include "src/crankshaft/arm/lithium-codegen-arm.h" |
6 | 6 |
7 #include "src/base/bits.h" | 7 #include "src/base/bits.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
10 #include "src/crankshaft/arm/lithium-gap-resolver-arm.h" | 10 #include "src/crankshaft/arm/lithium-gap-resolver-arm.h" |
(...skipping 3177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3188 // length is a small non-negative integer, due to the test above. | 3188 // length is a small non-negative integer, due to the test above. |
3189 __ cmp(length, Operand::Zero()); | 3189 __ cmp(length, Operand::Zero()); |
3190 __ b(eq, &invoke); | 3190 __ b(eq, &invoke); |
3191 __ bind(&loop); | 3191 __ bind(&loop); |
3192 __ ldr(scratch, MemOperand(elements, length, LSL, 2)); | 3192 __ ldr(scratch, MemOperand(elements, length, LSL, 2)); |
3193 __ push(scratch); | 3193 __ push(scratch); |
3194 __ sub(length, length, Operand(1), SetCC); | 3194 __ sub(length, length, Operand(1), SetCC); |
3195 __ b(ne, &loop); | 3195 __ b(ne, &loop); |
3196 | 3196 |
3197 __ bind(&invoke); | 3197 __ bind(&invoke); |
| 3198 |
| 3199 InvokeFlag flag = CALL_FUNCTION; |
| 3200 if (instr->hydrogen()->tail_call_mode() == TailCallMode::kAllow) { |
| 3201 // TODO(ishell): drop current frame before pushing arguments to the stack. |
| 3202 flag = JUMP_FUNCTION; |
| 3203 ParameterCount actual(r0); |
| 3204 // It is safe to use r3, r4 and r5 as scratch registers here given that |
| 3205 // 1) we are not going to return to caller function anyway, |
| 3206 // 2) r3 (new.target) will be initialized below. |
| 3207 PrepareForTailCall(actual, r3, r4, r5); |
| 3208 } |
| 3209 |
3198 DCHECK(instr->HasPointerMap()); | 3210 DCHECK(instr->HasPointerMap()); |
3199 LPointerMap* pointers = instr->pointer_map(); | 3211 LPointerMap* pointers = instr->pointer_map(); |
3200 SafepointGenerator safepoint_generator( | 3212 SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); |
3201 this, pointers, Safepoint::kLazyDeopt); | |
3202 // The number of arguments is stored in receiver which is r0, as expected | 3213 // The number of arguments is stored in receiver which is r0, as expected |
3203 // by InvokeFunction. | 3214 // by InvokeFunction. |
3204 ParameterCount actual(receiver); | 3215 ParameterCount actual(receiver); |
3205 __ InvokeFunction(function, no_reg, actual, CALL_FUNCTION, | 3216 __ InvokeFunction(function, no_reg, actual, flag, safepoint_generator); |
3206 safepoint_generator); | |
3207 } | 3217 } |
3208 | 3218 |
3209 | 3219 |
3210 void LCodeGen::DoPushArgument(LPushArgument* instr) { | 3220 void LCodeGen::DoPushArgument(LPushArgument* instr) { |
3211 LOperand* argument = instr->value(); | 3221 LOperand* argument = instr->value(); |
3212 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { | 3222 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { |
3213 Abort(kDoPushArgumentNotImplementedForDoubleType); | 3223 Abort(kDoPushArgumentNotImplementedForDoubleType); |
3214 } else { | 3224 } else { |
3215 Register argument_reg = EmitLoadRegister(argument, ip); | 3225 Register argument_reg = EmitLoadRegister(argument, ip); |
3216 __ push(argument_reg); | 3226 __ push(argument_reg); |
(...skipping 26 matching lines...) Expand all Loading... |
3243 | 3253 |
3244 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { | 3254 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { |
3245 DCHECK(ToRegister(instr->context()).is(cp)); | 3255 DCHECK(ToRegister(instr->context()).is(cp)); |
3246 __ Move(scratch0(), instr->hydrogen()->pairs()); | 3256 __ Move(scratch0(), instr->hydrogen()->pairs()); |
3247 __ push(scratch0()); | 3257 __ push(scratch0()); |
3248 __ mov(scratch0(), Operand(Smi::FromInt(instr->hydrogen()->flags()))); | 3258 __ mov(scratch0(), Operand(Smi::FromInt(instr->hydrogen()->flags()))); |
3249 __ push(scratch0()); | 3259 __ push(scratch0()); |
3250 CallRuntime(Runtime::kDeclareGlobals, instr); | 3260 CallRuntime(Runtime::kDeclareGlobals, instr); |
3251 } | 3261 } |
3252 | 3262 |
3253 | |
3254 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 3263 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
3255 int formal_parameter_count, int arity, | 3264 int formal_parameter_count, int arity, |
3256 LInstruction* instr) { | 3265 bool is_tail_call, LInstruction* instr) { |
3257 bool dont_adapt_arguments = | 3266 bool dont_adapt_arguments = |
3258 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; | 3267 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; |
3259 bool can_invoke_directly = | 3268 bool can_invoke_directly = |
3260 dont_adapt_arguments || formal_parameter_count == arity; | 3269 dont_adapt_arguments || formal_parameter_count == arity; |
3261 | 3270 |
3262 Register function_reg = r1; | 3271 Register function_reg = r1; |
3263 | 3272 |
3264 LPointerMap* pointers = instr->pointer_map(); | 3273 LPointerMap* pointers = instr->pointer_map(); |
3265 | 3274 |
3266 if (can_invoke_directly) { | 3275 if (can_invoke_directly) { |
3267 // Change context. | 3276 // Change context. |
3268 __ ldr(cp, FieldMemOperand(function_reg, JSFunction::kContextOffset)); | 3277 __ ldr(cp, FieldMemOperand(function_reg, JSFunction::kContextOffset)); |
3269 | 3278 |
3270 // Always initialize new target and number of actual arguments. | 3279 // Always initialize new target and number of actual arguments. |
3271 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); | 3280 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); |
3272 __ mov(r0, Operand(arity)); | 3281 __ mov(r0, Operand(arity)); |
3273 | 3282 |
| 3283 bool is_self_call = function.is_identical_to(info()->closure()); |
| 3284 |
3274 // Invoke function. | 3285 // Invoke function. |
3275 __ ldr(ip, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset)); | 3286 if (is_self_call) { |
3276 __ Call(ip); | 3287 Handle<Code> self(reinterpret_cast<Code**>(__ CodeObject().location())); |
| 3288 if (is_tail_call) { |
| 3289 __ Jump(self, RelocInfo::CODE_TARGET); |
| 3290 } else { |
| 3291 __ Call(self, RelocInfo::CODE_TARGET); |
| 3292 } |
| 3293 } else { |
| 3294 __ ldr(ip, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset)); |
| 3295 if (is_tail_call) { |
| 3296 __ Jump(ip); |
| 3297 } else { |
| 3298 __ Call(ip); |
| 3299 } |
| 3300 } |
3277 | 3301 |
3278 // Set up deoptimization. | 3302 if (!is_tail_call) { |
3279 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); | 3303 // Set up deoptimization. |
| 3304 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); |
| 3305 } |
3280 } else { | 3306 } else { |
3281 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); | 3307 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
3282 ParameterCount count(arity); | 3308 ParameterCount actual(arity); |
3283 ParameterCount expected(formal_parameter_count); | 3309 ParameterCount expected(formal_parameter_count); |
3284 __ InvokeFunction(function_reg, expected, count, CALL_FUNCTION, generator); | 3310 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
| 3311 __ InvokeFunction(function_reg, expected, actual, flag, generator); |
3285 } | 3312 } |
3286 } | 3313 } |
3287 | 3314 |
3288 | 3315 |
3289 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) { | 3316 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) { |
3290 DCHECK(instr->context() != NULL); | 3317 DCHECK(instr->context() != NULL); |
3291 DCHECK(ToRegister(instr->context()).is(cp)); | 3318 DCHECK(ToRegister(instr->context()).is(cp)); |
3292 Register input = ToRegister(instr->value()); | 3319 Register input = ToRegister(instr->value()); |
3293 Register result = ToRegister(instr->result()); | 3320 Register result = ToRegister(instr->result()); |
3294 Register scratch = scratch0(); | 3321 Register scratch = scratch0(); |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3561 __ MovFromFloatResult(ToDoubleRegister(instr->result())); | 3588 __ MovFromFloatResult(ToDoubleRegister(instr->result())); |
3562 } | 3589 } |
3563 | 3590 |
3564 | 3591 |
3565 void LCodeGen::DoMathClz32(LMathClz32* instr) { | 3592 void LCodeGen::DoMathClz32(LMathClz32* instr) { |
3566 Register input = ToRegister(instr->value()); | 3593 Register input = ToRegister(instr->value()); |
3567 Register result = ToRegister(instr->result()); | 3594 Register result = ToRegister(instr->result()); |
3568 __ clz(result, input); | 3595 __ clz(result, input); |
3569 } | 3596 } |
3570 | 3597 |
| 3598 void LCodeGen::PrepareForTailCall(const ParameterCount& actual, |
| 3599 Register scratch1, Register scratch2, |
| 3600 Register scratch3) { |
| 3601 #if DEBUG |
| 3602 if (actual.is_reg()) { |
| 3603 DCHECK(!AreAliased(actual.reg(), scratch1, scratch2, scratch3)); |
| 3604 } else { |
| 3605 DCHECK(!AreAliased(scratch1, scratch2, scratch3)); |
| 3606 } |
| 3607 #endif |
| 3608 if (FLAG_code_comments) { |
| 3609 if (actual.is_reg()) { |
| 3610 Comment(";;; PrepareForTailCall, actual: %s {", actual.reg().ToString()); |
| 3611 } else { |
| 3612 Comment(";;; PrepareForTailCall, actual: %d {", actual.immediate()); |
| 3613 } |
| 3614 } |
| 3615 |
| 3616 // Check if next frame is an arguments adaptor frame. |
| 3617 Register caller_args_count_reg = scratch1; |
| 3618 Label no_arguments_adaptor, formal_parameter_count_loaded; |
| 3619 __ ldr(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 3620 __ ldr(scratch3, |
| 3621 MemOperand(scratch2, StandardFrameConstants::kContextOffset)); |
| 3622 __ cmp(scratch3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 3623 __ b(ne, &no_arguments_adaptor); |
| 3624 |
| 3625 // Drop current frame and load arguments count from arguments adaptor frame. |
| 3626 __ mov(fp, scratch2); |
| 3627 __ ldr(caller_args_count_reg, |
| 3628 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 3629 __ SmiUntag(caller_args_count_reg); |
| 3630 __ b(&formal_parameter_count_loaded); |
| 3631 |
| 3632 __ bind(&no_arguments_adaptor); |
| 3633 // Load caller's formal parameter count |
| 3634 __ mov(caller_args_count_reg, Operand(info()->literal()->parameter_count())); |
| 3635 |
| 3636 __ bind(&formal_parameter_count_loaded); |
| 3637 __ PrepareForTailCall(actual, caller_args_count_reg, scratch2, scratch3); |
| 3638 |
| 3639 Comment(";;; }"); |
| 3640 } |
3571 | 3641 |
3572 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { | 3642 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { |
| 3643 HInvokeFunction* hinstr = instr->hydrogen(); |
3573 DCHECK(ToRegister(instr->context()).is(cp)); | 3644 DCHECK(ToRegister(instr->context()).is(cp)); |
3574 DCHECK(ToRegister(instr->function()).is(r1)); | 3645 DCHECK(ToRegister(instr->function()).is(r1)); |
3575 DCHECK(instr->HasPointerMap()); | 3646 DCHECK(instr->HasPointerMap()); |
3576 | 3647 |
3577 Handle<JSFunction> known_function = instr->hydrogen()->known_function(); | 3648 bool is_tail_call = hinstr->tail_call_mode() == TailCallMode::kAllow; |
| 3649 |
| 3650 if (is_tail_call) { |
| 3651 ParameterCount actual(instr->arity()); |
| 3652 // It is safe to use r3, r4 and r5 as scratch registers here given that |
| 3653 // 1) we are not going to return to caller function anyway, |
| 3654 // 2) r3 (new.target) will be initialized below. |
| 3655 PrepareForTailCall(actual, r3, r4, r5); |
| 3656 } |
| 3657 |
| 3658 Handle<JSFunction> known_function = hinstr->known_function(); |
3578 if (known_function.is_null()) { | 3659 if (known_function.is_null()) { |
3579 LPointerMap* pointers = instr->pointer_map(); | 3660 LPointerMap* pointers = instr->pointer_map(); |
3580 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); | 3661 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
3581 ParameterCount count(instr->arity()); | 3662 ParameterCount actual(instr->arity()); |
3582 __ InvokeFunction(r1, no_reg, count, CALL_FUNCTION, generator); | 3663 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
| 3664 __ InvokeFunction(r1, no_reg, actual, flag, generator); |
3583 } else { | 3665 } else { |
3584 CallKnownFunction(known_function, | 3666 CallKnownFunction(known_function, hinstr->formal_parameter_count(), |
3585 instr->hydrogen()->formal_parameter_count(), | 3667 instr->arity(), is_tail_call, instr); |
3586 instr->arity(), instr); | |
3587 } | 3668 } |
3588 } | 3669 } |
3589 | 3670 |
3590 | 3671 |
3591 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { | 3672 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { |
3592 DCHECK(ToRegister(instr->result()).is(r0)); | 3673 DCHECK(ToRegister(instr->result()).is(r0)); |
3593 | 3674 |
3594 if (instr->hydrogen()->IsTailCall()) { | 3675 if (instr->hydrogen()->IsTailCall()) { |
3595 if (NeedsEagerFrame()) __ LeaveFrame(StackFrame::INTERNAL); | 3676 if (NeedsEagerFrame()) __ LeaveFrame(StackFrame::INTERNAL); |
3596 | 3677 |
(...skipping 1880 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5477 void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) { | 5558 void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) { |
5478 Register context = ToRegister(instr->context()); | 5559 Register context = ToRegister(instr->context()); |
5479 __ str(context, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 5560 __ str(context, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
5480 } | 5561 } |
5481 | 5562 |
5482 | 5563 |
5483 #undef __ | 5564 #undef __ |
5484 | 5565 |
5485 } // namespace internal | 5566 } // namespace internal |
5486 } // namespace v8 | 5567 } // namespace v8 |
OLD | NEW |