OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |