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_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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |