Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(409)

Unified Diff: src/hydrogen.cc

Issue 327173002: Optimize various forms of slice.call(arguments, ...) (Closed) Base URL: https://github.com/v8/v8.git@master
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/hydrogen.h ('k') | src/objects.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/hydrogen.cc
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 4db3c7fe20427af2a6a82d138f1b07b00fb1c528..a5e2d07fe4926cc4e7db1047ac6888d16116070a 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -8338,7 +8338,16 @@ bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function,
}
-bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
+static Handle<JSFunction> BuiltinFunctionById(Handle<Context> native_context,
+ BuiltinFunctionId id) {
+ Handle<FixedArray> builtins(native_context->builtin_js_functions());
+ Handle<JSFunction> result(
+ JSFunction::cast(builtins->get(static_cast<int>(id))));
+ return result;
+}
+
+
+bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) {
ASSERT(expr->expression()->IsProperty());
if (!expr->IsMonomorphic()) {
@@ -8346,20 +8355,159 @@ 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;
}
+ switch (expr->target()->shared()->builtin_function_id()) {
+ case kFunctionApply:
+ return TryCallApply(expr);
+ case kFunctionCall:
+ return TryCallCall(expr);
+ default:
+ return false;
+ }
+}
+
+
+bool HOptimizedGraphBuilder::TryCallCall(Call* expr) {
if (current_info()->scope()->arguments() == NULL) return false;
+ // It is very likely that x in x.call(...) is reference to .slice
+ // in all the recognized patterns, however, if it's not,
+ // we shouldn't go into a deopt loop
+ if (!current_info()->shared_info()->use_optimistic_optimizations()) {
+ return false;
+ }
ZoneList<Expression*>* args = expr->arguments();
- if (args->length() != 2) return false;
+ if (args->length() < 1 || args->length() > 3) return false;
+ if (!IsLiveArguments(args->at(0))) return false;
+
+ HValue* lower_bound = graph()->GetConstant0();
+ HValue* upper_bound = NULL;
+ // f.call(arguments, ConstantSmi) or
+ // f.call(arguments, ConstantSmi, ConstantSmi)
+ if (args->length() >= 2) {
+ CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(1)), true);
+ HValue* lower_bound_arg = Pop();
+ if (!lower_bound_arg->IsConstant() ||
+ !HConstant::cast(lower_bound_arg)->HasSmiValue()) {
+ return false;
+ }
+ lower_bound = lower_bound_arg;
+ }
+ // f.call(arguments, ConstantSmi, ConstantSmi)
+ if (args->length() >= 3) {
+ CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(2)), true);
+ HValue* upper_bound_arg = Pop();
+ if (!upper_bound_arg->IsConstant() ||
+ !HConstant::cast(upper_bound_arg)->HasSmiValue()) {
+ return false;
+ }
+ upper_bound = upper_bound_arg;
+ }
- 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;
+ NoObservableSideEffectsScope scope(this);
+
+ HValue* arguments_length = NULL;
+ HInstruction* arguments_elements = NULL;
+ int max_length = JSObject::kInitialMaxFastElementArray;
+ HValue* function = Pop(); // f
+ Drop(1); // call
+
+ {
+ HConstant* slice = Add<HConstant>(
+ BuiltinFunctionById(isolate()->native_context(), kArraySlice));
+ IfBuilder check_slice(this);
+ check_slice.IfNot<HCompareObjectEqAndBranch>(function, slice);
+ check_slice.Then();
+ Handle<SharedFunctionInfo> shared_info = current_info()->shared_info();
+ Add<HPushArguments>(AddUncasted<HConstant>(shared_info));
+ Add<HCallRuntime>(
+ isolate()->factory()->empty_string(),
+ Runtime::FunctionForId(Runtime::kDisableOptimisticOptimizations),
+ 1);
+ check_slice.Deopt("expected a reference to Array.prototype.slice");
+ check_slice.End();
+ }
+
+ if (function_state()->outer() == NULL) {
+ arguments_elements = Add<HArgumentsElements>(false);
+ arguments_length = AddUncasted<HArgumentsLength>(arguments_elements);
+ } else {
+ EnsureArgumentsArePushedForAccess();
+
+ arguments_elements = function_state()->arguments_elements();
+ int args_count = environment()->
+ arguments_environment()->parameter_count() - 1;
+ arguments_length = AddUncasted<HConstant>(
+ static_cast<int32_t>(args_count));
+ }
+ Add<HBoundsCheck>(arguments_length, Add<HConstant>(max_length));
+
+ // Sanitize lower bound
+ if (HConstant::cast(lower_bound)->Integer32Value() < 0) {
+ lower_bound = AddUncasted<HAdd>(lower_bound, arguments_length);
+ lower_bound = AddUncasted<HMathMinMax>(
+ lower_bound, graph()->GetConstant0(), HMathMinMax::kMathMax);
+ } else {
+ lower_bound = AddUncasted<HMathMinMax>(
+ lower_bound, arguments_length, HMathMinMax::kMathMin);
+ }
+
+ // Sanitize upper bound
+ if (upper_bound == NULL) {
+ upper_bound = arguments_length;
+ } else if (HConstant::cast(upper_bound)->Integer32Value() < 0) {
+ upper_bound = AddUncasted<HAdd>(upper_bound, arguments_length);
+ upper_bound = AddUncasted<HMathMinMax>(
+ upper_bound, graph()->GetConstant0(), HMathMinMax::kMathMax);
+ } else {
+ upper_bound = AddUncasted<HMathMinMax>(
+ upper_bound, arguments_length, HMathMinMax::kMathMin);
+ }
+
+ // Allocate correctly sized array
+ HValue* result_length = AddUncasted<HSub>(upper_bound, lower_bound);
+ result_length->ClearFlag(HValue::kCanOverflow);
+ result_length = AddUncasted<HMathMinMax>(
+ result_length, graph()->GetConstant0(), HMathMinMax::kMathMax);
+
+ ElementsKind elements_kind = FAST_HOLEY_ELEMENTS;
+ Handle<JSFunction> array_function(
+ isolate()->native_context()->array_function());
+ JSArrayBuilder array_builder(this,
+ elements_kind,
+ AddUncasted<HConstant>(array_function));
+ HValue* result =
+ BuildAllocateArrayFromLength(&array_builder, result_length);
+ HValue* result_elements = array_builder.elements_location();
+
+ // Copy arguments to the array
+ LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
+
+ HValue* index =
+ loop.BeginBody(graph()->GetConstant0(), result_length, Token::LT);
+ {
+ HValue* arguments_index = AddUncasted<HAdd>(lower_bound, index);
+ arguments_index->ClearFlag(HValue::kCanOverflow);
+ HValue* value = AddUncasted<HAccessArgumentsAt>(
+ arguments_elements, arguments_length, arguments_index);
+ Add<HStoreKeyed>(result_elements, index, value, elements_kind);
+ }
+ loop.EndBody();
+ ast_context()->ReturnValue(result);
+
+ return true;
+}
+
+
+bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
+ if (current_info()->scope()->arguments() == NULL) return false;
+
+ ZoneList<Expression*>* args = expr->arguments();
+ if (args->length() != 2) return false;
+ if (!IsLiveArguments(args->at(1))) return false;
// Found pattern f.apply(receiver, arguments).
CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true);
@@ -8671,7 +8819,7 @@ 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>();
@@ -9866,6 +10014,14 @@ HValue* HGraphBuilder::TruncateToNumber(HValue* value, Type** expected) {
}
+bool HOptimizedGraphBuilder::IsLiveArguments(Expression* expr) {
+ VariableProxy* proxy = expr->AsVariableProxy();
+ if (proxy == NULL || !proxy->var()->IsStackAllocated()) return false;
+ HValue* value = LookupAndMakeLive(proxy->var());
+ return value->CheckFlag(HValue::kIsArguments);
+}
+
+
HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
BinaryOperation* expr,
HValue* left,
« no previous file with comments | « src/hydrogen.h ('k') | src/objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698