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

Side by Side Diff: src/crankshaft/arm/lithium-codegen-arm.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/arm/lithium-codegen-arm.h ('k') | src/crankshaft/arm64/lithium-arm64.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 #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
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
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
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
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
OLDNEW
« no previous file with comments | « src/crankshaft/arm/lithium-codegen-arm.h ('k') | src/crankshaft/arm64/lithium-arm64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698