Index: src/crankshaft/hydrogen.cc |
diff --git a/src/crankshaft/hydrogen.cc b/src/crankshaft/hydrogen.cc |
index a238c127a6848abb5f52258a40cd4443a0bc5078..e8e41d49fdd44d9e9a20906c73a6f84477277f64 100644 |
--- a/src/crankshaft/hydrogen.cc |
+++ b/src/crankshaft/hydrogen.cc |
@@ -3492,11 +3492,11 @@ HValue* HGraphBuilder::AddLoadJSBuiltin(int context_index) { |
return Add<HLoadNamedField>(native_context, nullptr, function_access); |
} |
- |
HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) |
: HGraphBuilder(info, CallInterfaceDescriptor()), |
function_state_(NULL), |
- initial_function_state_(this, info, NORMAL_RETURN, 0), |
+ initial_function_state_(this, info, NORMAL_RETURN, 0, |
+ TailCallMode::kAllow), |
ast_context_(NULL), |
break_scope_(NULL), |
inlined_count_(0), |
@@ -4032,11 +4032,12 @@ void HGraph::CollectPhis() { |
// a (possibly inlined) function. |
FunctionState::FunctionState(HOptimizedGraphBuilder* owner, |
CompilationInfo* info, InliningKind inlining_kind, |
- int inlining_id) |
+ int inlining_id, TailCallMode tail_call_mode) |
: owner_(owner), |
compilation_info_(info), |
call_context_(NULL), |
inlining_kind_(inlining_kind), |
+ tail_call_mode_(tail_call_mode), |
function_return_(NULL), |
test_context_(NULL), |
entry_(NULL), |
@@ -6573,7 +6574,8 @@ HValue* HOptimizedGraphBuilder::BuildMonomorphicAccess( |
HValue* function = Add<HConstant>(info->accessor()); |
PushArgumentsFromEnvironment(argument_count); |
return NewCallFunction(function, argument_count, |
- ConvertReceiverMode::kNotNullOrUndefined); |
+ ConvertReceiverMode::kNotNullOrUndefined, |
+ TailCallMode::kDisallow); |
} else if (FLAG_inline_accessors && can_inline_accessor) { |
bool success = info->IsLoad() |
? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id) |
@@ -6588,7 +6590,7 @@ HValue* HOptimizedGraphBuilder::BuildMonomorphicAccess( |
return nullptr; |
} |
return NewCallConstantFunction(Handle<JSFunction>::cast(info->accessor()), |
- argument_count); |
+ argument_count, TailCallMode::kDisallow); |
} |
DCHECK(info->IsDataConstant()); |
@@ -7987,11 +7989,13 @@ void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, |
} |
HInstruction* HOptimizedGraphBuilder::NewCallFunction( |
- HValue* function, int argument_count, ConvertReceiverMode convert_mode) { |
+ HValue* function, int argument_count, ConvertReceiverMode convert_mode, |
+ TailCallMode tail_call_mode) { |
HValue* arity = Add<HConstant>(argument_count - 1); |
HValue* op_vals[] = {context(), function, arity}; |
+ // TODO(ishell): use tail_call_mode here. |
Callable callable = CodeFactory::Call(isolate(), convert_mode); |
HConstant* stub = Add<HConstant>(callable.code()); |
@@ -8001,7 +8005,7 @@ HInstruction* HOptimizedGraphBuilder::NewCallFunction( |
HInstruction* HOptimizedGraphBuilder::NewCallFunctionViaIC( |
HValue* function, int argument_count, ConvertReceiverMode convert_mode, |
- FeedbackVectorSlot slot) { |
+ TailCallMode tail_call_mode, FeedbackVectorSlot slot) { |
int arity = argument_count - 1; |
Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); |
HValue* index_val = Add<HConstant>(vector->GetIndex(slot)); |
@@ -8009,6 +8013,7 @@ HInstruction* HOptimizedGraphBuilder::NewCallFunctionViaIC( |
HValue* op_vals[] = {context(), function, index_val, vector_val}; |
+ // TODO(ishell): use tail_call_mode here. |
Callable callable = CodeFactory::CallICInOptimizedCode( |
isolate(), arity, ConvertReceiverMode::kNullOrUndefined); |
HConstant* stub = Add<HConstant>(callable.code()); |
@@ -8018,7 +8023,9 @@ HInstruction* HOptimizedGraphBuilder::NewCallFunctionViaIC( |
} |
HInstruction* HOptimizedGraphBuilder::NewCallConstantFunction( |
- Handle<JSFunction> function, int argument_count) { |
+ Handle<JSFunction> function, int argument_count, |
+ TailCallMode tail_call_mode) { |
+ // TODO(ishell): use tail_call_mode here. |
HValue* target = Add<HConstant>(function); |
return New<HInvokeFunction>(target, function, argument_count); |
} |
@@ -8058,6 +8065,10 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
bool handled_string = false; |
int ordered_functions = 0; |
+ TailCallMode syntactic_tail_call_mode = expr->tail_call_mode(); |
+ TailCallMode tail_call_mode = |
+ function_state()->ComputeTailCallMode(syntactic_tail_call_mode); |
+ |
int i; |
for (i = 0; i < maps->length() && ordered_functions < kMaxCallPolymorphism; |
++i) { |
@@ -8168,8 +8179,9 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
HInstruction* call = |
needs_wrapping |
? NewCallFunction(function, argument_count, |
- ConvertReceiverMode::kNotNullOrUndefined) |
- : NewCallConstantFunction(target, argument_count); |
+ ConvertReceiverMode::kNotNullOrUndefined, |
+ tail_call_mode) |
+ : NewCallConstantFunction(target, argument_count, tail_call_mode); |
PushArgumentsFromEnvironment(argument_count); |
AddInstruction(call); |
Drop(1); // Drop the function. |
@@ -8199,7 +8211,8 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
CHECK_ALIVE(VisitExpressions(expr->arguments())); |
HInstruction* call = NewCallFunction( |
- function, argument_count, ConvertReceiverMode::kNotNullOrUndefined); |
+ function, argument_count, ConvertReceiverMode::kNotNullOrUndefined, |
+ tail_call_mode); |
PushArgumentsFromEnvironment(argument_count); |
@@ -8227,17 +8240,19 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
} |
} |
- |
void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target, |
Handle<JSFunction> caller, |
- const char* reason) { |
+ const char* reason, |
+ TailCallMode tail_call_mode) { |
if (FLAG_trace_inlining) { |
base::SmartArrayPointer<char> target_name = |
target->shared()->DebugName()->ToCString(); |
base::SmartArrayPointer<char> caller_name = |
caller->shared()->DebugName()->ToCString(); |
if (reason == NULL) { |
- PrintF("Inlined %s called from %s.\n", target_name.get(), |
+ const char* call_mode = |
+ tail_call_mode == TailCallMode::kAllow ? "tail called" : "called"; |
+ PrintF("Inlined %s %s from %s.\n", target_name.get(), call_mode, |
caller_name.get()); |
} else { |
PrintF("Did not inline %s called from %s (%s).\n", |
@@ -8294,12 +8309,12 @@ int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) { |
return nodes_added; |
} |
- |
bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, |
int arguments_count, |
HValue* implicit_return_value, |
BailoutId ast_id, BailoutId return_id, |
- InliningKind inlining_kind) { |
+ InliningKind inlining_kind, |
+ TailCallMode syntactic_tail_call_mode) { |
if (target->context()->native_context() != |
top_info()->closure()->context()->native_context()) { |
return false; |
@@ -8308,6 +8323,10 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, |
if (nodes_added == kNotInlinable) return false; |
Handle<JSFunction> caller = current_info()->closure(); |
+ if (syntactic_tail_call_mode == TailCallMode::kAllow) { |
+ TraceInline(target, caller, "call is at tail position"); |
+ return false; |
+ } |
if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { |
TraceInline(target, caller, "target AST is too large [early]"); |
@@ -8469,8 +8488,9 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, |
// Save the pending call context. Set up new one for the inlined function. |
// The function state is new-allocated because we need to delete it |
// in two different places. |
- FunctionState* target_state = |
- new FunctionState(this, &target_info, inlining_kind, inlining_id); |
+ FunctionState* target_state = new FunctionState( |
+ this, &target_info, inlining_kind, inlining_id, |
+ function_state()->ComputeTailCallMode(syntactic_tail_call_mode)); |
HConstant* undefined = graph()->GetConstantUndefined(); |
@@ -8540,7 +8560,7 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, |
TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info())); |
graph()->update_type_change_checksum(type_info->own_type_change_checksum()); |
- TraceInline(target, caller, NULL); |
+ TraceInline(target, caller, NULL, syntactic_tail_call_mode); |
if (current_block() != NULL) { |
FunctionState* state = function_state(); |
@@ -8624,7 +8644,8 @@ bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, |
bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) { |
return TryInline(expr->target(), expr->arguments()->length(), NULL, |
- expr->id(), expr->ReturnId(), NORMAL_RETURN); |
+ expr->id(), expr->ReturnId(), NORMAL_RETURN, |
+ expr->tail_call_mode()); |
} |
@@ -8632,7 +8653,7 @@ bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, |
HValue* implicit_return_value) { |
return TryInline(expr->target(), expr->arguments()->length(), |
implicit_return_value, expr->id(), expr->ReturnId(), |
- CONSTRUCT_CALL_RETURN); |
+ CONSTRUCT_CALL_RETURN, TailCallMode::kDisallow); |
} |
bool HOptimizedGraphBuilder::TryInlineGetter(Handle<Object> getter, |
@@ -8642,7 +8663,7 @@ bool HOptimizedGraphBuilder::TryInlineGetter(Handle<Object> getter, |
if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true; |
return getter->IsJSFunction() && |
TryInline(Handle<JSFunction>::cast(getter), 0, NULL, ast_id, return_id, |
- GETTER_CALL_RETURN); |
+ GETTER_CALL_RETURN, TailCallMode::kDisallow); |
} |
bool HOptimizedGraphBuilder::TryInlineSetter(Handle<Object> setter, |
@@ -8653,7 +8674,8 @@ bool HOptimizedGraphBuilder::TryInlineSetter(Handle<Object> setter, |
if (TryInlineApiSetter(setter, receiver_map, id)) return true; |
return setter->IsJSFunction() && |
TryInline(Handle<JSFunction>::cast(setter), 1, implicit_return_value, |
- id, assignment_id, SETTER_CALL_RETURN); |
+ id, assignment_id, SETTER_CALL_RETURN, |
+ TailCallMode::kDisallow); |
} |
@@ -8661,13 +8683,15 @@ bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function, |
Call* expr, |
int arguments_count) { |
return TryInline(function, arguments_count, NULL, expr->id(), |
- expr->ReturnId(), NORMAL_RETURN); |
+ expr->ReturnId(), NORMAL_RETURN, expr->tail_call_mode()); |
} |
bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { |
if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
+ // We intentionally ignore expr->tail_call_mode() here because builtins |
+ // we inline here do not observe if they were tail called or not. |
switch (id) { |
case kMathExp: |
if (!FLAG_fast_math) break; |
@@ -9083,7 +9107,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
if_inline.Else(); |
{ |
Add<HPushArguments>(receiver); |
- result = AddInstruction(NewCallConstantFunction(function, 1)); |
+ result = AddInstruction( |
+ NewCallConstantFunction(function, 1, TailCallMode::kDisallow)); |
if (!ast_context()->IsEffect()) Push(result); |
} |
if_inline.End(); |
@@ -9147,12 +9172,8 @@ bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, |
Handle<JSFunction> function = expr->target(); |
int argc = expr->arguments()->length(); |
SmallMapList receiver_maps; |
- return TryInlineApiCall(function, |
- receiver, |
- &receiver_maps, |
- argc, |
- expr->id(), |
- kCallApiFunction); |
+ return TryInlineApiCall(function, receiver, &receiver_maps, argc, expr->id(), |
+ kCallApiFunction, expr->tail_call_mode()); |
} |
@@ -9162,12 +9183,8 @@ bool HOptimizedGraphBuilder::TryInlineApiMethodCall( |
SmallMapList* receiver_maps) { |
Handle<JSFunction> function = expr->target(); |
int argc = expr->arguments()->length(); |
- return TryInlineApiCall(function, |
- receiver, |
- receiver_maps, |
- argc, |
- expr->id(), |
- kCallApiMethod); |
+ return TryInlineApiCall(function, receiver, receiver_maps, argc, expr->id(), |
+ kCallApiMethod, expr->tail_call_mode()); |
} |
bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<Object> function, |
@@ -9177,10 +9194,8 @@ bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<Object> function, |
receiver_maps.Add(receiver_map, zone()); |
return TryInlineApiCall(function, |
NULL, // Receiver is on expression stack. |
- &receiver_maps, |
- 0, |
- ast_id, |
- kCallApiGetter); |
+ &receiver_maps, 0, ast_id, kCallApiGetter, |
+ TailCallMode::kDisallow); |
} |
bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<Object> function, |
@@ -9190,22 +9205,22 @@ bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<Object> function, |
receiver_maps.Add(receiver_map, zone()); |
return TryInlineApiCall(function, |
NULL, // Receiver is on expression stack. |
- &receiver_maps, |
- 1, |
- ast_id, |
- kCallApiSetter); |
+ &receiver_maps, 1, ast_id, kCallApiSetter, |
+ TailCallMode::kDisallow); |
} |
-bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<Object> function, |
- HValue* receiver, |
- SmallMapList* receiver_maps, |
- int argc, BailoutId ast_id, |
- ApiCallType call_type) { |
+bool HOptimizedGraphBuilder::TryInlineApiCall( |
+ Handle<Object> function, HValue* receiver, SmallMapList* receiver_maps, |
+ int argc, BailoutId ast_id, ApiCallType call_type, |
+ TailCallMode syntactic_tail_call_mode) { |
if (function->IsJSFunction() && |
Handle<JSFunction>::cast(function)->context()->native_context() != |
top_info()->closure()->context()->native_context()) { |
return false; |
} |
+ if (syntactic_tail_call_mode == TailCallMode::kAllow) { |
+ return false; |
+ } |
CallOptimization optimization(function); |
if (!optimization.is_simple_api_call()) return false; |
Handle<Map> holder_map; |
@@ -9359,6 +9374,12 @@ void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function, |
} |
} |
+ TailCallMode syntactic_tail_call_mode = expr->tail_call_mode(); |
+ TailCallMode tail_call_mode = |
+ function_state()->ComputeTailCallMode(syntactic_tail_call_mode); |
+ USE(tail_call_mode); |
+ |
+ // TODO(ishell): use tail_call_mode here. |
PushArgumentsFromEnvironment(arguments_count); |
HInvokeFunction* call = |
New<HInvokeFunction>(function, known_function, arguments_count); |
@@ -9413,6 +9434,12 @@ void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) { |
HValue* checked_function = AddCheckMap(function, function_map); |
if (function_state()->outer() == NULL) { |
+ TailCallMode syntactic_tail_call_mode = expr->tail_call_mode(); |
+ TailCallMode tail_call_mode = |
+ function_state()->ComputeTailCallMode(syntactic_tail_call_mode); |
+ USE(tail_call_mode); |
+ |
+ // TODO(ishell): use tail_call_mode here. |
HInstruction* elements = Add<HArgumentsElements>(false); |
HInstruction* length = Add<HArgumentsLength>(elements); |
HValue* wrapped_receiver = BuildWrapReceiver(receiver, checked_function); |
@@ -9698,6 +9725,10 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
HInstruction* call = NULL; |
+ TailCallMode syntactic_tail_call_mode = expr->tail_call_mode(); |
+ TailCallMode tail_call_mode = |
+ function_state()->ComputeTailCallMode(syntactic_tail_call_mode); |
+ |
Property* prop = callee->AsProperty(); |
if (prop != NULL) { |
CHECK_ALIVE(VisitForValue(prop->obj())); |
@@ -9756,11 +9787,13 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
// TODO(verwaest): Support creation of value wrappers directly in |
// HWrapReceiver. |
call = NewCallFunction(function, argument_count, |
- ConvertReceiverMode::kNotNullOrUndefined); |
+ ConvertReceiverMode::kNotNullOrUndefined, |
+ tail_call_mode); |
} else if (TryInlineCall(expr)) { |
return; |
} else { |
- call = NewCallConstantFunction(known_function, argument_count); |
+ call = NewCallConstantFunction(known_function, argument_count, |
+ tail_call_mode); |
} |
} else { |
@@ -9780,7 +9813,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag)); |
call = NewCallFunction(function, argument_count, |
- ConvertReceiverMode::kNotNullOrUndefined); |
+ ConvertReceiverMode::kNotNullOrUndefined, |
+ tail_call_mode); |
} |
PushArgumentsFromEnvironment(argument_count); |
@@ -9827,7 +9861,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
if (TryInlineCall(expr)) return; |
PushArgumentsFromEnvironment(argument_count); |
- call = NewCallConstantFunction(expr->target(), argument_count); |
+ call = NewCallConstantFunction(expr->target(), argument_count, |
+ tail_call_mode); |
} else { |
PushArgumentsFromEnvironment(argument_count); |
if (expr->is_uninitialized() && |
@@ -9836,10 +9871,11 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
// through the type vector. |
call = NewCallFunctionViaIC(function, argument_count, |
ConvertReceiverMode::kNullOrUndefined, |
- expr->CallFeedbackICSlot()); |
+ tail_call_mode, expr->CallFeedbackICSlot()); |
} else { |
call = NewCallFunction(function, argument_count, |
- ConvertReceiverMode::kNullOrUndefined); |
+ ConvertReceiverMode::kNullOrUndefined, |
+ tail_call_mode); |
} |
} |
} |