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-native-context-specialization.h" | 5 #include "src/compiler/js-native-context-specialization.h" |
6 | 6 |
7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
10 #include "src/compiler/access-builder.h" | 10 #include "src/compiler/access-builder.h" |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 case IrOpcode::kJSCallFunction: | 50 case IrOpcode::kJSCallFunction: |
51 return ReduceJSCallFunction(node); | 51 return ReduceJSCallFunction(node); |
52 case IrOpcode::kJSLoadGlobal: | 52 case IrOpcode::kJSLoadGlobal: |
53 return ReduceJSLoadGlobal(node); | 53 return ReduceJSLoadGlobal(node); |
54 case IrOpcode::kJSStoreGlobal: | 54 case IrOpcode::kJSStoreGlobal: |
55 return ReduceJSStoreGlobal(node); | 55 return ReduceJSStoreGlobal(node); |
56 case IrOpcode::kJSLoadNamed: | 56 case IrOpcode::kJSLoadNamed: |
57 return ReduceJSLoadNamed(node); | 57 return ReduceJSLoadNamed(node); |
58 case IrOpcode::kJSStoreNamed: | 58 case IrOpcode::kJSStoreNamed: |
59 return ReduceJSStoreNamed(node); | 59 return ReduceJSStoreNamed(node); |
| 60 case IrOpcode::kJSLoadProperty: |
| 61 return ReduceJSLoadProperty(node); |
| 62 case IrOpcode::kJSStoreProperty: |
| 63 return ReduceJSStoreProperty(node); |
60 default: | 64 default: |
61 break; | 65 break; |
62 } | 66 } |
63 return NoChange(); | 67 return NoChange(); |
64 } | 68 } |
65 | 69 |
66 | 70 |
67 Reduction JSNativeContextSpecialization::ReduceJSCallFunction(Node* node) { | 71 Reduction JSNativeContextSpecialization::ReduceJSCallFunction(Node* node) { |
68 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); | 72 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); |
69 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); | 73 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 effect = graph()->NewNode( | 301 effect = graph()->NewNode( |
298 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), | 302 simplified()->StoreField(AccessBuilder::ForPropertyCellValue()), |
299 jsgraph()->Constant(property_cell), value, effect, control); | 303 jsgraph()->Constant(property_cell), value, effect, control); |
300 return Replace(node, value, effect, control); | 304 return Replace(node, value, effect, control); |
301 } | 305 } |
302 | 306 |
303 | 307 |
304 Reduction JSNativeContextSpecialization::ReduceNamedAccess( | 308 Reduction JSNativeContextSpecialization::ReduceNamedAccess( |
305 Node* node, Node* value, MapHandleList const& receiver_maps, | 309 Node* node, Node* value, MapHandleList const& receiver_maps, |
306 Handle<Name> name, PropertyAccessMode access_mode, | 310 Handle<Name> name, PropertyAccessMode access_mode, |
307 LanguageMode language_mode) { | 311 LanguageMode language_mode, Node* index) { |
308 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || | 312 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || |
309 node->opcode() == IrOpcode::kJSStoreNamed); | 313 node->opcode() == IrOpcode::kJSStoreNamed || |
| 314 node->opcode() == IrOpcode::kJSLoadProperty || |
| 315 node->opcode() == IrOpcode::kJSStoreProperty); |
310 Node* receiver = NodeProperties::GetValueInput(node, 0); | 316 Node* receiver = NodeProperties::GetValueInput(node, 0); |
311 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); | 317 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); |
312 Node* effect = NodeProperties::GetEffectInput(node); | 318 Node* effect = NodeProperties::GetEffectInput(node); |
313 Node* control = NodeProperties::GetControlInput(node); | 319 Node* control = NodeProperties::GetControlInput(node); |
314 | 320 |
315 // Not much we can do if deoptimization support is disabled. | 321 // Not much we can do if deoptimization support is disabled. |
316 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | 322 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
317 | 323 |
318 // Compute property access infos for the receiver maps. | 324 // Compute property access infos for the receiver maps. |
319 ZoneVector<PropertyAccessInfo> access_infos(zone()); | 325 ZoneVector<PropertyAccessInfo> access_infos(zone()); |
320 if (!access_info_factory().ComputePropertyAccessInfos( | 326 if (!access_info_factory().ComputePropertyAccessInfos( |
321 receiver_maps, name, access_mode, &access_infos)) { | 327 receiver_maps, name, access_mode, &access_infos)) { |
322 return NoChange(); | 328 return NoChange(); |
323 } | 329 } |
324 | 330 |
325 // Nothing to do if we have no non-deprecated maps. | 331 // Nothing to do if we have no non-deprecated maps. |
326 if (access_infos.empty()) return NoChange(); | 332 if (access_infos.empty()) return NoChange(); |
327 | 333 |
328 // The final states for every polymorphic branch. We join them with | 334 // The final states for every polymorphic branch. We join them with |
329 // Merge++Phi+EffectPhi at the bottom. | 335 // Merge++Phi+EffectPhi at the bottom. |
330 ZoneVector<Node*> values(zone()); | 336 ZoneVector<Node*> values(zone()); |
331 ZoneVector<Node*> effects(zone()); | 337 ZoneVector<Node*> effects(zone()); |
332 ZoneVector<Node*> controls(zone()); | 338 ZoneVector<Node*> controls(zone()); |
333 | 339 |
334 // The list of "exiting" controls, which currently go to a single deoptimize. | 340 // The list of "exiting" controls, which currently go to a single deoptimize. |
335 // TODO(bmeurer): Consider using an IC as fallback. | 341 // TODO(bmeurer): Consider using an IC as fallback. |
336 Node* const exit_effect = effect; | 342 Node* const exit_effect = effect; |
337 ZoneVector<Node*> exit_controls(zone()); | 343 ZoneVector<Node*> exit_controls(zone()); |
338 | 344 |
| 345 // Ensure that {index} matches the specified {name} (if {index} is given). |
| 346 if (index != nullptr) { |
| 347 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), |
| 348 index, jsgraph()->HeapConstant(name)); |
| 349 Node* branch = |
| 350 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 351 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch)); |
| 352 control = graph()->NewNode(common()->IfTrue(), branch); |
| 353 } |
| 354 |
339 // Ensure that {receiver} is a heap object. | 355 // Ensure that {receiver} is a heap object. |
340 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); | 356 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); |
341 Node* branch = | 357 Node* branch = |
342 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); | 358 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); |
343 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); | 359 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); |
344 control = graph()->NewNode(common()->IfFalse(), branch); | 360 control = graph()->NewNode(common()->IfFalse(), branch); |
345 | 361 |
346 // Load the {receiver} map. The resulting effect is the dominating effect for | 362 // Load the {receiver} map. The resulting effect is the dominating effect for |
347 // all (polymorphic) branches. | 363 // all (polymorphic) branches. |
348 Node* receiver_map = effect = | 364 Node* receiver_map = effect = |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
646 StoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); | 662 StoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); |
647 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); | 663 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); |
648 DCHECK_LT(0, receiver_maps.length()); | 664 DCHECK_LT(0, receiver_maps.length()); |
649 | 665 |
650 // Try to lower the named access based on the {receiver_maps}. | 666 // Try to lower the named access based on the {receiver_maps}. |
651 return ReduceNamedAccess(node, value, receiver_maps, p.name(), | 667 return ReduceNamedAccess(node, value, receiver_maps, p.name(), |
652 PropertyAccessMode::kStore, p.language_mode()); | 668 PropertyAccessMode::kStore, p.language_mode()); |
653 } | 669 } |
654 | 670 |
655 | 671 |
| 672 Reduction JSNativeContextSpecialization::ReduceKeyedAccess( |
| 673 Node* node, Node* index, Node* value, FeedbackNexus const& nexus, |
| 674 PropertyAccessMode access_mode, LanguageMode language_mode) { |
| 675 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || |
| 676 node->opcode() == IrOpcode::kJSStoreProperty); |
| 677 |
| 678 // Extract receiver maps from the {nexus}. |
| 679 MapHandleList receiver_maps; |
| 680 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); |
| 681 DCHECK_LT(0, receiver_maps.length()); |
| 682 |
| 683 // Optimize access for constant {index}. |
| 684 HeapObjectMatcher mindex(index); |
| 685 if (mindex.HasValue() && mindex.Value()->IsPrimitive()) { |
| 686 // Keyed access requires a ToPropertyKey on the {index} first before |
| 687 // looking up the property on the object (see ES6 section 12.3.2.1). |
| 688 // We can only do this for non-observable ToPropertyKey invocations, |
| 689 // so we limit the constant indices to primitives at this point. |
| 690 Handle<Name> name; |
| 691 if (Object::ToName(isolate(), mindex.Value()).ToHandle(&name)) { |
| 692 uint32_t array_index; |
| 693 if (name->AsArrayIndex(&array_index)) { |
| 694 // TODO(bmeurer): Optimize element access with constant {index}. |
| 695 } else { |
| 696 name = factory()->InternalizeName(name); |
| 697 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode, |
| 698 language_mode); |
| 699 } |
| 700 } |
| 701 } |
| 702 |
| 703 // Check if we have feedback for a named access. |
| 704 if (Name* name = nexus.FindFirstName()) { |
| 705 return ReduceNamedAccess(node, value, receiver_maps, |
| 706 handle(name, isolate()), access_mode, |
| 707 language_mode, index); |
| 708 } |
| 709 |
| 710 return NoChange(); |
| 711 } |
| 712 |
| 713 |
| 714 Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) { |
| 715 DCHECK_EQ(IrOpcode::kJSLoadProperty, node->opcode()); |
| 716 PropertyAccess const& p = PropertyAccessOf(node->op()); |
| 717 Node* const index = NodeProperties::GetValueInput(node, 1); |
| 718 Node* const value = jsgraph()->Dead(); |
| 719 |
| 720 // Extract receiver maps from the KEYED_LOAD_IC using the KeyedLoadICNexus. |
| 721 if (!p.feedback().IsValid()) return NoChange(); |
| 722 KeyedLoadICNexus nexus(p.feedback().vector(), p.feedback().slot()); |
| 723 |
| 724 // Try to lower the keyed access based on the {nexus}. |
| 725 return ReduceKeyedAccess(node, index, value, nexus, PropertyAccessMode::kLoad, |
| 726 p.language_mode()); |
| 727 } |
| 728 |
| 729 |
| 730 Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) { |
| 731 DCHECK_EQ(IrOpcode::kJSStoreProperty, node->opcode()); |
| 732 PropertyAccess const& p = PropertyAccessOf(node->op()); |
| 733 Node* const index = NodeProperties::GetValueInput(node, 1); |
| 734 Node* const value = NodeProperties::GetValueInput(node, 2); |
| 735 |
| 736 // Extract receiver maps from the KEYED_STORE_IC using the KeyedStoreICNexus. |
| 737 if (!p.feedback().IsValid()) return NoChange(); |
| 738 KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); |
| 739 |
| 740 // Try to lower the keyed access based on the {nexus}. |
| 741 return ReduceKeyedAccess(node, index, value, nexus, |
| 742 PropertyAccessMode::kStore, p.language_mode()); |
| 743 } |
| 744 |
| 745 |
656 Reduction JSNativeContextSpecialization::Replace(Node* node, | 746 Reduction JSNativeContextSpecialization::Replace(Node* node, |
657 Handle<Object> value) { | 747 Handle<Object> value) { |
658 return Replace(node, jsgraph()->Constant(value)); | 748 return Replace(node, jsgraph()->Constant(value)); |
659 } | 749 } |
660 | 750 |
661 | 751 |
662 bool JSNativeContextSpecialization::LookupInScriptContextTable( | 752 bool JSNativeContextSpecialization::LookupInScriptContextTable( |
663 Handle<Name> name, ScriptContextTableLookupResult* result) { | 753 Handle<Name> name, ScriptContextTableLookupResult* result) { |
664 if (!name->IsString()) return false; | 754 if (!name->IsString()) return false; |
665 Handle<ScriptContextTable> script_context_table( | 755 Handle<ScriptContextTable> script_context_table( |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
734 } | 824 } |
735 | 825 |
736 | 826 |
737 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 827 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
738 return jsgraph()->simplified(); | 828 return jsgraph()->simplified(); |
739 } | 829 } |
740 | 830 |
741 } // namespace compiler | 831 } // namespace compiler |
742 } // namespace internal | 832 } // namespace internal |
743 } // namespace v8 | 833 } // namespace v8 |
OLD | NEW |