OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/compiler/js-call-reducer.h" | 5 #include "src/compiler/js-call-reducer.h" |
6 | 6 |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
| 10 #include "src/compiler/access-builder.h" |
10 #include "src/compiler/js-graph.h" | 11 #include "src/compiler/js-graph.h" |
11 #include "src/compiler/linkage.h" | 12 #include "src/compiler/linkage.h" |
12 #include "src/compiler/node-matchers.h" | 13 #include "src/compiler/node-matchers.h" |
13 #include "src/compiler/simplified-operator.h" | 14 #include "src/compiler/simplified-operator.h" |
14 #include "src/feedback-vector-inl.h" | 15 #include "src/feedback-vector-inl.h" |
15 #include "src/ic/call-optimization.h" | 16 #include "src/ic/call-optimization.h" |
16 #include "src/objects-inl.h" | 17 #include "src/objects-inl.h" |
17 | 18 |
18 namespace v8 { | 19 namespace v8 { |
19 namespace internal { | 20 namespace internal { |
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 | 344 |
344 // ES6 section 26.1.7 Reflect.getPrototypeOf ( target ) | 345 // ES6 section 26.1.7 Reflect.getPrototypeOf ( target ) |
345 Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) { | 346 Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) { |
346 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); | 347 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); |
347 Node* target = (node->op()->ValueInputCount() >= 3) | 348 Node* target = (node->op()->ValueInputCount() >= 3) |
348 ? NodeProperties::GetValueInput(node, 2) | 349 ? NodeProperties::GetValueInput(node, 2) |
349 : jsgraph()->UndefinedConstant(); | 350 : jsgraph()->UndefinedConstant(); |
350 return ReduceObjectGetPrototype(node, target); | 351 return ReduceObjectGetPrototype(node, target); |
351 } | 352 } |
352 | 353 |
| 354 Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function, |
| 355 Node* node) { |
| 356 if (!FLAG_turbo_inline_array_builtins) return NoChange(); |
| 357 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); |
| 358 Node* outer_frame_state = NodeProperties::GetFrameStateInput(node); |
| 359 Node* effect = NodeProperties::GetEffectInput(node); |
| 360 Node* control = NodeProperties::GetControlInput(node); |
| 361 Node* context = NodeProperties::GetContextInput(node); |
| 362 CallParameters const& p = CallParametersOf(node->op()); |
| 363 |
| 364 // Try to determine the {receiver} map. |
| 365 Node* receiver = NodeProperties::GetValueInput(node, 1); |
| 366 Node* fncallback = node->op()->ValueInputCount() > 2 |
| 367 ? NodeProperties::GetValueInput(node, 2) |
| 368 : jsgraph()->UndefinedConstant(); |
| 369 Node* this_arg = node->op()->ValueInputCount() > 3 |
| 370 ? NodeProperties::GetValueInput(node, 3) |
| 371 : jsgraph()->UndefinedConstant(); |
| 372 ZoneHandleSet<Map> receiver_maps; |
| 373 NodeProperties::InferReceiverMapsResult result = |
| 374 NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps); |
| 375 if (result != NodeProperties::kReliableReceiverMaps) { |
| 376 return NoChange(); |
| 377 } |
| 378 if (receiver_maps.size() != 1) return NoChange(); |
| 379 Handle<Map> receiver_map(receiver_maps[0]); |
| 380 ElementsKind kind = receiver_map->elements_kind(); |
| 381 // TODO(danno): Handle holey Smi and Object fast elements kinds and double |
| 382 // packed. |
| 383 if (!IsFastPackedElementsKind(kind) || IsFastDoubleElementsKind(kind)) { |
| 384 return NoChange(); |
| 385 } |
| 386 |
| 387 // TODO(danno): forEach can throw. Hook up exceptional edges. |
| 388 if (NodeProperties::IsExceptionalCall(node)) return NoChange(); |
| 389 |
| 390 Node* k = jsgraph()->ZeroConstant(); |
| 391 |
| 392 Node* original_length = graph()->NewNode( |
| 393 simplified()->LoadField(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS)), |
| 394 receiver, effect, control); |
| 395 |
| 396 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control); |
| 397 Node* eloop = effect = |
| 398 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); |
| 399 Node* vloop = k = graph()->NewNode( |
| 400 common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop); |
| 401 |
| 402 control = loop; |
| 403 effect = eloop; |
| 404 |
| 405 Node* continue_test = |
| 406 graph()->NewNode(simplified()->NumberLessThan(), k, original_length); |
| 407 Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
| 408 continue_test, control); |
| 409 |
| 410 Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch); |
| 411 Node* if_false = graph()->NewNode(common()->IfFalse(), continue_branch); |
| 412 control = if_true; |
| 413 |
| 414 std::vector<Node*> checkpoint_params( |
| 415 {receiver, fncallback, this_arg, k, original_length}); |
| 416 const int stack_parameters = static_cast<int>(checkpoint_params.size()); |
| 417 |
| 418 Node* frame_state = CreateJavaScriptBuiltinContinuationFrameState( |
| 419 jsgraph(), function, Builtins::kArrayForEachLoopEagerDeoptContinuation, |
| 420 node->InputAt(0), context, &checkpoint_params[0], stack_parameters, |
| 421 outer_frame_state, ContinuationFrameStateMode::EAGER); |
| 422 |
| 423 effect = |
| 424 graph()->NewNode(common()->Checkpoint(), frame_state, effect, control); |
| 425 |
| 426 // Make sure the map hasn't changed during the iteration |
| 427 Node* orig_map = jsgraph()->HeapConstant(receiver_map); |
| 428 Node* array_map = effect = |
| 429 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 430 receiver, effect, control); |
| 431 Node* check_map = |
| 432 graph()->NewNode(simplified()->ReferenceEqual(), array_map, orig_map); |
| 433 effect = |
| 434 graph()->NewNode(simplified()->CheckIf(), check_map, effect, control); |
| 435 |
| 436 // Make sure that the access is still in bounds, since the callback could have |
| 437 // changed the array's size. |
| 438 Node* length = graph()->NewNode( |
| 439 simplified()->LoadField(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS)), |
| 440 receiver, effect, control); |
| 441 k = effect = |
| 442 graph()->NewNode(simplified()->CheckBounds(), k, length, effect, control); |
| 443 |
| 444 // Reload the elements pointer before calling the callback, since the previous |
| 445 // callback might have resized the array causing the elements buffer to be |
| 446 // re-allocated. |
| 447 Node* elements = graph()->NewNode( |
| 448 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, |
| 449 effect, control); |
| 450 |
| 451 Node* element = graph()->NewNode( |
| 452 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), |
| 453 elements, k, effect, control); |
| 454 |
| 455 Node* next_k = |
| 456 graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->Constant(1)); |
| 457 checkpoint_params[3] = next_k; |
| 458 frame_state = CreateJavaScriptBuiltinContinuationFrameState( |
| 459 jsgraph(), function, Builtins::kArrayForEachLoopLazyDeoptContinuation, |
| 460 node->InputAt(0), context, &checkpoint_params[0], stack_parameters, |
| 461 outer_frame_state, ContinuationFrameStateMode::LAZY); |
| 462 |
| 463 control = effect = graph()->NewNode( |
| 464 javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k, |
| 465 receiver, context, frame_state, effect, control); |
| 466 |
| 467 k = next_k; |
| 468 |
| 469 loop->ReplaceInput(1, control); |
| 470 vloop->ReplaceInput(1, k); |
| 471 eloop->ReplaceInput(1, effect); |
| 472 |
| 473 control = if_false; |
| 474 effect = eloop; |
| 475 |
| 476 ReplaceWithValue(node, jsgraph()->UndefinedConstant(), effect, control); |
| 477 return Replace(jsgraph()->UndefinedConstant()); |
| 478 } |
| 479 |
353 Reduction JSCallReducer::ReduceCallApiFunction( | 480 Reduction JSCallReducer::ReduceCallApiFunction( |
354 Node* node, Handle<FunctionTemplateInfo> function_template_info) { | 481 Node* node, Handle<FunctionTemplateInfo> function_template_info) { |
355 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); | 482 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); |
356 CallParameters const& p = CallParametersOf(node->op()); | 483 CallParameters const& p = CallParametersOf(node->op()); |
357 int const argc = static_cast<int>(p.arity()) - 2; | 484 int const argc = static_cast<int>(p.arity()) - 2; |
358 Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined) | 485 Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined) |
359 ? jsgraph()->HeapConstant(global_proxy()) | 486 ? jsgraph()->HeapConstant(global_proxy()) |
360 : NodeProperties::GetValueInput(node, 1); | 487 : NodeProperties::GetValueInput(node, 1); |
361 Node* effect = NodeProperties::GetEffectInput(node); | 488 Node* effect = NodeProperties::GetEffectInput(node); |
362 | 489 |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
609 case Builtins::kFunctionPrototypeHasInstance: | 736 case Builtins::kFunctionPrototypeHasInstance: |
610 return ReduceFunctionPrototypeHasInstance(node); | 737 return ReduceFunctionPrototypeHasInstance(node); |
611 case Builtins::kNumberConstructor: | 738 case Builtins::kNumberConstructor: |
612 return ReduceNumberConstructor(node); | 739 return ReduceNumberConstructor(node); |
613 case Builtins::kObjectGetPrototypeOf: | 740 case Builtins::kObjectGetPrototypeOf: |
614 return ReduceObjectGetPrototypeOf(node); | 741 return ReduceObjectGetPrototypeOf(node); |
615 case Builtins::kObjectPrototypeGetProto: | 742 case Builtins::kObjectPrototypeGetProto: |
616 return ReduceObjectPrototypeGetProto(node); | 743 return ReduceObjectPrototypeGetProto(node); |
617 case Builtins::kReflectGetPrototypeOf: | 744 case Builtins::kReflectGetPrototypeOf: |
618 return ReduceReflectGetPrototypeOf(node); | 745 return ReduceReflectGetPrototypeOf(node); |
| 746 case Builtins::kArrayForEach: |
| 747 return ReduceArrayForEach(function, node); |
619 default: | 748 default: |
620 break; | 749 break; |
621 } | 750 } |
622 | 751 |
623 // Check for the Array constructor. | 752 // Check for the Array constructor. |
624 if (*function == function->native_context()->array_function()) { | 753 if (*function == function->native_context()->array_function()) { |
625 return ReduceArrayConstructor(node); | 754 return ReduceArrayConstructor(node); |
626 } | 755 } |
627 | 756 |
628 if (!FLAG_runtime_stats && shared->IsApiFunction()) { | 757 if (!FLAG_runtime_stats && shared->IsApiFunction()) { |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
892 return jsgraph()->javascript(); | 1021 return jsgraph()->javascript(); |
893 } | 1022 } |
894 | 1023 |
895 SimplifiedOperatorBuilder* JSCallReducer::simplified() const { | 1024 SimplifiedOperatorBuilder* JSCallReducer::simplified() const { |
896 return jsgraph()->simplified(); | 1025 return jsgraph()->simplified(); |
897 } | 1026 } |
898 | 1027 |
899 } // namespace compiler | 1028 } // namespace compiler |
900 } // namespace internal | 1029 } // namespace internal |
901 } // namespace v8 | 1030 } // namespace v8 |
OLD | NEW |