Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index ae63db7d538cb23f2bb463accf63ca6cd52a09ac..a9dd53513f1951d0cb69c1a02a112e5a3a1c5960 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -8084,9 +8084,9 @@ bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, |
} |
-bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, |
- Call* expr, |
- int arguments_count) { |
+bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function, |
+ Call* expr, |
+ int arguments_count) { |
return TryInline(function, |
arguments_count, |
NULL, |
@@ -8138,13 +8138,22 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { |
bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
- Call* expr, |
- HValue* receiver, |
- Handle<Map> receiver_map) { |
+ Call* expr, Handle<JSFunction> function, Handle<Map> receiver_map, |
+ int args_count_no_receiver) { |
+ if (!function->shared()->HasBuiltinFunctionId()) return false; |
+ BuiltinFunctionId id = function->shared()->builtin_function_id(); |
+ int argument_count = args_count_no_receiver + 1; // Plus receiver. |
+ |
+ if (receiver_map.is_null()) { |
+ HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver); |
+ if (receiver->IsConstant() && |
+ HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) { |
+ receiver_map = |
+ handle(Handle<HeapObject>::cast( |
+ HConstant::cast(receiver)->handle(isolate()))->map()); |
Toon Verwaest
2015/04/24 18:51:07
This caused a major issue since no map-check is ad
|
+ } |
+ } |
// Try to inline calls like Math.* as operations in the calling function. |
- if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
- BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
- int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
switch (id) { |
case kStringCharCodeAt: |
case kStringCharAt: |
@@ -8253,7 +8262,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
if (receiver_map->is_observed()) return false; |
if (!receiver_map->is_extensible()) return false; |
- Drop(expr->arguments()->length()); |
+ Drop(args_count_no_receiver); |
HValue* result; |
HValue* reduced_length; |
HValue* receiver = Pop(); |
@@ -8329,7 +8338,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); |
BuildCheckPrototypeMaps(prototype, Handle<JSObject>()); |
- const int argc = expr->arguments()->length(); |
+ const int argc = args_count_no_receiver; |
if (argc != 1) return false; |
HValue* value_to_push = Pop(); |
@@ -8386,7 +8395,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
// Threshold for fast inlined Array.shift(). |
HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16)); |
- Drop(expr->arguments()->length()); |
+ Drop(args_count_no_receiver); |
HValue* receiver = Pop(); |
HValue* function = Pop(); |
HValue* result; |
@@ -8692,7 +8701,47 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function, |
} |
-bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
+void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function, |
+ int arguments_count) { |
+ Handle<JSFunction> known_function; |
+ int args_count_no_receiver = arguments_count - 1; |
+ if (function->IsConstant() && |
+ HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
+ HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver); |
+ Handle<Map> receiver_map; |
+ if (receiver->IsConstant() && |
+ HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) { |
+ receiver_map = |
+ handle(Handle<HeapObject>::cast( |
+ HConstant::cast(receiver)->handle(isolate()))->map()); |
+ } |
+ |
+ known_function = |
+ Handle<JSFunction>::cast(HConstant::cast(function)->handle(isolate())); |
+ if (TryInlineBuiltinMethodCall(expr, known_function, receiver_map, |
+ args_count_no_receiver)) { |
+ if (FLAG_trace_inlining) { |
+ PrintF("Inlining builtin "); |
+ known_function->ShortPrint(); |
+ PrintF("\n"); |
+ } |
+ return; |
+ } |
+ |
+ if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) { |
+ return; |
+ } |
+ } |
+ |
+ PushArgumentsFromEnvironment(arguments_count); |
+ HInvokeFunction* call = |
+ New<HInvokeFunction>(function, known_function, arguments_count); |
+ Drop(1); // Function |
+ ast_context()->ReturnInstruction(call, expr->id()); |
+} |
+ |
+ |
+bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) { |
DCHECK(expr->expression()->IsProperty()); |
if (!expr->IsMonomorphic()) { |
@@ -8700,27 +8749,45 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
} |
Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
if (function_map->instance_type() != JS_FUNCTION_TYPE || |
- !expr->target()->shared()->HasBuiltinFunctionId() || |
- expr->target()->shared()->builtin_function_id() != kFunctionApply) { |
+ !expr->target()->shared()->HasBuiltinFunctionId()) { |
return false; |
} |
- if (current_info()->scope()->arguments() == NULL) return false; |
+ switch (expr->target()->shared()->builtin_function_id()) { |
+ case kFunctionCall: { |
+ if (expr->arguments()->length() == 0) return false; |
+ BuildFunctionCall(expr); |
+ return true; |
+ } |
+ case kFunctionApply: { |
+ // For .apply, only the pattern f.apply(receiver, arguments) |
+ // is supported. |
+ if (current_info()->scope()->arguments() == NULL) return false; |
- ZoneList<Expression*>* args = expr->arguments(); |
- if (args->length() != 2) return false; |
+ ZoneList<Expression*>* args = expr->arguments(); |
+ if (args->length() != 2) return false; |
+ |
+ VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
+ if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
+ HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); |
+ if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
+ BuildFunctionApply(expr); |
+ return true; |
+ } |
+ default: { return false; } |
+ } |
+ UNREACHABLE(); |
+} |
- VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
- if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
- HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); |
- if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
- // Found pattern f.apply(receiver, arguments). |
- CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); |
+void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) { |
+ ZoneList<Expression*>* args = expr->arguments(); |
+ CHECK_ALIVE(VisitForValue(args->at(0))); |
HValue* receiver = Pop(); // receiver |
HValue* function = Pop(); // f |
Drop(1); // apply |
+ Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
HValue* checked_function = AddCheckMap(function, function_map); |
if (function_state()->outer() == NULL) { |
@@ -8732,7 +8799,6 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
length, |
elements); |
ast_context()->ReturnInstruction(result, expr->id()); |
- return true; |
} else { |
// We are inside inlined function and we know exactly what is inside |
// arguments object. But we need to be able to materialize at deopt. |
@@ -8746,23 +8812,33 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
for (int i = 1; i < arguments_count; i++) { |
Push(arguments_values->at(i)); |
} |
+ HandleIndirectCall(expr, function, arguments_count); |
+ } |
+} |
- Handle<JSFunction> known_function; |
- if (function->IsConstant() && |
- HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
- known_function = Handle<JSFunction>::cast( |
- HConstant::cast(function)->handle(isolate())); |
- int args_count = arguments_count - 1; // Excluding receiver. |
- if (TryInlineApply(known_function, expr, args_count)) return true; |
- } |
- PushArgumentsFromEnvironment(arguments_count); |
- HInvokeFunction* call = New<HInvokeFunction>( |
- function, known_function, arguments_count); |
- Drop(1); // Function. |
- ast_context()->ReturnInstruction(call, expr->id()); |
- return true; |
- } |
+// f.call(...) |
+void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) { |
+ HValue* function = Top(); // f |
+ Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
+ HValue* checked_function = AddCheckMap(function, function_map); |
+ |
+ // f and call are on the stack in the unoptimized code |
+ // during evaluation of the arguments. |
+ CHECK_ALIVE(VisitExpressions(expr->arguments())); |
+ |
+ int args_length = expr->arguments()->length(); |
+ int receiver_index = args_length - 1; |
+ // Patch the receiver. |
+ HValue* receiver = BuildWrapReceiver( |
+ environment()->ExpressionStackAt(receiver_index), checked_function); |
+ environment()->SetExpressionStackAt(receiver_index, receiver); |
+ |
+ // Call must not be on the stack from now on. |
+ int call_index = args_length + 1; |
+ environment()->RemoveExpressionStackAt(call_index); |
+ |
+ HandleIndirectCall(expr, function, args_length); |
} |
@@ -9028,11 +9104,12 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
HConstant::cast(function)->handle(isolate())); |
expr->set_target(known_function); |
- if (TryCallApply(expr)) return; |
+ if (TryIndirectCall(expr)) return; |
CHECK_ALIVE(VisitExpressions(expr->arguments())); |
Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); |
- if (TryInlineBuiltinMethodCall(expr, receiver, map)) { |
+ if (TryInlineBuiltinMethodCall(expr, known_function, map, |
+ expr->arguments()->length())) { |
if (FLAG_trace_inlining) { |
PrintF("Inlining builtin "); |
known_function->ShortPrint(); |
@@ -12070,6 +12147,18 @@ void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) { |
} |
+HValue* HEnvironment::RemoveExpressionStackAt(int index_from_top) { |
+ int count = index_from_top + 1; |
+ int index = values_.length() - count; |
+ DCHECK(HasExpressionAt(index)); |
+ // Simulate popping 'count' elements and then |
+ // pushing 'count - 1' elements back. |
+ pop_count_ += Max(count - push_count_, 0); |
+ push_count_ = Max(push_count_ - count, 0) + (count - 1); |
+ return values_.Remove(index); |
+} |
+ |
+ |
void HEnvironment::Drop(int count) { |
for (int i = 0; i < count; ++i) { |
Pop(); |