Chromium Code Reviews| 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(); |