| 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 |