| Index: src/crankshaft/arm64/lithium-codegen-arm64.cc | 
| diff --git a/src/crankshaft/arm64/lithium-codegen-arm64.cc b/src/crankshaft/arm64/lithium-codegen-arm64.cc | 
| index 6e9d604be8a074026a7f5e538330de3cd0b43be2..163d3ef0b4c0b9506e989a81529733267dc4aa13 100644 | 
| --- a/src/crankshaft/arm64/lithium-codegen-arm64.cc | 
| +++ b/src/crankshaft/arm64/lithium-codegen-arm64.cc | 
| @@ -1528,14 +1528,25 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { | 
| __ B(ne, &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(x0); | 
| +    // It is safe to use x3, x4 and x5 as scratch registers here given that | 
| +    // 1) we are not going to return to caller function anyway, | 
| +    // 2) x3 (new.target) will be initialized below. | 
| +    PrepareForTailCall(actual, x3, x4, x5); | 
| +  } | 
| + | 
| DCHECK(instr->HasPointerMap()); | 
| LPointerMap* pointers = instr->pointer_map(); | 
| SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt); | 
| // The number of arguments is stored in argc (receiver) which is x0, as | 
| // expected by InvokeFunction. | 
| ParameterCount actual(argc); | 
| -  __ InvokeFunction(function, no_reg, actual, CALL_FUNCTION, | 
| -                    safepoint_generator); | 
| +  __ InvokeFunction(function, no_reg, actual, flag, safepoint_generator); | 
| } | 
|  | 
|  | 
| @@ -1836,10 +1847,9 @@ void LCodeGen::DoBranch(LBranch* 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 = | 
| @@ -1867,21 +1877,38 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 
| __ LoadRoot(x3, Heap::kUndefinedValueRootIndex); | 
| __ Mov(arity_reg, arity); | 
|  | 
| +    bool is_self_call = function.is_identical_to(info()->closure()); | 
| + | 
| // Invoke function. | 
| -    __ Ldr(x10, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset)); | 
| -    __ Call(x10); | 
| +    if (is_self_call) { | 
| +      Handle<Code> self(reinterpret_cast<Code**>(__ CodeObject().location())); | 
| +      if (is_tail_call) { | 
| +        __ Jump(self, RelocInfo::CODE_TARGET); | 
| +      } else { | 
| +        __ Call(self, RelocInfo::CODE_TARGET); | 
| +      } | 
| +    } else { | 
| +      __ Ldr(x10, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset)); | 
| +      if (is_tail_call) { | 
| +        __ Jump(x10); | 
| +      } else { | 
| +        __ Call(x10); | 
| +      } | 
| +    } | 
|  | 
| -    // 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); | 
| } | 
| } | 
|  | 
| - | 
| void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { | 
| DCHECK(instr->IsMarkedAsCall()); | 
| DCHECK(ToRegister(instr->result()).Is(x0)); | 
| @@ -2786,23 +2813,78 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { | 
| __ Scvtf(result, value); | 
| } | 
|  | 
| +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; | 
| +  __ Ldr(scratch2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 
| +  __ Ldr(scratch3, | 
| +         MemOperand(scratch2, StandardFrameConstants::kContextOffset)); | 
| +  __ Cmp(scratch3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 
| +  __ B(ne, &no_arguments_adaptor); | 
| + | 
| +  // Drop current frame and load arguments count from arguments adaptor frame. | 
| +  __ mov(fp, scratch2); | 
| +  __ Ldr(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, | 
| +         Immediate(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)); | 
| // The function is required to be in x1. | 
| DCHECK(ToRegister(instr->function()).is(x1)); | 
| 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 x3, x4 and x5 as scratch registers here given that | 
| +    // 1) we are not going to return to caller function anyway, | 
| +    // 2) x3 (new.target) will be initialized below. | 
| +    PrepareForTailCall(actual, x3, x4, x5); | 
| +  } | 
| + | 
| +  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(x1, no_reg, count, CALL_FUNCTION, generator); | 
| +    ParameterCount actual(instr->arity()); | 
| +    InvokeFlag flag = is_tail_call ? JUMP_FUNCTION : CALL_FUNCTION; | 
| +    __ InvokeFunction(x1, 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); | 
| } | 
| RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta()); | 
| } | 
|  |