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

Side by Side Diff: src/crankshaft/x64/lithium-codegen-x64.cc

Issue 1760253003: [crankshaft] Support ES6 tail call elimination. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@tco-crank-2
Patch Set: Addressing comments Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/crankshaft/x64/lithium-codegen-x64.h ('k') | src/crankshaft/x64/lithium-x64.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 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
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
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
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
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
OLDNEW
« no previous file with comments | « src/crankshaft/x64/lithium-codegen-x64.h ('k') | src/crankshaft/x64/lithium-x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698