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

Side by Side Diff: src/crankshaft/ia32/lithium-codegen-ia32.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/ia32/lithium-codegen-ia32.h ('k') | src/crankshaft/ia32/lithium-ia32.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 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 #if V8_TARGET_ARCH_IA32 5 #if V8_TARGET_ARCH_IA32
6 6
7 #include "src/crankshaft/ia32/lithium-codegen-ia32.h" 7 #include "src/crankshaft/ia32/lithium-codegen-ia32.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 2923 matching lines...) Expand 10 before | Expand all | Expand 10 after
2934 // length is a small non-negative integer, due to the test above. 2934 // length is a small non-negative integer, due to the test above.
2935 __ test(length, Operand(length)); 2935 __ test(length, Operand(length));
2936 __ j(zero, &invoke, Label::kNear); 2936 __ j(zero, &invoke, Label::kNear);
2937 __ bind(&loop); 2937 __ bind(&loop);
2938 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize)); 2938 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
2939 __ dec(length); 2939 __ dec(length);
2940 __ j(not_zero, &loop); 2940 __ j(not_zero, &loop);
2941 2941
2942 // Invoke the function. 2942 // Invoke the function.
2943 __ bind(&invoke); 2943 __ bind(&invoke);
2944
2945 InvokeFlag flag = CALL_FUNCTION;
2946 if (instr->hydrogen()->tail_call_mode() == TailCallMode::kAllow) {
2947 // TODO(ishell): drop current frame before pushing arguments to the stack.
2948 flag = JUMP_FUNCTION;
2949 ParameterCount actual(eax);
2950 // It is safe to use ebx, ecx and edx as scratch registers here given that
2951 // 1) we are not going to return to caller function anyway,
2952 // 2) ebx (expected arguments count) and edx (new.target) will be
2953 // initialized below.
2954 PrepareForTailCall(actual, ebx, ecx, edx);
2955 }
2956
2944 DCHECK(instr->HasPointerMap()); 2957 DCHECK(instr->HasPointerMap());
2945 LPointerMap* pointers = instr->pointer_map(); 2958 LPointerMap* pointers = instr->pointer_map();
2946 SafepointGenerator safepoint_generator( 2959 SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt);
2947 this, pointers, Safepoint::kLazyDeopt);
2948 ParameterCount actual(eax); 2960 ParameterCount actual(eax);
2949 __ InvokeFunction(function, no_reg, actual, CALL_FUNCTION, 2961 __ InvokeFunction(function, no_reg, actual, flag, safepoint_generator);
2950 safepoint_generator);
2951 } 2962 }
2952 2963
2953 2964
2954 void LCodeGen::DoDebugBreak(LDebugBreak* instr) { 2965 void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
2955 __ int3(); 2966 __ int3();
2956 } 2967 }
2957 2968
2958 2969
2959 void LCodeGen::DoPushArgument(LPushArgument* instr) { 2970 void LCodeGen::DoPushArgument(LPushArgument* instr) {
2960 LOperand* argument = instr->value(); 2971 LOperand* argument = instr->value();
(...skipping 23 matching lines...) Expand all
2984 } 2995 }
2985 2996
2986 2997
2987 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { 2998 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
2988 DCHECK(ToRegister(instr->context()).is(esi)); 2999 DCHECK(ToRegister(instr->context()).is(esi));
2989 __ push(Immediate(instr->hydrogen()->pairs())); 3000 __ push(Immediate(instr->hydrogen()->pairs()));
2990 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags()))); 3001 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
2991 CallRuntime(Runtime::kDeclareGlobals, instr); 3002 CallRuntime(Runtime::kDeclareGlobals, instr);
2992 } 3003 }
2993 3004
2994
2995 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, 3005 void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
2996 int formal_parameter_count, int arity, 3006 int formal_parameter_count, int arity,
2997 LInstruction* instr) { 3007 bool is_tail_call, LInstruction* instr) {
2998 bool dont_adapt_arguments = 3008 bool dont_adapt_arguments =
2999 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; 3009 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3000 bool can_invoke_directly = 3010 bool can_invoke_directly =
3001 dont_adapt_arguments || formal_parameter_count == arity; 3011 dont_adapt_arguments || formal_parameter_count == arity;
3002 3012
3003 Register function_reg = edi; 3013 Register function_reg = edi;
3004 3014
3005 if (can_invoke_directly) { 3015 if (can_invoke_directly) {
3006 // Change context. 3016 // Change context.
3007 __ mov(esi, FieldOperand(function_reg, JSFunction::kContextOffset)); 3017 __ mov(esi, FieldOperand(function_reg, JSFunction::kContextOffset));
3008 3018
3009 // Always initialize new target and number of actual arguments. 3019 // Always initialize new target and number of actual arguments.
3010 __ mov(edx, factory()->undefined_value()); 3020 __ mov(edx, factory()->undefined_value());
3011 __ mov(eax, arity); 3021 __ mov(eax, arity);
3012 3022
3023 bool is_self_call = function.is_identical_to(info()->closure());
3024
3013 // Invoke function directly. 3025 // Invoke function directly.
3014 if (function.is_identical_to(info()->closure())) { 3026 if (is_self_call) {
3015 __ CallSelf(); 3027 Handle<Code> self(reinterpret_cast<Code**>(__ CodeObject().location()));
3028 if (is_tail_call) {
3029 __ Jump(self, RelocInfo::CODE_TARGET);
3030 } else {
3031 __ Call(self, RelocInfo::CODE_TARGET);
3032 }
3016 } else { 3033 } else {
3017 __ call(FieldOperand(function_reg, JSFunction::kCodeEntryOffset)); 3034 Operand target = FieldOperand(function_reg, JSFunction::kCodeEntryOffset);
3035 if (is_tail_call) {
3036 __ jmp(target);
3037 } else {
3038 __ call(target);
3039 }
3018 } 3040 }
3019 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); 3041
3042 if (!is_tail_call) {
3043 // Set up deoptimization.
3044 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3045 }
3020 } else { 3046 } else {
3021 // We need to adapt arguments. 3047 // We need to adapt arguments.
3022 LPointerMap* pointers = instr->pointer_map(); 3048 LPointerMap* pointers = instr->pointer_map();
3023 SafepointGenerator generator( 3049 SafepointGenerator generator(
3024 this, pointers, Safepoint::kLazyDeopt); 3050 this, pointers, Safepoint::kLazyDeopt);
3025 ParameterCount count(arity); 3051 ParameterCount actual(arity);
3026 ParameterCount expected(formal_parameter_count); 3052 ParameterCount expected(formal_parameter_count);
3027 __ InvokeFunction(function_reg, expected, count, CALL_FUNCTION, generator); 3053 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION;
3054 __ InvokeFunction(function_reg, expected, actual, flag, generator);
3028 } 3055 }
3029 } 3056 }
3030 3057
3031 3058
3032 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { 3059 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
3033 DCHECK(ToRegister(instr->result()).is(eax)); 3060 DCHECK(ToRegister(instr->result()).is(eax));
3034 3061
3035 if (instr->hydrogen()->IsTailCall()) { 3062 if (instr->hydrogen()->IsTailCall()) {
3036 if (NeedsEagerFrame()) __ leave(); 3063 if (NeedsEagerFrame()) __ leave();
3037 3064
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
3409 void LCodeGen::DoMathExp(LMathExp* instr) { 3436 void LCodeGen::DoMathExp(LMathExp* instr) {
3410 XMMRegister input = ToDoubleRegister(instr->value()); 3437 XMMRegister input = ToDoubleRegister(instr->value());
3411 XMMRegister result = ToDoubleRegister(instr->result()); 3438 XMMRegister result = ToDoubleRegister(instr->result());
3412 XMMRegister temp0 = double_scratch0(); 3439 XMMRegister temp0 = double_scratch0();
3413 Register temp1 = ToRegister(instr->temp1()); 3440 Register temp1 = ToRegister(instr->temp1());
3414 Register temp2 = ToRegister(instr->temp2()); 3441 Register temp2 = ToRegister(instr->temp2());
3415 3442
3416 MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2); 3443 MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
3417 } 3444 }
3418 3445
3446 void LCodeGen::PrepareForTailCall(const ParameterCount& actual,
3447 Register scratch1, Register scratch2,
3448 Register scratch3) {
3449 #if DEBUG
3450 if (actual.is_reg()) {
3451 DCHECK(!AreAliased(actual.reg(), scratch1, scratch2, scratch3));
3452 } else {
3453 DCHECK(!AreAliased(scratch1, scratch2, scratch3));
3454 }
3455 #endif
3456 if (FLAG_code_comments) {
3457 if (actual.is_reg()) {
3458 Comment(";;; PrepareForTailCall, actual: %s {", actual.reg().ToString());
3459 } else {
3460 Comment(";;; PrepareForTailCall, actual: %d {", actual.immediate());
3461 }
3462 }
3463
3464 // Check if next frame is an arguments adaptor frame.
3465 Register caller_args_count_reg = scratch1;
3466 Label no_arguments_adaptor, formal_parameter_count_loaded;
3467 __ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3468 __ cmp(Operand(scratch2, StandardFrameConstants::kContextOffset),
3469 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3470 __ j(not_equal, &no_arguments_adaptor, Label::kNear);
3471
3472 // Drop current frame and load arguments count from arguments adaptor frame.
3473 __ mov(ebp, scratch2);
3474 __ mov(caller_args_count_reg,
3475 Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset));
3476 __ SmiUntag(caller_args_count_reg);
3477 __ jmp(&formal_parameter_count_loaded, Label::kNear);
3478
3479 __ bind(&no_arguments_adaptor);
3480 // Load caller's formal parameter count.
3481 __ mov(caller_args_count_reg,
3482 Immediate(info()->literal()->parameter_count()));
3483
3484 __ bind(&formal_parameter_count_loaded);
3485 __ PrepareForTailCall(actual, caller_args_count_reg, scratch2, scratch3,
3486 ReturnAddressState::kNotOnStack);
3487 Comment(";;; }");
3488 }
3419 3489
3420 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { 3490 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3491 HInvokeFunction* hinstr = instr->hydrogen();
3421 DCHECK(ToRegister(instr->context()).is(esi)); 3492 DCHECK(ToRegister(instr->context()).is(esi));
3422 DCHECK(ToRegister(instr->function()).is(edi)); 3493 DCHECK(ToRegister(instr->function()).is(edi));
3423 DCHECK(instr->HasPointerMap()); 3494 DCHECK(instr->HasPointerMap());
3424 3495
3425 Handle<JSFunction> known_function = instr->hydrogen()->known_function(); 3496 bool is_tail_call = hinstr->tail_call_mode() == TailCallMode::kAllow;
3497
3498 if (is_tail_call) {
3499 ParameterCount actual(instr->arity());
3500 // It is safe to use ebx, ecx and edx as scratch registers here given that
3501 // 1) we are not going to return to caller function anyway,
3502 // 2) ebx (expected arguments count) and edx (new.target) will be
3503 // initialized below.
3504 PrepareForTailCall(actual, ebx, ecx, edx);
3505 }
3506
3507 Handle<JSFunction> known_function = hinstr->known_function();
3426 if (known_function.is_null()) { 3508 if (known_function.is_null()) {
3427 LPointerMap* pointers = instr->pointer_map(); 3509 LPointerMap* pointers = instr->pointer_map();
3428 SafepointGenerator generator( 3510 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3429 this, pointers, Safepoint::kLazyDeopt); 3511 ParameterCount actual(instr->arity());
3430 ParameterCount count(instr->arity()); 3512 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION;
3431 __ InvokeFunction(edi, no_reg, count, CALL_FUNCTION, generator); 3513 __ InvokeFunction(edi, no_reg, actual, flag, generator);
3432 } else { 3514 } else {
3433 CallKnownFunction(known_function, 3515 CallKnownFunction(known_function, hinstr->formal_parameter_count(),
3434 instr->hydrogen()->formal_parameter_count(), 3516 instr->arity(), is_tail_call, instr);
3435 instr->arity(), instr);
3436 } 3517 }
3437 } 3518 }
3438 3519
3439 3520
3440 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { 3521 void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
3441 DCHECK(ToRegister(instr->context()).is(esi)); 3522 DCHECK(ToRegister(instr->context()).is(esi));
3442 DCHECK(ToRegister(instr->constructor()).is(edi)); 3523 DCHECK(ToRegister(instr->constructor()).is(edi));
3443 DCHECK(ToRegister(instr->result()).is(eax)); 3524 DCHECK(ToRegister(instr->result()).is(eax));
3444 3525
3445 __ Move(eax, Immediate(instr->arity())); 3526 __ Move(eax, Immediate(instr->arity()));
(...skipping 1757 matching lines...) Expand 10 before | Expand all | Expand 10 after
5203 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), context); 5284 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), context);
5204 } 5285 }
5205 5286
5206 5287
5207 #undef __ 5288 #undef __
5208 5289
5209 } // namespace internal 5290 } // namespace internal
5210 } // namespace v8 5291 } // namespace v8
5211 5292
5212 #endif // V8_TARGET_ARCH_IA32 5293 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « src/crankshaft/ia32/lithium-codegen-ia32.h ('k') | src/crankshaft/ia32/lithium-ia32.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698