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 #if V8_TARGET_ARCH_X87 | 5 #if V8_TARGET_ARCH_X87 |
6 | 6 |
7 #include "src/crankshaft/x87/lithium-codegen-x87.h" | 7 #include "src/crankshaft/x87/lithium-codegen-x87.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 3189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3200 // length is a small non-negative integer, due to the test above. | 3200 // length is a small non-negative integer, due to the test above. |
3201 __ test(length, Operand(length)); | 3201 __ test(length, Operand(length)); |
3202 __ j(zero, &invoke, Label::kNear); | 3202 __ j(zero, &invoke, Label::kNear); |
3203 __ bind(&loop); | 3203 __ bind(&loop); |
3204 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize)); | 3204 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize)); |
3205 __ dec(length); | 3205 __ dec(length); |
3206 __ j(not_zero, &loop); | 3206 __ j(not_zero, &loop); |
3207 | 3207 |
3208 // Invoke the function. | 3208 // Invoke the function. |
3209 __ bind(&invoke); | 3209 __ bind(&invoke); |
| 3210 |
| 3211 InvokeFlag flag = CALL_FUNCTION; |
| 3212 if (instr->hydrogen()->tail_call_mode() == TailCallMode::kAllow) { |
| 3213 // TODO(ishell): drop current frame before pushing arguments to the stack. |
| 3214 flag = JUMP_FUNCTION; |
| 3215 ParameterCount actual(eax); |
| 3216 // It is safe to use ebx, ecx and edx as scratch registers here given that |
| 3217 // 1) we are not going to return to caller function anyway, |
| 3218 // 2) ebx (expected arguments count) and edx (new.target) will be |
| 3219 // initialized below. |
| 3220 PrepareForTailCall(actual, ebx, ecx, edx); |
| 3221 } |
| 3222 |
3210 DCHECK(instr->HasPointerMap()); | 3223 DCHECK(instr->HasPointerMap()); |
3211 LPointerMap* pointers = instr->pointer_map(); | 3224 LPointerMap* pointers = instr->pointer_map(); |
3212 SafepointGenerator safepoint_generator( | 3225 SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); |
3213 this, pointers, Safepoint::kLazyDeopt); | |
3214 ParameterCount actual(eax); | 3226 ParameterCount actual(eax); |
3215 __ InvokeFunction(function, no_reg, actual, CALL_FUNCTION, | 3227 __ InvokeFunction(function, no_reg, actual, flag, safepoint_generator); |
3216 safepoint_generator); | |
3217 } | 3228 } |
3218 | 3229 |
3219 | 3230 |
3220 void LCodeGen::DoDebugBreak(LDebugBreak* instr) { | 3231 void LCodeGen::DoDebugBreak(LDebugBreak* instr) { |
3221 __ int3(); | 3232 __ int3(); |
3222 } | 3233 } |
3223 | 3234 |
3224 | 3235 |
3225 void LCodeGen::DoPushArgument(LPushArgument* instr) { | 3236 void LCodeGen::DoPushArgument(LPushArgument* instr) { |
3226 LOperand* argument = instr->value(); | 3237 LOperand* argument = instr->value(); |
(...skipping 23 matching lines...) Expand all Loading... |
3250 } | 3261 } |
3251 | 3262 |
3252 | 3263 |
3253 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { | 3264 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { |
3254 DCHECK(ToRegister(instr->context()).is(esi)); | 3265 DCHECK(ToRegister(instr->context()).is(esi)); |
3255 __ push(Immediate(instr->hydrogen()->pairs())); | 3266 __ push(Immediate(instr->hydrogen()->pairs())); |
3256 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags()))); | 3267 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags()))); |
3257 CallRuntime(Runtime::kDeclareGlobals, instr); | 3268 CallRuntime(Runtime::kDeclareGlobals, instr); |
3258 } | 3269 } |
3259 | 3270 |
3260 | |
3261 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 3271 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
3262 int formal_parameter_count, int arity, | 3272 int formal_parameter_count, int arity, |
3263 LInstruction* instr) { | 3273 bool is_tail_call, LInstruction* instr) { |
3264 bool dont_adapt_arguments = | 3274 bool dont_adapt_arguments = |
3265 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; | 3275 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; |
3266 bool can_invoke_directly = | 3276 bool can_invoke_directly = |
3267 dont_adapt_arguments || formal_parameter_count == arity; | 3277 dont_adapt_arguments || formal_parameter_count == arity; |
3268 | 3278 |
3269 Register function_reg = edi; | 3279 Register function_reg = edi; |
3270 | 3280 |
3271 if (can_invoke_directly) { | 3281 if (can_invoke_directly) { |
3272 // Change context. | 3282 // Change context. |
3273 __ mov(esi, FieldOperand(function_reg, JSFunction::kContextOffset)); | 3283 __ mov(esi, FieldOperand(function_reg, JSFunction::kContextOffset)); |
3274 | 3284 |
3275 // Always initialize new target and number of actual arguments. | 3285 // Always initialize new target and number of actual arguments. |
3276 __ mov(edx, factory()->undefined_value()); | 3286 __ mov(edx, factory()->undefined_value()); |
3277 __ mov(eax, arity); | 3287 __ mov(eax, arity); |
3278 | 3288 |
| 3289 bool is_self_call = function.is_identical_to(info()->closure()); |
| 3290 |
3279 // Invoke function directly. | 3291 // Invoke function directly. |
3280 if (function.is_identical_to(info()->closure())) { | 3292 if (is_self_call) { |
3281 __ CallSelf(); | 3293 Handle<Code> self(reinterpret_cast<Code**>(__ CodeObject().location())); |
| 3294 if (is_tail_call) { |
| 3295 __ Jump(self, RelocInfo::CODE_TARGET); |
| 3296 } else { |
| 3297 __ Call(self, RelocInfo::CODE_TARGET); |
| 3298 } |
3282 } else { | 3299 } else { |
3283 __ call(FieldOperand(function_reg, JSFunction::kCodeEntryOffset)); | 3300 Operand target = FieldOperand(function_reg, JSFunction::kCodeEntryOffset); |
| 3301 if (is_tail_call) { |
| 3302 __ jmp(target); |
| 3303 } else { |
| 3304 __ call(target); |
| 3305 } |
3284 } | 3306 } |
3285 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); | 3307 |
| 3308 if (!is_tail_call) { |
| 3309 // Set up deoptimization. |
| 3310 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); |
| 3311 } |
3286 } else { | 3312 } else { |
3287 // We need to adapt arguments. | 3313 // We need to adapt arguments. |
3288 LPointerMap* pointers = instr->pointer_map(); | 3314 LPointerMap* pointers = instr->pointer_map(); |
3289 SafepointGenerator generator( | 3315 SafepointGenerator generator( |
3290 this, pointers, Safepoint::kLazyDeopt); | 3316 this, pointers, Safepoint::kLazyDeopt); |
3291 ParameterCount count(arity); | 3317 ParameterCount actual(arity); |
3292 ParameterCount expected(formal_parameter_count); | 3318 ParameterCount expected(formal_parameter_count); |
3293 __ InvokeFunction(function_reg, expected, count, CALL_FUNCTION, generator); | 3319 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
| 3320 __ InvokeFunction(function_reg, expected, actual, flag, generator); |
3294 } | 3321 } |
3295 } | 3322 } |
3296 | 3323 |
3297 | 3324 |
3298 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { | 3325 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { |
3299 DCHECK(ToRegister(instr->result()).is(eax)); | 3326 DCHECK(ToRegister(instr->result()).is(eax)); |
3300 | 3327 |
3301 if (instr->hydrogen()->IsTailCall()) { | 3328 if (instr->hydrogen()->IsTailCall()) { |
3302 if (NeedsEagerFrame()) __ leave(); | 3329 if (NeedsEagerFrame()) __ leave(); |
3303 | 3330 |
(...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3757 // SMI | 3784 // SMI |
3758 __ bind(&smi); | 3785 __ bind(&smi); |
3759 __ SmiUntag(temp_result); | 3786 __ SmiUntag(temp_result); |
3760 __ push(temp_result); | 3787 __ push(temp_result); |
3761 __ fild_s(MemOperand(esp, 0)); | 3788 __ fild_s(MemOperand(esp, 0)); |
3762 __ pop(temp_result); | 3789 __ pop(temp_result); |
3763 __ bind(&finish); | 3790 __ bind(&finish); |
3764 X87CommitWrite(result_reg); | 3791 X87CommitWrite(result_reg); |
3765 } | 3792 } |
3766 | 3793 |
| 3794 void LCodeGen::PrepareForTailCall(const ParameterCount& actual, |
| 3795 Register scratch1, Register scratch2, |
| 3796 Register scratch3) { |
| 3797 #if DEBUG |
| 3798 if (actual.is_reg()) { |
| 3799 DCHECK(!AreAliased(actual.reg(), scratch1, scratch2, scratch3)); |
| 3800 } else { |
| 3801 DCHECK(!AreAliased(scratch1, scratch2, scratch3)); |
| 3802 } |
| 3803 #endif |
| 3804 if (FLAG_code_comments) { |
| 3805 if (actual.is_reg()) { |
| 3806 Comment(";;; PrepareForTailCall, actual: %s {", actual.reg().ToString()); |
| 3807 } else { |
| 3808 Comment(";;; PrepareForTailCall, actual: %d {", actual.immediate()); |
| 3809 } |
| 3810 } |
| 3811 |
| 3812 // Check if next frame is an arguments adaptor frame. |
| 3813 Register caller_args_count_reg = scratch1; |
| 3814 Label no_arguments_adaptor, formal_parameter_count_loaded; |
| 3815 __ mov(scratch2, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
| 3816 __ cmp(Operand(scratch2, StandardFrameConstants::kContextOffset), |
| 3817 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 3818 __ j(not_equal, &no_arguments_adaptor, Label::kNear); |
| 3819 |
| 3820 // Drop current frame and load arguments count from arguments adaptor frame. |
| 3821 __ mov(ebp, scratch2); |
| 3822 __ mov(caller_args_count_reg, |
| 3823 Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 3824 __ SmiUntag(caller_args_count_reg); |
| 3825 __ jmp(&formal_parameter_count_loaded, Label::kNear); |
| 3826 |
| 3827 __ bind(&no_arguments_adaptor); |
| 3828 // Load caller's formal parameter count. |
| 3829 __ mov(caller_args_count_reg, |
| 3830 Immediate(info()->literal()->parameter_count())); |
| 3831 |
| 3832 __ bind(&formal_parameter_count_loaded); |
| 3833 __ PrepareForTailCall(actual, caller_args_count_reg, scratch2, scratch3, |
| 3834 ReturnAddressState::kNotOnStack); |
| 3835 Comment(";;; }"); |
| 3836 } |
3767 | 3837 |
3768 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { | 3838 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { |
| 3839 HInvokeFunction* hinstr = instr->hydrogen(); |
3769 DCHECK(ToRegister(instr->context()).is(esi)); | 3840 DCHECK(ToRegister(instr->context()).is(esi)); |
3770 DCHECK(ToRegister(instr->function()).is(edi)); | 3841 DCHECK(ToRegister(instr->function()).is(edi)); |
3771 DCHECK(instr->HasPointerMap()); | 3842 DCHECK(instr->HasPointerMap()); |
3772 | 3843 |
3773 Handle<JSFunction> known_function = instr->hydrogen()->known_function(); | 3844 bool is_tail_call = hinstr->tail_call_mode() == TailCallMode::kAllow; |
| 3845 |
| 3846 if (is_tail_call) { |
| 3847 ParameterCount actual(instr->arity()); |
| 3848 // It is safe to use ebx, ecx and edx as scratch registers here given that |
| 3849 // 1) we are not going to return to caller function anyway, |
| 3850 // 2) ebx (expected arguments count) and edx (new.target) will be |
| 3851 // initialized below. |
| 3852 PrepareForTailCall(actual, ebx, ecx, edx); |
| 3853 } |
| 3854 |
| 3855 Handle<JSFunction> known_function = hinstr->known_function(); |
3774 if (known_function.is_null()) { | 3856 if (known_function.is_null()) { |
3775 LPointerMap* pointers = instr->pointer_map(); | 3857 LPointerMap* pointers = instr->pointer_map(); |
3776 SafepointGenerator generator( | 3858 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
3777 this, pointers, Safepoint::kLazyDeopt); | 3859 ParameterCount actual(instr->arity()); |
3778 ParameterCount count(instr->arity()); | 3860 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
3779 __ InvokeFunction(edi, no_reg, count, CALL_FUNCTION, generator); | 3861 __ InvokeFunction(edi, no_reg, actual, flag, generator); |
3780 } else { | 3862 } else { |
3781 CallKnownFunction(known_function, | 3863 CallKnownFunction(known_function, hinstr->formal_parameter_count(), |
3782 instr->hydrogen()->formal_parameter_count(), | 3864 instr->arity(), is_tail_call, instr); |
3783 instr->arity(), instr); | |
3784 } | 3865 } |
3785 } | 3866 } |
3786 | 3867 |
3787 | 3868 |
3788 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { | 3869 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { |
3789 DCHECK(ToRegister(instr->context()).is(esi)); | 3870 DCHECK(ToRegister(instr->context()).is(esi)); |
3790 DCHECK(ToRegister(instr->constructor()).is(edi)); | 3871 DCHECK(ToRegister(instr->constructor()).is(edi)); |
3791 DCHECK(ToRegister(instr->result()).is(eax)); | 3872 DCHECK(ToRegister(instr->result()).is(eax)); |
3792 | 3873 |
3793 __ Move(eax, Immediate(instr->arity())); | 3874 __ Move(eax, Immediate(instr->arity())); |
(...skipping 1965 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5759 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), context); | 5840 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), context); |
5760 } | 5841 } |
5761 | 5842 |
5762 | 5843 |
5763 #undef __ | 5844 #undef __ |
5764 | 5845 |
5765 } // namespace internal | 5846 } // namespace internal |
5766 } // namespace v8 | 5847 } // namespace v8 |
5767 | 5848 |
5768 #endif // V8_TARGET_ARCH_X87 | 5849 #endif // V8_TARGET_ARCH_X87 |
OLD | NEW |