| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index 339e0d3a8aba3297551cefdabb6e799b63201e1a..3d6284d0de2ad2e6a19c01054d09137466dc48c1 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -7927,9 +7927,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,
|
| @@ -7981,19 +7981,30 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) {
|
|
|
| bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| Call* expr,
|
| - HValue* receiver,
|
| - Handle<Map> receiver_map) {
|
| + Handle<JSFunction> function,
|
| + Handle<Map> receiver_map,
|
| + int args_count_no_receiver,
|
| + int drop_extra) {
|
| + 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());
|
| + }
|
| + }
|
| // 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:
|
| if (argument_count == 2) {
|
| HValue* index = Pop();
|
| HValue* string = Pop();
|
| - Drop(1); // Function.
|
| + Drop(1 + drop_extra); // Function + extra.
|
| HInstruction* char_code =
|
| BuildStringCharCodeAt(string, index);
|
| if (id == kStringCharCodeAt) {
|
| @@ -8009,7 +8020,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| case kStringFromCharCode:
|
| if (argument_count == 2) {
|
| HValue* argument = Pop();
|
| - Drop(2); // Receiver and function.
|
| + Drop(2 + drop_extra); // Receiver and function + extra.
|
| HInstruction* result = NewUncasted<HStringCharFromCode>(argument);
|
| ast_context()->ReturnInstruction(result, expr->id());
|
| return true;
|
| @@ -8026,7 +8037,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| case kMathClz32:
|
| if (argument_count == 2) {
|
| HValue* argument = Pop();
|
| - Drop(2); // Receiver and function.
|
| + Drop(2 + drop_extra); // Receiver and function + extra.
|
| HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
|
| ast_context()->ReturnInstruction(op, expr->id());
|
| return true;
|
| @@ -8036,7 +8047,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| if (argument_count == 3) {
|
| HValue* right = Pop();
|
| HValue* left = Pop();
|
| - Drop(2); // Receiver and function.
|
| + Drop(2 + drop_extra); // Receiver and function + extra.
|
| HInstruction* result = NULL;
|
| // Use sqrt() if exponent is 0.5 or -0.5.
|
| if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
|
| @@ -8068,7 +8079,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| if (argument_count == 3) {
|
| HValue* right = Pop();
|
| HValue* left = Pop();
|
| - Drop(2); // Receiver and function.
|
| + Drop(2 + drop_extra); // Receiver and function + extra.
|
| HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin
|
| : HMathMinMax::kMathMax;
|
| HInstruction* result = NewUncasted<HMathMinMax>(left, right, op);
|
| @@ -8080,7 +8091,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| if (argument_count == 3) {
|
| HValue* right = Pop();
|
| HValue* left = Pop();
|
| - Drop(2); // Receiver and function.
|
| + Drop(2 + drop_extra); // Receiver and function + extra.
|
| HInstruction* result = HMul::NewImul(zone(), context(), left, right);
|
| ast_context()->ReturnInstruction(result, expr->id());
|
| return true;
|
| @@ -8094,7 +8105,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| if (receiver_map->is_observed()) return false;
|
| ASSERT(receiver_map->is_extensible());
|
|
|
| - Drop(expr->arguments()->length());
|
| + Drop(args_count_no_receiver);
|
| HValue* result;
|
| HValue* reduced_length;
|
| HValue* receiver = Pop();
|
| @@ -8104,7 +8115,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
| checked_object, static_cast<HValue*>(NULL),
|
| HObjectAccess::ForArrayLength(elements_kind));
|
|
|
| - Drop(1); // Function.
|
| + Drop(1 + drop_extra); // Function + extra.
|
|
|
| { NoObservableSideEffectsScope scope(this);
|
| IfBuilder length_checker(this);
|
| @@ -8170,12 +8181,12 @@ 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();
|
| HValue* array = Pop();
|
| - Drop(1); // Drop function.
|
| + Drop(1 + drop_extra); // Drop function + extra.
|
|
|
| HInstruction* new_size = NULL;
|
| HValue* length = NULL;
|
| @@ -8227,9 +8238,10 @@ 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();
|
| + Drop(drop_extra); // Drop extras after function.
|
| HValue* result;
|
|
|
| {
|
| @@ -8341,7 +8353,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
|
|
|
| HValue* search_element = Pop();
|
| HValue* receiver = Pop();
|
| - Drop(1); // Drop function.
|
| + Drop(1 + drop_extra); // Drop function + extra.
|
|
|
| ArrayIndexOfMode mode = (id == kArrayIndexOf)
|
| ? kFirstIndexOf : kLastIndexOf;
|
| @@ -8538,35 +8550,90 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function,
|
| }
|
|
|
|
|
| -bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
|
| +void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr,
|
| + HValue* function,
|
| + int arguments_count,
|
| + int drop_extra) {
|
| + Handle<JSFunction> known_function;
|
| + int args_count_no_receiver = arguments_count - 1;
|
| + if (function->IsConstant() &&
|
| + HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
|
| + known_function = Handle<JSFunction>::cast(
|
| + HConstant::cast(function)->handle(isolate()));
|
| + if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) {
|
| + Drop(drop_extra);
|
| + return;
|
| + }
|
| +
|
| + Handle<Map> map;
|
| + if (TryInlineBuiltinMethodCall(expr, known_function, map,
|
| + args_count_no_receiver, drop_extra)) {
|
| + if (FLAG_trace_inlining) {
|
| + PrintF("Inlining builtin ");
|
| + known_function->ShortPrint();
|
| + PrintF("\n");
|
| + }
|
| + return;
|
| + }
|
| + }
|
| +
|
| + PushArgumentsFromEnvironment(arguments_count);
|
| + HInvokeFunction* call = New<HInvokeFunction>(
|
| + function, known_function, arguments_count);
|
| + Drop(1 + drop_extra); // Function + extra.
|
| + ast_context()->ReturnInstruction(call, expr->id());
|
| +}
|
| +
|
| +
|
| +bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) {
|
| ASSERT(expr->expression()->IsProperty());
|
|
|
| if (!expr->IsMonomorphic()) {
|
| return false;
|
| }
|
| +
|
| 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: {
|
| + 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;
|
| + 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();
|
| +}
|
|
|
| - // 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) {
|
| @@ -8578,7 +8645,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.
|
| @@ -8592,23 +8658,36 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
|
| for (int i = 1; i < arguments_count; i++) {
|
| Push(arguments_values->at(i));
|
| }
|
| + HandleIndirectCall(expr, function, arguments_count, 0);
|
| + }
|
| +}
|
|
|
| - 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);
|
| +
|
| + int drop_extra = 0;
|
| + ZoneList<Expression*>* args = expr->arguments();
|
| + int args_length = args->length();
|
| + if (args_length == 0) {
|
| + Drop(2); // function and call
|
| + Push(function);
|
| + Push(BuildWrapReceiver(
|
| + graph()->GetConstantUndefined(), checked_function));
|
| + args_length = 1;
|
| + } else {
|
| + CHECK_ALIVE(VisitForValue(args->at(0)));
|
| + Push(BuildWrapReceiver(Pop(), checked_function));
|
| + for (int i = 1; i < args_length; i++) {
|
| + CHECK_ALIVE(VisitForValue(args->at(i)));
|
| + }
|
| + drop_extra = 1; // drop call later
|
| }
|
| +
|
| + HandleIndirectCall(expr, function, args_length, drop_extra);
|
| }
|
|
|
|
|
| @@ -8873,11 +8952,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();
|
|
|