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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « src/hydrogen.h ('k') | src/objects.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/hydrogen.h" 5 #include "src/hydrogen.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "src/v8.h" 9 #include "src/v8.h"
10 #include "src/allocation-site-scopes.h" 10 #include "src/allocation-site-scopes.h"
(...skipping 8320 matching lines...) Expand 10 before | Expand all | Expand 10 after
8331 HInstruction* call = New<HCallWithDescriptor>( 8331 HInstruction* call = New<HCallWithDescriptor>(
8332 code_value, argc + 1, descriptor, 8332 code_value, argc + 1, descriptor,
8333 Vector<HValue*>(op_vals, descriptor->environment_length())); 8333 Vector<HValue*>(op_vals, descriptor->environment_length()));
8334 8334
8335 if (drop_extra) Drop(1); // Drop function. 8335 if (drop_extra) Drop(1); // Drop function.
8336 ast_context()->ReturnInstruction(call, ast_id); 8336 ast_context()->ReturnInstruction(call, ast_id);
8337 return true; 8337 return true;
8338 } 8338 }
8339 8339
8340 8340
8341 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { 8341 static Handle<JSFunction> BuiltinFunctionById(Handle<Context> native_context,
8342 BuiltinFunctionId id) {
8343 Handle<FixedArray> builtins(native_context->builtin_js_functions());
8344 Handle<JSFunction> result(
8345 JSFunction::cast(builtins->get(static_cast<int>(id))));
8346 return result;
8347 }
8348
8349
8350 bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) {
8342 ASSERT(expr->expression()->IsProperty()); 8351 ASSERT(expr->expression()->IsProperty());
8343 8352
8344 if (!expr->IsMonomorphic()) { 8353 if (!expr->IsMonomorphic()) {
8345 return false; 8354 return false;
8346 } 8355 }
8347 Handle<Map> function_map = expr->GetReceiverTypes()->first(); 8356 Handle<Map> function_map = expr->GetReceiverTypes()->first();
8348 if (function_map->instance_type() != JS_FUNCTION_TYPE || 8357 if (function_map->instance_type() != JS_FUNCTION_TYPE ||
8349 !expr->target()->shared()->HasBuiltinFunctionId() || 8358 !expr->target()->shared()->HasBuiltinFunctionId()) {
8350 expr->target()->shared()->builtin_function_id() != kFunctionApply) {
8351 return false; 8359 return false;
8352 } 8360 }
8353 8361
8362 switch (expr->target()->shared()->builtin_function_id()) {
8363 case kFunctionApply:
8364 return TryCallApply(expr);
8365 case kFunctionCall:
8366 return TryCallCall(expr);
8367 default:
8368 return false;
8369 }
8370 }
8371
8372
8373 bool HOptimizedGraphBuilder::TryCallCall(Call* expr) {
8374 if (current_info()->scope()->arguments() == NULL) return false;
8375 // It is very likely that x in x.call(...) is reference to .slice
8376 // in all the recognized patterns, however, if it's not,
8377 // we shouldn't go into a deopt loop
8378 if (!current_info()->shared_info()->use_optimistic_optimizations()) {
8379 return false;
8380 }
8381
8382 ZoneList<Expression*>* args = expr->arguments();
8383 if (args->length() < 1 || args->length() > 3) return false;
8384 if (!IsLiveArguments(args->at(0))) return false;
8385
8386 HValue* lower_bound = graph()->GetConstant0();
8387 HValue* upper_bound = NULL;
8388 // f.call(arguments, ConstantSmi) or
8389 // f.call(arguments, ConstantSmi, ConstantSmi)
8390 if (args->length() >= 2) {
8391 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(1)), true);
8392 HValue* lower_bound_arg = Pop();
8393 if (!lower_bound_arg->IsConstant() ||
8394 !HConstant::cast(lower_bound_arg)->HasSmiValue()) {
8395 return false;
8396 }
8397 lower_bound = lower_bound_arg;
8398 }
8399 // f.call(arguments, ConstantSmi, ConstantSmi)
8400 if (args->length() >= 3) {
8401 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(2)), true);
8402 HValue* upper_bound_arg = Pop();
8403 if (!upper_bound_arg->IsConstant() ||
8404 !HConstant::cast(upper_bound_arg)->HasSmiValue()) {
8405 return false;
8406 }
8407 upper_bound = upper_bound_arg;
8408 }
8409
8410 NoObservableSideEffectsScope scope(this);
8411
8412 HValue* arguments_length = NULL;
8413 HInstruction* arguments_elements = NULL;
8414 int max_length = JSObject::kInitialMaxFastElementArray;
8415 HValue* function = Pop(); // f
8416 Drop(1); // call
8417
8418 {
8419 HConstant* slice = Add<HConstant>(
8420 BuiltinFunctionById(isolate()->native_context(), kArraySlice));
8421 IfBuilder check_slice(this);
8422 check_slice.IfNot<HCompareObjectEqAndBranch>(function, slice);
8423 check_slice.Then();
8424 Handle<SharedFunctionInfo> shared_info = current_info()->shared_info();
8425 Add<HPushArguments>(AddUncasted<HConstant>(shared_info));
8426 Add<HCallRuntime>(
8427 isolate()->factory()->empty_string(),
8428 Runtime::FunctionForId(Runtime::kDisableOptimisticOptimizations),
8429 1);
8430 check_slice.Deopt("expected a reference to Array.prototype.slice");
8431 check_slice.End();
8432 }
8433
8434 if (function_state()->outer() == NULL) {
8435 arguments_elements = Add<HArgumentsElements>(false);
8436 arguments_length = AddUncasted<HArgumentsLength>(arguments_elements);
8437 } else {
8438 EnsureArgumentsArePushedForAccess();
8439
8440 arguments_elements = function_state()->arguments_elements();
8441 int args_count = environment()->
8442 arguments_environment()->parameter_count() - 1;
8443 arguments_length = AddUncasted<HConstant>(
8444 static_cast<int32_t>(args_count));
8445 }
8446 Add<HBoundsCheck>(arguments_length, Add<HConstant>(max_length));
8447
8448 // Sanitize lower bound
8449 if (HConstant::cast(lower_bound)->Integer32Value() < 0) {
8450 lower_bound = AddUncasted<HAdd>(lower_bound, arguments_length);
8451 lower_bound = AddUncasted<HMathMinMax>(
8452 lower_bound, graph()->GetConstant0(), HMathMinMax::kMathMax);
8453 } else {
8454 lower_bound = AddUncasted<HMathMinMax>(
8455 lower_bound, arguments_length, HMathMinMax::kMathMin);
8456 }
8457
8458 // Sanitize upper bound
8459 if (upper_bound == NULL) {
8460 upper_bound = arguments_length;
8461 } else if (HConstant::cast(upper_bound)->Integer32Value() < 0) {
8462 upper_bound = AddUncasted<HAdd>(upper_bound, arguments_length);
8463 upper_bound = AddUncasted<HMathMinMax>(
8464 upper_bound, graph()->GetConstant0(), HMathMinMax::kMathMax);
8465 } else {
8466 upper_bound = AddUncasted<HMathMinMax>(
8467 upper_bound, arguments_length, HMathMinMax::kMathMin);
8468 }
8469
8470 // Allocate correctly sized array
8471 HValue* result_length = AddUncasted<HSub>(upper_bound, lower_bound);
8472 result_length->ClearFlag(HValue::kCanOverflow);
8473 result_length = AddUncasted<HMathMinMax>(
8474 result_length, graph()->GetConstant0(), HMathMinMax::kMathMax);
8475
8476 ElementsKind elements_kind = FAST_HOLEY_ELEMENTS;
8477 Handle<JSFunction> array_function(
8478 isolate()->native_context()->array_function());
8479 JSArrayBuilder array_builder(this,
8480 elements_kind,
8481 AddUncasted<HConstant>(array_function));
8482 HValue* result =
8483 BuildAllocateArrayFromLength(&array_builder, result_length);
8484 HValue* result_elements = array_builder.elements_location();
8485
8486 // Copy arguments to the array
8487 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
8488
8489 HValue* index =
8490 loop.BeginBody(graph()->GetConstant0(), result_length, Token::LT);
8491 {
8492 HValue* arguments_index = AddUncasted<HAdd>(lower_bound, index);
8493 arguments_index->ClearFlag(HValue::kCanOverflow);
8494 HValue* value = AddUncasted<HAccessArgumentsAt>(
8495 arguments_elements, arguments_length, arguments_index);
8496 Add<HStoreKeyed>(result_elements, index, value, elements_kind);
8497 }
8498 loop.EndBody();
8499 ast_context()->ReturnValue(result);
8500
8501 return true;
8502 }
8503
8504
8505 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
8354 if (current_info()->scope()->arguments() == NULL) return false; 8506 if (current_info()->scope()->arguments() == NULL) return false;
8355 8507
8356 ZoneList<Expression*>* args = expr->arguments(); 8508 ZoneList<Expression*>* args = expr->arguments();
8357 if (args->length() != 2) return false; 8509 if (args->length() != 2) return false;
8358 8510 if (!IsLiveArguments(args->at(1))) return false;
8359 VariableProxy* arg_two = args->at(1)->AsVariableProxy();
8360 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
8361 HValue* arg_two_value = LookupAndMakeLive(arg_two->var());
8362 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
8363 8511
8364 // Found pattern f.apply(receiver, arguments). 8512 // Found pattern f.apply(receiver, arguments).
8365 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); 8513 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true);
8366 HValue* receiver = Pop(); // receiver 8514 HValue* receiver = Pop(); // receiver
8367 HValue* function = Pop(); // f 8515 HValue* function = Pop(); // f
8368 Drop(1); // apply 8516 Drop(1); // apply
8369 8517
8370 if (function_state()->outer() == NULL) { 8518 if (function_state()->outer() == NULL) {
8371 HInstruction* elements = Add<HArgumentsElements>(false); 8519 HInstruction* elements = Add<HArgumentsElements>(false);
8372 HInstruction* length = Add<HArgumentsLength>(elements); 8520 HInstruction* length = Add<HArgumentsLength>(elements);
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
8664 environment()->SetExpressionStackAt(0, function); 8812 environment()->SetExpressionStackAt(0, function);
8665 8813
8666 Push(receiver); 8814 Push(receiver);
8667 8815
8668 if (function->IsConstant() && 8816 if (function->IsConstant() &&
8669 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { 8817 HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
8670 Handle<JSFunction> known_function = Handle<JSFunction>::cast( 8818 Handle<JSFunction> known_function = Handle<JSFunction>::cast(
8671 HConstant::cast(function)->handle(isolate())); 8819 HConstant::cast(function)->handle(isolate()));
8672 expr->set_target(known_function); 8820 expr->set_target(known_function);
8673 8821
8674 if (TryCallApply(expr)) return; 8822 if (TryIndirectCall(expr)) return;
8675 CHECK_ALIVE(VisitExpressions(expr->arguments())); 8823 CHECK_ALIVE(VisitExpressions(expr->arguments()));
8676 8824
8677 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); 8825 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>();
8678 if (TryInlineBuiltinMethodCall(expr, receiver, map)) { 8826 if (TryInlineBuiltinMethodCall(expr, receiver, map)) {
8679 if (FLAG_trace_inlining) { 8827 if (FLAG_trace_inlining) {
8680 PrintF("Inlining builtin "); 8828 PrintF("Inlining builtin ");
8681 known_function->ShortPrint(); 8829 known_function->ShortPrint();
8682 PrintF("\n"); 8830 PrintF("\n");
8683 } 8831 }
8684 return; 8832 return;
(...skipping 1174 matching lines...) Expand 10 before | Expand all | Expand 10 after
9859 if (expected_obj->Is(Type::Undefined(zone()))) { 10007 if (expected_obj->Is(Type::Undefined(zone()))) {
9860 // This is already done by HChange. 10008 // This is already done by HChange.
9861 *expected = Type::Union(expected_number, Type::Number(zone()), zone()); 10009 *expected = Type::Union(expected_number, Type::Number(zone()), zone());
9862 return value; 10010 return value;
9863 } 10011 }
9864 10012
9865 return value; 10013 return value;
9866 } 10014 }
9867 10015
9868 10016
10017 bool HOptimizedGraphBuilder::IsLiveArguments(Expression* expr) {
10018 VariableProxy* proxy = expr->AsVariableProxy();
10019 if (proxy == NULL || !proxy->var()->IsStackAllocated()) return false;
10020 HValue* value = LookupAndMakeLive(proxy->var());
10021 return value->CheckFlag(HValue::kIsArguments);
10022 }
10023
10024
9869 HValue* HOptimizedGraphBuilder::BuildBinaryOperation( 10025 HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
9870 BinaryOperation* expr, 10026 BinaryOperation* expr,
9871 HValue* left, 10027 HValue* left,
9872 HValue* right, 10028 HValue* right,
9873 PushBeforeSimulateBehavior push_sim_result) { 10029 PushBeforeSimulateBehavior push_sim_result) {
9874 Type* left_type = expr->left()->bounds().lower; 10030 Type* left_type = expr->left()->bounds().lower;
9875 Type* right_type = expr->right()->bounds().lower; 10031 Type* right_type = expr->right()->bounds().lower;
9876 Type* result_type = expr->bounds().lower; 10032 Type* result_type = expr->bounds().lower;
9877 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); 10033 Maybe<int> fixed_right_arg = expr->fixed_right_arg();
9878 Handle<AllocationSite> allocation_site = expr->allocation_site(); 10034 Handle<AllocationSite> allocation_site = expr->allocation_site();
(...skipping 2269 matching lines...) Expand 10 before | Expand all | Expand 10 after
12148 if (ShouldProduceTraceOutput()) { 12304 if (ShouldProduceTraceOutput()) {
12149 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); 12305 isolate()->GetHTracer()->TraceHydrogen(name(), graph_);
12150 } 12306 }
12151 12307
12152 #ifdef DEBUG 12308 #ifdef DEBUG
12153 graph_->Verify(false); // No full verify. 12309 graph_->Verify(false); // No full verify.
12154 #endif 12310 #endif
12155 } 12311 }
12156 12312
12157 } } // namespace v8::internal 12313 } } // namespace v8::internal
OLDNEW
« 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