Index: src/crankshaft/ppc/lithium-codegen-ppc.cc |
diff --git a/src/crankshaft/ppc/lithium-codegen-ppc.cc b/src/crankshaft/ppc/lithium-codegen-ppc.cc |
index cf06108660a7951533facb778dce569a2d8c097a..ffd32798d41a8ceef5b18460120f56e912f128fe 100644 |
--- a/src/crankshaft/ppc/lithium-codegen-ppc.cc |
+++ b/src/crankshaft/ppc/lithium-codegen-ppc.cc |
@@ -3348,14 +3348,25 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { |
__ bdnz(&loop); |
__ bind(&invoke); |
+ |
+ InvokeFlag flag = CALL_FUNCTION; |
+ if (instr->hydrogen()->tail_call_mode() == TailCallMode::kAllow) { |
+ // TODO(ishell): drop current frame before pushing arguments to the stack. |
+ flag = JUMP_FUNCTION; |
+ ParameterCount actual(r3); |
+ // It is safe to use r6, r7 and r8 as scratch registers here given that |
+ // 1) we are not going to return to caller function anyway, |
+ // 2) r6 (new.target) will be initialized below. |
+ PrepareForTailCall(actual, r6, r7, r8); |
+ } |
+ |
DCHECK(instr->HasPointerMap()); |
LPointerMap* pointers = instr->pointer_map(); |
SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); |
// The number of arguments is stored in receiver which is r3, as expected |
// by InvokeFunction. |
ParameterCount actual(receiver); |
- __ InvokeFunction(function, no_reg, actual, CALL_FUNCTION, |
- safepoint_generator); |
+ __ InvokeFunction(function, no_reg, actual, flag, safepoint_generator); |
} |
@@ -3400,10 +3411,9 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { |
CallRuntime(Runtime::kDeclareGlobals, instr); |
} |
- |
void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
int formal_parameter_count, int arity, |
- LInstruction* instr) { |
+ bool is_tail_call, LInstruction* instr) { |
bool dont_adapt_arguments = |
formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; |
bool can_invoke_directly = |
@@ -3425,19 +3435,31 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
// Invoke function. |
if (is_self_call) { |
- __ CallSelf(); |
+ Handle<Code> self(reinterpret_cast<Code**>(__ CodeObject().location())); |
+ if (is_tail_call) { |
+ __ Jump(self, RelocInfo::CODE_TARGET); |
+ } else { |
+ __ Call(self, RelocInfo::CODE_TARGET); |
+ } |
} else { |
__ LoadP(ip, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset)); |
- __ CallJSEntry(ip); |
+ if (is_tail_call) { |
+ __ JumpToJSEntry(ip); |
+ } else { |
+ __ CallJSEntry(ip); |
+ } |
} |
- // Set up deoptimization. |
- RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); |
+ if (!is_tail_call) { |
+ // Set up deoptimization. |
+ RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); |
+ } |
} else { |
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
- ParameterCount count(arity); |
+ ParameterCount actual(arity); |
ParameterCount expected(formal_parameter_count); |
- __ InvokeFunction(function_reg, expected, count, CALL_FUNCTION, generator); |
+ InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
+ __ InvokeFunction(function_reg, expected, actual, flag, generator); |
} |
} |
@@ -3766,22 +3788,76 @@ void LCodeGen::DoMathClz32(LMathClz32* instr) { |
__ cntlzw_(result, input); |
} |
+void LCodeGen::PrepareForTailCall(const ParameterCount& actual, |
+ Register scratch1, Register scratch2, |
+ Register scratch3) { |
+#if DEBUG |
+ if (actual.is_reg()) { |
+ DCHECK(!AreAliased(actual.reg(), scratch1, scratch2, scratch3)); |
+ } else { |
+ DCHECK(!AreAliased(scratch1, scratch2, scratch3)); |
+ } |
+#endif |
+ if (FLAG_code_comments) { |
+ if (actual.is_reg()) { |
+ Comment(";;; PrepareForTailCall, actual: %s {", actual.reg().ToString()); |
+ } else { |
+ Comment(";;; PrepareForTailCall, actual: %d {", actual.immediate()); |
+ } |
+ } |
+ |
+ // Check if next frame is an arguments adaptor frame. |
+ Register caller_args_count_reg = scratch1; |
+ Label no_arguments_adaptor, formal_parameter_count_loaded; |
+ __ LoadP(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
+ __ LoadP(scratch3, |
+ MemOperand(scratch2, StandardFrameConstants::kContextOffset)); |
+ __ CmpSmiLiteral(scratch3, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0); |
+ __ bne(&no_arguments_adaptor); |
+ |
+ // Drop current frame and load arguments count from arguments adaptor frame. |
+ __ mr(fp, scratch2); |
+ __ LoadP(caller_args_count_reg, |
+ MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
+ __ SmiUntag(caller_args_count_reg); |
+ __ b(&formal_parameter_count_loaded); |
+ |
+ __ bind(&no_arguments_adaptor); |
+ // Load caller's formal parameter count |
+ __ mov(caller_args_count_reg, Operand(info()->literal()->parameter_count())); |
+ |
+ __ bind(&formal_parameter_count_loaded); |
+ __ PrepareForTailCall(actual, caller_args_count_reg, scratch2, scratch3); |
+ |
+ Comment(";;; }"); |
+} |
void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { |
+ HInvokeFunction* hinstr = instr->hydrogen(); |
DCHECK(ToRegister(instr->context()).is(cp)); |
DCHECK(ToRegister(instr->function()).is(r4)); |
DCHECK(instr->HasPointerMap()); |
- Handle<JSFunction> known_function = instr->hydrogen()->known_function(); |
+ bool is_tail_call = hinstr->tail_call_mode() == TailCallMode::kAllow; |
+ |
+ if (is_tail_call) { |
+ ParameterCount actual(instr->arity()); |
+ // It is safe to use r6, r7 and r8 as scratch registers here given that |
+ // 1) we are not going to return to caller function anyway, |
+ // 2) r6 (new.target) will be initialized below. |
+ PrepareForTailCall(actual, r6, r7, r8); |
+ } |
+ |
+ Handle<JSFunction> known_function = hinstr->known_function(); |
if (known_function.is_null()) { |
LPointerMap* pointers = instr->pointer_map(); |
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
- ParameterCount count(instr->arity()); |
- __ InvokeFunction(r4, no_reg, count, CALL_FUNCTION, generator); |
+ ParameterCount actual(instr->arity()); |
+ InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; |
+ __ InvokeFunction(r4, no_reg, actual, flag, generator); |
} else { |
- CallKnownFunction(known_function, |
- instr->hydrogen()->formal_parameter_count(), |
- instr->arity(), instr); |
+ CallKnownFunction(known_function, hinstr->formal_parameter_count(), |
+ instr->arity(), is_tail_call, instr); |
} |
} |