OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved.7 | 1 // Copyright 2012 the V8 project authors. All rights reserved.7 |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 3112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3123 __ sll(scratch, length, 2); | 3123 __ sll(scratch, length, 2); |
3124 __ bind(&loop); | 3124 __ bind(&loop); |
3125 __ Addu(scratch, elements, scratch); | 3125 __ Addu(scratch, elements, scratch); |
3126 __ lw(scratch, MemOperand(scratch)); | 3126 __ lw(scratch, MemOperand(scratch)); |
3127 __ push(scratch); | 3127 __ push(scratch); |
3128 __ Subu(length, length, Operand(1)); | 3128 __ Subu(length, length, Operand(1)); |
3129 __ Branch(USE_DELAY_SLOT, &loop, ne, length, Operand(zero_reg)); | 3129 __ Branch(USE_DELAY_SLOT, &loop, ne, length, Operand(zero_reg)); |
3130 __ sll(scratch, length, 2); | 3130 __ sll(scratch, length, 2); |
3131 | 3131 |
3132 __ bind(&invoke); | 3132 __ bind(&invoke); |
| 3133 |
| 3134 InvokeFlag flag = CALL_FUNCTION; |
| 3135 if (instr->hydrogen()->tail_call_mode() == TailCallMode::kAllow) { |
| 3136 // TODO(ishell): drop current frame before pushing arguments to the stack. |
| 3137 flag = JUMP_FUNCTION; |
| 3138 ParameterCount actual(a0); |
| 3139 // It is safe to use t0, t1 and t2 as scratch registers here given that |
| 3140 // we are not going to return to caller function anyway. |
| 3141 PrepareForTailCall(actual, t0, t1, t2); |
| 3142 } |
| 3143 |
3133 DCHECK(instr->HasPointerMap()); | 3144 DCHECK(instr->HasPointerMap()); |
3134 LPointerMap* pointers = instr->pointer_map(); | 3145 LPointerMap* pointers = instr->pointer_map(); |
3135 SafepointGenerator safepoint_generator( | 3146 SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); |
3136 this, pointers, Safepoint::kLazyDeopt); | |
3137 // The number of arguments is stored in receiver which is a0, as expected | 3147 // The number of arguments is stored in receiver which is a0, as expected |
3138 // by InvokeFunction. | 3148 // by InvokeFunction. |
3139 ParameterCount actual(receiver); | 3149 ParameterCount actual(receiver); |
3140 __ InvokeFunction(function, no_reg, actual, CALL_FUNCTION, | 3150 __ InvokeFunction(function, no_reg, actual, flag, safepoint_generator); |
3141 safepoint_generator); | |
3142 } | 3151 } |
3143 | 3152 |
3144 | 3153 |
3145 void LCodeGen::DoPushArgument(LPushArgument* instr) { | 3154 void LCodeGen::DoPushArgument(LPushArgument* instr) { |
3146 LOperand* argument = instr->value(); | 3155 LOperand* argument = instr->value(); |
3147 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { | 3156 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { |
3148 Abort(kDoPushArgumentNotImplementedForDoubleType); | 3157 Abort(kDoPushArgumentNotImplementedForDoubleType); |
3149 } else { | 3158 } else { |
3150 Register argument_reg = EmitLoadRegister(argument, at); | 3159 Register argument_reg = EmitLoadRegister(argument, at); |
3151 __ push(argument_reg); | 3160 __ push(argument_reg); |
(...skipping 25 matching lines...) Expand all Loading... |
3177 | 3186 |
3178 | 3187 |
3179 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { | 3188 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { |
3180 DCHECK(ToRegister(instr->context()).is(cp)); | 3189 DCHECK(ToRegister(instr->context()).is(cp)); |
3181 __ li(scratch0(), instr->hydrogen()->pairs()); | 3190 __ li(scratch0(), instr->hydrogen()->pairs()); |
3182 __ li(scratch1(), Operand(Smi::FromInt(instr->hydrogen()->flags()))); | 3191 __ li(scratch1(), Operand(Smi::FromInt(instr->hydrogen()->flags()))); |
3183 __ Push(scratch0(), scratch1()); | 3192 __ Push(scratch0(), scratch1()); |
3184 CallRuntime(Runtime::kDeclareGlobals, instr); | 3193 CallRuntime(Runtime::kDeclareGlobals, instr); |
3185 } | 3194 } |
3186 | 3195 |
3187 | |
3188 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 3196 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
3189 int formal_parameter_count, int arity, | 3197 int formal_parameter_count, int arity, |
3190 LInstruction* instr) { | 3198 bool is_tail_call, LInstruction* instr) { |
3191 bool dont_adapt_arguments = | 3199 bool dont_adapt_arguments = |
3192 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; | 3200 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; |
3193 bool can_invoke_directly = | 3201 bool can_invoke_directly = |
3194 dont_adapt_arguments || formal_parameter_count == arity; | 3202 dont_adapt_arguments || formal_parameter_count == arity; |
3195 | 3203 |
3196 Register function_reg = a1; | 3204 Register function_reg = a1; |
3197 LPointerMap* pointers = instr->pointer_map(); | 3205 LPointerMap* pointers = instr->pointer_map(); |
3198 | 3206 |
3199 if (can_invoke_directly) { | 3207 if (can_invoke_directly) { |
3200 // Change context. | 3208 // Change context. |
3201 __ lw(cp, FieldMemOperand(function_reg, JSFunction::kContextOffset)); | 3209 __ lw(cp, FieldMemOperand(function_reg, JSFunction::kContextOffset)); |
3202 | 3210 |
3203 // Always initialize new target and number of actual arguments. | 3211 // Always initialize new target and number of actual arguments. |
3204 __ LoadRoot(a3, Heap::kUndefinedValueRootIndex); | 3212 __ LoadRoot(a3, Heap::kUndefinedValueRootIndex); |
3205 __ li(a0, Operand(arity)); | 3213 __ li(a0, Operand(arity)); |
3206 | 3214 |
| 3215 bool is_self_call = function.is_identical_to(info()->closure()); |
| 3216 |
3207 // Invoke function. | 3217 // Invoke function. |
3208 __ lw(at, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset)); | 3218 if (is_self_call) { |
3209 __ Call(at); | 3219 Handle<Code> self(reinterpret_cast<Code**>(__ CodeObject().location())); |
| 3220 if (is_tail_call) { |
| 3221 __ Jump(self, RelocInfo::CODE_TARGET); |
| 3222 } else { |
| 3223 __ Call(self, RelocInfo::CODE_TARGET); |
| 3224 } |
| 3225 } else { |
| 3226 __ lw(at, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset)); |
| 3227 if (is_tail_call) { |
| 3228 __ Jump(at); |
| 3229 } else { |
| 3230 __ Call(at); |
| 3231 } |
| 3232 } |
3210 | 3233 |
3211 // Set up deoptimization. | 3234 if (!is_tail_call) { |
3212 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); | 3235 // Set up deoptimization. |
| 3236 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); |
| 3237 } |
3213 } else { | 3238 } else { |
3214 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); | 3239 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
3215 ParameterCount count(arity); | 3240 ParameterCount actual(arity); |
3216 ParameterCount expected(formal_parameter_count); | 3241 ParameterCount expected(formal_parameter_count); |
3217 __ InvokeFunction(function_reg, expected, count, CALL_FUNCTION, generator); | 3242 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
| 3243 __ InvokeFunction(function_reg, expected, actual, flag, generator); |
3218 } | 3244 } |
3219 } | 3245 } |
3220 | 3246 |
3221 | 3247 |
3222 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) { | 3248 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) { |
3223 DCHECK(instr->context() != NULL); | 3249 DCHECK(instr->context() != NULL); |
3224 DCHECK(ToRegister(instr->context()).is(cp)); | 3250 DCHECK(ToRegister(instr->context()).is(cp)); |
3225 Register input = ToRegister(instr->value()); | 3251 Register input = ToRegister(instr->value()); |
3226 Register result = ToRegister(instr->result()); | 3252 Register result = ToRegister(instr->result()); |
3227 Register scratch = scratch0(); | 3253 Register scratch = scratch0(); |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3541 __ MovFromFloatResult(ToDoubleRegister(instr->result())); | 3567 __ MovFromFloatResult(ToDoubleRegister(instr->result())); |
3542 } | 3568 } |
3543 | 3569 |
3544 | 3570 |
3545 void LCodeGen::DoMathClz32(LMathClz32* instr) { | 3571 void LCodeGen::DoMathClz32(LMathClz32* instr) { |
3546 Register input = ToRegister(instr->value()); | 3572 Register input = ToRegister(instr->value()); |
3547 Register result = ToRegister(instr->result()); | 3573 Register result = ToRegister(instr->result()); |
3548 __ Clz(result, input); | 3574 __ Clz(result, input); |
3549 } | 3575 } |
3550 | 3576 |
| 3577 void LCodeGen::PrepareForTailCall(const ParameterCount& actual, |
| 3578 Register scratch1, Register scratch2, |
| 3579 Register scratch3) { |
| 3580 #if DEBUG |
| 3581 if (actual.is_reg()) { |
| 3582 DCHECK(!AreAliased(actual.reg(), scratch1, scratch2, scratch3)); |
| 3583 } else { |
| 3584 DCHECK(!AreAliased(scratch1, scratch2, scratch3)); |
| 3585 } |
| 3586 #endif |
| 3587 if (FLAG_code_comments) { |
| 3588 if (actual.is_reg()) { |
| 3589 Comment(";;; PrepareForTailCall, actual: %s {", actual.reg().ToString()); |
| 3590 } else { |
| 3591 Comment(";;; PrepareForTailCall, actual: %d {", actual.immediate()); |
| 3592 } |
| 3593 } |
| 3594 |
| 3595 // Check if next frame is an arguments adaptor frame. |
| 3596 Register caller_args_count_reg = scratch1; |
| 3597 Label no_arguments_adaptor, formal_parameter_count_loaded; |
| 3598 __ lw(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 3599 __ lw(scratch3, MemOperand(scratch2, StandardFrameConstants::kContextOffset)); |
| 3600 __ Branch(&no_arguments_adaptor, ne, scratch3, |
| 3601 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 3602 |
| 3603 // Drop current frame and load arguments count from arguments adaptor frame. |
| 3604 __ mov(fp, scratch2); |
| 3605 __ lw(caller_args_count_reg, |
| 3606 MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 3607 __ SmiUntag(caller_args_count_reg); |
| 3608 __ Branch(&formal_parameter_count_loaded); |
| 3609 |
| 3610 __ bind(&no_arguments_adaptor); |
| 3611 // Load caller's formal parameter count |
| 3612 __ lw(scratch1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 3613 __ lw(scratch1, |
| 3614 FieldMemOperand(scratch1, JSFunction::kSharedFunctionInfoOffset)); |
| 3615 __ li(caller_args_count_reg, Operand(info()->literal()->parameter_count())); |
| 3616 |
| 3617 __ bind(&formal_parameter_count_loaded); |
| 3618 __ PrepareForTailCall(actual, caller_args_count_reg, scratch2, scratch3); |
| 3619 |
| 3620 Comment(";;; }"); |
| 3621 } |
3551 | 3622 |
3552 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { | 3623 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { |
| 3624 HInvokeFunction* hinstr = instr->hydrogen(); |
3553 DCHECK(ToRegister(instr->context()).is(cp)); | 3625 DCHECK(ToRegister(instr->context()).is(cp)); |
3554 DCHECK(ToRegister(instr->function()).is(a1)); | 3626 DCHECK(ToRegister(instr->function()).is(a1)); |
3555 DCHECK(instr->HasPointerMap()); | 3627 DCHECK(instr->HasPointerMap()); |
3556 | 3628 |
3557 Handle<JSFunction> known_function = instr->hydrogen()->known_function(); | 3629 bool is_tail_call = hinstr->tail_call_mode() == TailCallMode::kAllow; |
| 3630 |
| 3631 if (is_tail_call) { |
| 3632 ParameterCount actual(instr->arity()); |
| 3633 // It is safe to use t0, t1 and t2 as scratch registers here given that |
| 3634 // we are not going to return to caller function anyway. |
| 3635 PrepareForTailCall(actual, t0, t1, t2); |
| 3636 } |
| 3637 |
| 3638 Handle<JSFunction> known_function = hinstr->known_function(); |
3558 if (known_function.is_null()) { | 3639 if (known_function.is_null()) { |
3559 LPointerMap* pointers = instr->pointer_map(); | 3640 LPointerMap* pointers = instr->pointer_map(); |
3560 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); | 3641 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
3561 ParameterCount count(instr->arity()); | 3642 ParameterCount actual(instr->arity()); |
3562 __ InvokeFunction(a1, no_reg, count, CALL_FUNCTION, generator); | 3643 InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
| 3644 __ InvokeFunction(a1, no_reg, actual, flag, generator); |
3563 } else { | 3645 } else { |
3564 CallKnownFunction(known_function, | 3646 CallKnownFunction(known_function, hinstr->formal_parameter_count(), |
3565 instr->hydrogen()->formal_parameter_count(), | 3647 instr->arity(), is_tail_call, instr); |
3566 instr->arity(), instr); | |
3567 } | 3648 } |
3568 } | 3649 } |
3569 | 3650 |
3570 | 3651 |
3571 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { | 3652 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { |
3572 DCHECK(ToRegister(instr->result()).is(v0)); | 3653 DCHECK(ToRegister(instr->result()).is(v0)); |
3573 | 3654 |
3574 if (instr->hydrogen()->IsTailCall()) { | 3655 if (instr->hydrogen()->IsTailCall()) { |
3575 if (NeedsEagerFrame()) __ LeaveFrame(StackFrame::INTERNAL); | 3656 if (NeedsEagerFrame()) __ LeaveFrame(StackFrame::INTERNAL); |
3576 | 3657 |
(...skipping 1920 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5497 void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) { | 5578 void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) { |
5498 Register context = ToRegister(instr->context()); | 5579 Register context = ToRegister(instr->context()); |
5499 __ sw(context, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 5580 __ sw(context, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
5500 } | 5581 } |
5501 | 5582 |
5502 | 5583 |
5503 #undef __ | 5584 #undef __ |
5504 | 5585 |
5505 } // namespace internal | 5586 } // namespace internal |
5506 } // namespace v8 | 5587 } // namespace v8 |
OLD | NEW |