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/mips64/lithium-codegen-mips64.h" | 5 #include "src/crankshaft/mips64/lithium-codegen-mips64.h" |
6 | 6 |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
9 #include "src/crankshaft/hydrogen-osr.h" | 9 #include "src/crankshaft/hydrogen-osr.h" |
10 #include "src/crankshaft/mips64/lithium-gap-resolver-mips64.h" | 10 #include "src/crankshaft/mips64/lithium-gap-resolver-mips64.h" |
(...skipping 3296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3307 __ dsll(scratch, length, kPointerSizeLog2); | 3307 __ dsll(scratch, length, kPointerSizeLog2); |
3308 __ bind(&loop); | 3308 __ bind(&loop); |
3309 __ Daddu(scratch, elements, scratch); | 3309 __ Daddu(scratch, elements, scratch); |
3310 __ ld(scratch, MemOperand(scratch)); | 3310 __ ld(scratch, MemOperand(scratch)); |
3311 __ push(scratch); | 3311 __ push(scratch); |
3312 __ Dsubu(length, length, Operand(1)); | 3312 __ Dsubu(length, length, Operand(1)); |
3313 __ Branch(USE_DELAY_SLOT, &loop, ne, length, Operand(zero_reg)); | 3313 __ Branch(USE_DELAY_SLOT, &loop, ne, length, Operand(zero_reg)); |
3314 __ dsll(scratch, length, kPointerSizeLog2); | 3314 __ dsll(scratch, length, kPointerSizeLog2); |
3315 | 3315 |
3316 __ bind(&invoke); | 3316 __ bind(&invoke); |
| 3317 |
| 3318 InvokeFlag flag = CALL_FUNCTION; |
| 3319 if (instr->hydrogen()->tail_call_mode() == TailCallMode::kAllow) { |
| 3320 // TODO(ishell): drop current frame before pushing arguments to the stack. |
| 3321 flag = JUMP_FUNCTION; |
| 3322 ParameterCount actual(a0); |
| 3323 // It is safe to use t0, t1 and t2 as scratch registers here given that |
| 3324 // we are not going to return to caller function anyway. |
| 3325 PrepareForTailCall(actual, t0, t1, t2); |
| 3326 } |
| 3327 |
3317 DCHECK(instr->HasPointerMap()); | 3328 DCHECK(instr->HasPointerMap()); |
3318 LPointerMap* pointers = instr->pointer_map(); | 3329 LPointerMap* pointers = instr->pointer_map(); |
3319 SafepointGenerator safepoint_generator( | 3330 SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); |
3320 this, pointers, Safepoint::kLazyDeopt); | |
3321 // The number of arguments is stored in receiver which is a0, as expected | 3331 // The number of arguments is stored in receiver which is a0, as expected |
3322 // by InvokeFunction. | 3332 // by InvokeFunction. |
3323 ParameterCount actual(receiver); | 3333 ParameterCount actual(receiver); |
3324 __ InvokeFunction(function, no_reg, actual, CALL_FUNCTION, | 3334 __ InvokeFunction(function, no_reg, actual, flag, safepoint_generator); |
3325 safepoint_generator); | |
3326 } | 3335 } |
3327 | 3336 |
3328 | 3337 |
3329 void LCodeGen::DoPushArgument(LPushArgument* instr) { | 3338 void LCodeGen::DoPushArgument(LPushArgument* instr) { |
3330 LOperand* argument = instr->value(); | 3339 LOperand* argument = instr->value(); |
3331 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { | 3340 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { |
3332 Abort(kDoPushArgumentNotImplementedForDoubleType); | 3341 Abort(kDoPushArgumentNotImplementedForDoubleType); |
3333 } else { | 3342 } else { |
3334 Register argument_reg = EmitLoadRegister(argument, at); | 3343 Register argument_reg = EmitLoadRegister(argument, at); |
3335 __ push(argument_reg); | 3344 __ push(argument_reg); |
(...skipping 25 matching lines...) Expand all Loading... |
3361 | 3370 |
3362 | 3371 |
3363 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { | 3372 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { |
3364 DCHECK(ToRegister(instr->context()).is(cp)); | 3373 DCHECK(ToRegister(instr->context()).is(cp)); |
3365 __ li(scratch0(), instr->hydrogen()->pairs()); | 3374 __ li(scratch0(), instr->hydrogen()->pairs()); |
3366 __ li(scratch1(), Operand(Smi::FromInt(instr->hydrogen()->flags()))); | 3375 __ li(scratch1(), Operand(Smi::FromInt(instr->hydrogen()->flags()))); |
3367 __ Push(scratch0(), scratch1()); | 3376 __ Push(scratch0(), scratch1()); |
3368 CallRuntime(Runtime::kDeclareGlobals, instr); | 3377 CallRuntime(Runtime::kDeclareGlobals, instr); |
3369 } | 3378 } |
3370 | 3379 |
3371 | |
3372 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 3380 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
3373 int formal_parameter_count, int arity, | 3381 int formal_parameter_count, int arity, |
3374 LInstruction* instr) { | 3382 bool is_tail_call, LInstruction* instr) { |
3375 bool dont_adapt_arguments = | 3383 bool dont_adapt_arguments = |
3376 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; | 3384 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; |
3377 bool can_invoke_directly = | 3385 bool can_invoke_directly = |
3378 dont_adapt_arguments || formal_parameter_count == arity; | 3386 dont_adapt_arguments || formal_parameter_count == arity; |
3379 | 3387 |
3380 Register function_reg = a1; | 3388 Register function_reg = a1; |
3381 LPointerMap* pointers = instr->pointer_map(); | 3389 LPointerMap* pointers = instr->pointer_map(); |
3382 | 3390 |
3383 if (can_invoke_directly) { | 3391 if (can_invoke_directly) { |
3384 // Change context. | 3392 // Change context. |
3385 __ ld(cp, FieldMemOperand(function_reg, JSFunction::kContextOffset)); | 3393 __ ld(cp, FieldMemOperand(function_reg, JSFunction::kContextOffset)); |
3386 | 3394 |
3387 // Always initialize new target and number of actual arguments. | 3395 // Always initialize new target and number of actual arguments. |
3388 __ LoadRoot(a3, Heap::kUndefinedValueRootIndex); | 3396 __ LoadRoot(a3, Heap::kUndefinedValueRootIndex); |
3389 __ li(a0, Operand(arity)); | 3397 __ li(a0, Operand(arity)); |
3390 | 3398 |
| 3399 bool is_self_call = function.is_identical_to(info()->closure()); |
| 3400 |
3391 // Invoke function. | 3401 // Invoke function. |
3392 __ ld(at, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset)); | 3402 if (is_self_call) { |
3393 __ Call(at); | 3403 Handle<Code> self(reinterpret_cast<Code**>(__ CodeObject().location())); |
| 3404 if (is_tail_call) { |
| 3405 __ Jump(self, RelocInfo::CODE_TARGET); |
| 3406 } else { |
| 3407 __ Call(self, RelocInfo::CODE_TARGET); |
| 3408 } |
| 3409 } else { |
| 3410 __ ld(at, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset)); |
| 3411 if (is_tail_call) { |
| 3412 __ Jump(at); |
| 3413 } else { |
| 3414 __ Call(at); |
| 3415 } |
| 3416 } |
3394 | 3417 |
3395 // Set up deoptimization. | 3418 if (!is_tail_call) { |
3396 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); | 3419 // Set up deoptimization. |
| 3420 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); |
| 3421 } |
3397 } else { | 3422 } else { |
3398 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); | 3423 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
3399 ParameterCount count(arity); | 3424 ParameterCount actual(arity); |
3400 ParameterCount expected(formal_parameter_count); | 3425 ParameterCount expected(formal_parameter_count); |
3401 __ InvokeFunction(function_reg, expected, count, CALL_FUNCTION, generator); | 3426 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
| 3427 __ InvokeFunction(function_reg, expected, actual, flag, generator); |
3402 } | 3428 } |
3403 } | 3429 } |
3404 | 3430 |
3405 | 3431 |
3406 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) { | 3432 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) { |
3407 DCHECK(instr->context() != NULL); | 3433 DCHECK(instr->context() != NULL); |
3408 DCHECK(ToRegister(instr->context()).is(cp)); | 3434 DCHECK(ToRegister(instr->context()).is(cp)); |
3409 Register input = ToRegister(instr->value()); | 3435 Register input = ToRegister(instr->value()); |
3410 Register result = ToRegister(instr->result()); | 3436 Register result = ToRegister(instr->result()); |
3411 Register scratch = scratch0(); | 3437 Register scratch = scratch0(); |
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3744 __ MovFromFloatResult(ToDoubleRegister(instr->result())); | 3770 __ MovFromFloatResult(ToDoubleRegister(instr->result())); |
3745 } | 3771 } |
3746 | 3772 |
3747 | 3773 |
3748 void LCodeGen::DoMathClz32(LMathClz32* instr) { | 3774 void LCodeGen::DoMathClz32(LMathClz32* instr) { |
3749 Register input = ToRegister(instr->value()); | 3775 Register input = ToRegister(instr->value()); |
3750 Register result = ToRegister(instr->result()); | 3776 Register result = ToRegister(instr->result()); |
3751 __ Clz(result, input); | 3777 __ Clz(result, input); |
3752 } | 3778 } |
3753 | 3779 |
| 3780 void LCodeGen::PrepareForTailCall(const ParameterCount& actual, |
| 3781 Register scratch1, Register scratch2, |
| 3782 Register scratch3) { |
| 3783 #if DEBUG |
| 3784 if (actual.is_reg()) { |
| 3785 DCHECK(!AreAliased(actual.reg(), scratch1, scratch2, scratch3)); |
| 3786 } else { |
| 3787 DCHECK(!AreAliased(scratch1, scratch2, scratch3)); |
| 3788 } |
| 3789 #endif |
| 3790 if (FLAG_code_comments) { |
| 3791 if (actual.is_reg()) { |
| 3792 Comment(";;; PrepareForTailCall, actual: %s {", actual.reg().ToString()); |
| 3793 } else { |
| 3794 Comment(";;; PrepareForTailCall, actual: %d {", actual.immediate()); |
| 3795 } |
| 3796 } |
| 3797 |
| 3798 // Check if next frame is an arguments adaptor frame. |
| 3799 Register caller_args_count_reg = scratch1; |
| 3800 Label no_arguments_adaptor, formal_parameter_count_loaded; |
| 3801 __ ld(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 3802 __ ld(scratch3, MemOperand(scratch2, StandardFrameConstants::kContextOffset)); |
| 3803 __ Branch(&no_arguments_adaptor, ne, scratch3, |
| 3804 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 3805 |
| 3806 // Drop current frame and load arguments count from arguments adaptor frame. |
| 3807 __ mov(fp, scratch2); |
| 3808 __ ld(caller_args_count_reg, |
| 3809 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 3810 __ SmiUntag(caller_args_count_reg); |
| 3811 __ Branch(&formal_parameter_count_loaded); |
| 3812 |
| 3813 __ bind(&no_arguments_adaptor); |
| 3814 // Load caller's formal parameter count |
| 3815 __ li(caller_args_count_reg, Operand(info()->literal()->parameter_count())); |
| 3816 |
| 3817 __ bind(&formal_parameter_count_loaded); |
| 3818 __ PrepareForTailCall(actual, caller_args_count_reg, scratch2, scratch3); |
| 3819 |
| 3820 Comment(";;; }"); |
| 3821 } |
3754 | 3822 |
3755 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { | 3823 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { |
| 3824 HInvokeFunction* hinstr = instr->hydrogen(); |
3756 DCHECK(ToRegister(instr->context()).is(cp)); | 3825 DCHECK(ToRegister(instr->context()).is(cp)); |
3757 DCHECK(ToRegister(instr->function()).is(a1)); | 3826 DCHECK(ToRegister(instr->function()).is(a1)); |
3758 DCHECK(instr->HasPointerMap()); | 3827 DCHECK(instr->HasPointerMap()); |
3759 | 3828 |
3760 Handle<JSFunction> known_function = instr->hydrogen()->known_function(); | 3829 bool is_tail_call = hinstr->tail_call_mode() == TailCallMode::kAllow; |
| 3830 |
| 3831 if (is_tail_call) { |
| 3832 ParameterCount actual(instr->arity()); |
| 3833 // It is safe to use t0, t1 and t2 as scratch registers here given that |
| 3834 // we are not going to return to caller function anyway. |
| 3835 PrepareForTailCall(actual, t0, t1, t2); |
| 3836 } |
| 3837 |
| 3838 Handle<JSFunction> known_function = hinstr->known_function(); |
3761 if (known_function.is_null()) { | 3839 if (known_function.is_null()) { |
3762 LPointerMap* pointers = instr->pointer_map(); | 3840 LPointerMap* pointers = instr->pointer_map(); |
3763 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); | 3841 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
3764 ParameterCount count(instr->arity()); | 3842 ParameterCount actual(instr->arity()); |
3765 __ InvokeFunction(a1, no_reg, count, CALL_FUNCTION, generator); | 3843 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
| 3844 __ InvokeFunction(a1, no_reg, actual, flag, generator); |
3766 } else { | 3845 } else { |
3767 CallKnownFunction(known_function, | 3846 CallKnownFunction(known_function, hinstr->formal_parameter_count(), |
3768 instr->hydrogen()->formal_parameter_count(), | 3847 instr->arity(), is_tail_call, instr); |
3769 instr->arity(), instr); | |
3770 } | 3848 } |
3771 } | 3849 } |
3772 | 3850 |
3773 | 3851 |
3774 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { | 3852 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { |
3775 DCHECK(ToRegister(instr->result()).is(v0)); | 3853 DCHECK(ToRegister(instr->result()).is(v0)); |
3776 | 3854 |
3777 if (instr->hydrogen()->IsTailCall()) { | 3855 if (instr->hydrogen()->IsTailCall()) { |
3778 if (NeedsEagerFrame()) __ LeaveFrame(StackFrame::INTERNAL); | 3856 if (NeedsEagerFrame()) __ LeaveFrame(StackFrame::INTERNAL); |
3779 | 3857 |
(...skipping 1921 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5701 void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) { | 5779 void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) { |
5702 Register context = ToRegister(instr->context()); | 5780 Register context = ToRegister(instr->context()); |
5703 __ sd(context, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 5781 __ sd(context, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
5704 } | 5782 } |
5705 | 5783 |
5706 | 5784 |
5707 #undef __ | 5785 #undef __ |
5708 | 5786 |
5709 } // namespace internal | 5787 } // namespace internal |
5710 } // namespace v8 | 5788 } // namespace v8 |
OLD | NEW |