OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 #if V8_TARGET_ARCH_X64 | 5 #if V8_TARGET_ARCH_X64 |
6 | 6 |
7 #include "src/crankshaft/x64/lithium-codegen-x64.h" | 7 #include "src/crankshaft/x64/lithium-codegen-x64.h" |
8 | 8 |
9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
(...skipping 3129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3140 __ j(zero, &invoke, Label::kNear); | 3140 __ j(zero, &invoke, Label::kNear); |
3141 __ bind(&loop); | 3141 __ bind(&loop); |
3142 StackArgumentsAccessor args(elements, length, | 3142 StackArgumentsAccessor args(elements, length, |
3143 ARGUMENTS_DONT_CONTAIN_RECEIVER); | 3143 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
3144 __ Push(args.GetArgumentOperand(0)); | 3144 __ Push(args.GetArgumentOperand(0)); |
3145 __ decl(length); | 3145 __ decl(length); |
3146 __ j(not_zero, &loop); | 3146 __ j(not_zero, &loop); |
3147 | 3147 |
3148 // Invoke the function. | 3148 // Invoke the function. |
3149 __ bind(&invoke); | 3149 __ bind(&invoke); |
| 3150 |
| 3151 InvokeFlag flag = CALL_FUNCTION; |
| 3152 if (instr->hydrogen()->tail_call_mode() == TailCallMode::kAllow) { |
| 3153 // TODO(ishell): drop current frame before pushing arguments to the stack. |
| 3154 flag = JUMP_FUNCTION; |
| 3155 ParameterCount actual(rax); |
| 3156 // It is safe to use rbx, rcx and r8 as scratch registers here given that |
| 3157 // 1) we are not going to return to caller function anyway, |
| 3158 // 2) rbx (expected number of arguments) will be initialized below. |
| 3159 PrepareForTailCall(actual, rbx, rcx, r8); |
| 3160 } |
| 3161 |
3150 DCHECK(instr->HasPointerMap()); | 3162 DCHECK(instr->HasPointerMap()); |
3151 LPointerMap* pointers = instr->pointer_map(); | 3163 LPointerMap* pointers = instr->pointer_map(); |
3152 SafepointGenerator safepoint_generator( | 3164 SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); |
3153 this, pointers, Safepoint::kLazyDeopt); | |
3154 ParameterCount actual(rax); | 3165 ParameterCount actual(rax); |
3155 __ InvokeFunction(function, no_reg, actual, CALL_FUNCTION, | 3166 __ InvokeFunction(function, no_reg, actual, flag, safepoint_generator); |
3156 safepoint_generator); | |
3157 } | 3167 } |
3158 | 3168 |
3159 | 3169 |
3160 void LCodeGen::DoPushArgument(LPushArgument* instr) { | 3170 void LCodeGen::DoPushArgument(LPushArgument* instr) { |
3161 LOperand* argument = instr->value(); | 3171 LOperand* argument = instr->value(); |
3162 EmitPushTaggedOperand(argument); | 3172 EmitPushTaggedOperand(argument); |
3163 } | 3173 } |
3164 | 3174 |
3165 | 3175 |
3166 void LCodeGen::DoDrop(LDrop* instr) { | 3176 void LCodeGen::DoDrop(LDrop* instr) { |
(...skipping 18 matching lines...) Expand all Loading... |
3185 } | 3195 } |
3186 | 3196 |
3187 | 3197 |
3188 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { | 3198 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { |
3189 DCHECK(ToRegister(instr->context()).is(rsi)); | 3199 DCHECK(ToRegister(instr->context()).is(rsi)); |
3190 __ Push(instr->hydrogen()->pairs()); | 3200 __ Push(instr->hydrogen()->pairs()); |
3191 __ Push(Smi::FromInt(instr->hydrogen()->flags())); | 3201 __ Push(Smi::FromInt(instr->hydrogen()->flags())); |
3192 CallRuntime(Runtime::kDeclareGlobals, instr); | 3202 CallRuntime(Runtime::kDeclareGlobals, instr); |
3193 } | 3203 } |
3194 | 3204 |
3195 | |
3196 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 3205 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
3197 int formal_parameter_count, int arity, | 3206 int formal_parameter_count, int arity, |
3198 LInstruction* instr) { | 3207 bool is_tail_call, LInstruction* instr) { |
3199 bool dont_adapt_arguments = | 3208 bool dont_adapt_arguments = |
3200 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; | 3209 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; |
3201 bool can_invoke_directly = | 3210 bool can_invoke_directly = |
3202 dont_adapt_arguments || formal_parameter_count == arity; | 3211 dont_adapt_arguments || formal_parameter_count == arity; |
3203 | 3212 |
3204 Register function_reg = rdi; | 3213 Register function_reg = rdi; |
3205 LPointerMap* pointers = instr->pointer_map(); | 3214 LPointerMap* pointers = instr->pointer_map(); |
3206 | 3215 |
3207 if (can_invoke_directly) { | 3216 if (can_invoke_directly) { |
3208 // Change context. | 3217 // Change context. |
3209 __ movp(rsi, FieldOperand(function_reg, JSFunction::kContextOffset)); | 3218 __ movp(rsi, FieldOperand(function_reg, JSFunction::kContextOffset)); |
3210 | 3219 |
3211 // Always initialize new target and number of actual arguments. | 3220 // Always initialize new target and number of actual arguments. |
3212 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); | 3221 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); |
3213 __ Set(rax, arity); | 3222 __ Set(rax, arity); |
3214 | 3223 |
| 3224 bool is_self_call = function.is_identical_to(info()->closure()); |
| 3225 |
3215 // Invoke function. | 3226 // Invoke function. |
3216 if (function.is_identical_to(info()->closure())) { | 3227 if (is_self_call) { |
3217 __ CallSelf(); | 3228 Handle<Code> self(reinterpret_cast<Code**>(__ CodeObject().location())); |
| 3229 if (is_tail_call) { |
| 3230 __ Jump(self, RelocInfo::CODE_TARGET); |
| 3231 } else { |
| 3232 __ Call(self, RelocInfo::CODE_TARGET); |
| 3233 } |
3218 } else { | 3234 } else { |
3219 __ Call(FieldOperand(function_reg, JSFunction::kCodeEntryOffset)); | 3235 Operand target = FieldOperand(function_reg, JSFunction::kCodeEntryOffset); |
| 3236 if (is_tail_call) { |
| 3237 __ Jump(target); |
| 3238 } else { |
| 3239 __ Call(target); |
| 3240 } |
3220 } | 3241 } |
3221 | 3242 |
3222 // Set up deoptimization. | 3243 if (!is_tail_call) { |
3223 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0); | 3244 // Set up deoptimization. |
| 3245 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0); |
| 3246 } |
3224 } else { | 3247 } else { |
3225 // We need to adapt arguments. | 3248 // We need to adapt arguments. |
3226 SafepointGenerator generator( | 3249 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
3227 this, pointers, Safepoint::kLazyDeopt); | 3250 ParameterCount actual(arity); |
3228 ParameterCount count(arity); | |
3229 ParameterCount expected(formal_parameter_count); | 3251 ParameterCount expected(formal_parameter_count); |
3230 __ InvokeFunction(function_reg, no_reg, expected, count, CALL_FUNCTION, | 3252 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
3231 generator); | 3253 __ InvokeFunction(function_reg, no_reg, expected, actual, flag, generator); |
3232 } | 3254 } |
3233 } | 3255 } |
3234 | 3256 |
3235 | 3257 |
3236 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { | 3258 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { |
3237 DCHECK(ToRegister(instr->result()).is(rax)); | 3259 DCHECK(ToRegister(instr->result()).is(rax)); |
3238 | 3260 |
3239 if (instr->hydrogen()->IsTailCall()) { | 3261 if (instr->hydrogen()->IsTailCall()) { |
3240 if (NeedsEagerFrame()) __ leave(); | 3262 if (NeedsEagerFrame()) __ leave(); |
3241 | 3263 |
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3621 } | 3643 } |
3622 | 3644 |
3623 | 3645 |
3624 void LCodeGen::DoMathClz32(LMathClz32* instr) { | 3646 void LCodeGen::DoMathClz32(LMathClz32* instr) { |
3625 Register input = ToRegister(instr->value()); | 3647 Register input = ToRegister(instr->value()); |
3626 Register result = ToRegister(instr->result()); | 3648 Register result = ToRegister(instr->result()); |
3627 | 3649 |
3628 __ Lzcntl(result, input); | 3650 __ Lzcntl(result, input); |
3629 } | 3651 } |
3630 | 3652 |
| 3653 void LCodeGen::PrepareForTailCall(const ParameterCount& actual, |
| 3654 Register scratch1, Register scratch2, |
| 3655 Register scratch3) { |
| 3656 #if DEBUG |
| 3657 if (actual.is_reg()) { |
| 3658 DCHECK(!AreAliased(actual.reg(), scratch1, scratch2, scratch3)); |
| 3659 } else { |
| 3660 DCHECK(!AreAliased(scratch1, scratch2, scratch3)); |
| 3661 } |
| 3662 #endif |
| 3663 if (FLAG_code_comments) { |
| 3664 if (actual.is_reg()) { |
| 3665 Comment(";;; PrepareForTailCall, actual: %s {", actual.reg().ToString()); |
| 3666 } else { |
| 3667 Comment(";;; PrepareForTailCall, actual: %d {", actual.immediate()); |
| 3668 } |
| 3669 } |
| 3670 |
| 3671 // Check if next frame is an arguments adaptor frame. |
| 3672 Register caller_args_count_reg = scratch1; |
| 3673 Label no_arguments_adaptor, formal_parameter_count_loaded; |
| 3674 __ movp(scratch2, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 3675 __ Cmp(Operand(scratch2, StandardFrameConstants::kContextOffset), |
| 3676 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 3677 __ j(not_equal, &no_arguments_adaptor, Label::kNear); |
| 3678 |
| 3679 // Drop current frame and load arguments count from arguments adaptor frame. |
| 3680 __ movp(rbp, scratch2); |
| 3681 __ SmiToInteger32( |
| 3682 caller_args_count_reg, |
| 3683 Operand(rbp, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 3684 __ jmp(&formal_parameter_count_loaded, Label::kNear); |
| 3685 |
| 3686 __ bind(&no_arguments_adaptor); |
| 3687 // Load caller's formal parameter count. |
| 3688 __ movp(caller_args_count_reg, |
| 3689 Immediate(info()->literal()->parameter_count())); |
| 3690 |
| 3691 __ bind(&formal_parameter_count_loaded); |
| 3692 __ PrepareForTailCall(actual, caller_args_count_reg, scratch2, scratch3, |
| 3693 ReturnAddressState::kNotOnStack); |
| 3694 Comment(";;; }"); |
| 3695 } |
3631 | 3696 |
3632 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { | 3697 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { |
| 3698 HInvokeFunction* hinstr = instr->hydrogen(); |
3633 DCHECK(ToRegister(instr->context()).is(rsi)); | 3699 DCHECK(ToRegister(instr->context()).is(rsi)); |
3634 DCHECK(ToRegister(instr->function()).is(rdi)); | 3700 DCHECK(ToRegister(instr->function()).is(rdi)); |
3635 DCHECK(instr->HasPointerMap()); | 3701 DCHECK(instr->HasPointerMap()); |
3636 | 3702 |
3637 Handle<JSFunction> known_function = instr->hydrogen()->known_function(); | 3703 bool is_tail_call = hinstr->tail_call_mode() == TailCallMode::kAllow; |
| 3704 |
| 3705 if (is_tail_call) { |
| 3706 ParameterCount actual(instr->arity()); |
| 3707 // It is safe to use rbx, rcx and r8 as scratch registers here given that |
| 3708 // 1) we are not going to return to caller function anyway, |
| 3709 // 2) rbx (expected number of arguments) will be initialized below. |
| 3710 PrepareForTailCall(actual, rbx, rcx, r8); |
| 3711 } |
| 3712 |
| 3713 Handle<JSFunction> known_function = hinstr->known_function(); |
3638 if (known_function.is_null()) { | 3714 if (known_function.is_null()) { |
3639 LPointerMap* pointers = instr->pointer_map(); | 3715 LPointerMap* pointers = instr->pointer_map(); |
3640 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); | 3716 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
3641 ParameterCount count(instr->arity()); | 3717 ParameterCount actual(instr->arity()); |
3642 __ InvokeFunction(rdi, no_reg, count, CALL_FUNCTION, generator); | 3718 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
| 3719 __ InvokeFunction(rdi, no_reg, actual, flag, generator); |
3643 } else { | 3720 } else { |
3644 CallKnownFunction(known_function, | 3721 CallKnownFunction(known_function, hinstr->formal_parameter_count(), |
3645 instr->hydrogen()->formal_parameter_count(), | 3722 instr->arity(), is_tail_call, instr); |
3646 instr->arity(), instr); | |
3647 } | 3723 } |
3648 } | 3724 } |
3649 | 3725 |
3650 | 3726 |
3651 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { | 3727 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { |
3652 DCHECK(ToRegister(instr->context()).is(rsi)); | 3728 DCHECK(ToRegister(instr->context()).is(rsi)); |
3653 DCHECK(ToRegister(instr->constructor()).is(rdi)); | 3729 DCHECK(ToRegister(instr->constructor()).is(rdi)); |
3654 DCHECK(ToRegister(instr->result()).is(rax)); | 3730 DCHECK(ToRegister(instr->result()).is(rax)); |
3655 | 3731 |
3656 __ Set(rax, instr->arity()); | 3732 __ Set(rax, instr->arity()); |
(...skipping 1864 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5521 __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), context); | 5597 __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), context); |
5522 } | 5598 } |
5523 | 5599 |
5524 | 5600 |
5525 #undef __ | 5601 #undef __ |
5526 | 5602 |
5527 } // namespace internal | 5603 } // namespace internal |
5528 } // namespace v8 | 5604 } // namespace v8 |
5529 | 5605 |
5530 #endif // V8_TARGET_ARCH_X64 | 5606 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |