1 // Copyright 2019 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/map-inference.h"
6
7 #include "src/compiler/compilation-dependencies.h"
8 #include "src/compiler/feedback-source.h"
9 #include "src/compiler/js-graph.h"
10 #include "src/compiler/simplified-operator.h"
11 #include "src/objects/map-inl.h"
12 #include "src/zone/zone-handle-set.h"
13
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17
MapInference(JSHeapBroker * broker,Node * object,Node * effect)18 MapInference::MapInference(JSHeapBroker* broker, Node* object, Node* effect)
19 : broker_(broker), object_(object) {
20 ZoneHandleSet<Map> maps;
21 auto result =
22 NodeProperties::InferMapsUnsafe(broker_, object_, effect, &maps);
23 maps_.insert(maps_.end(), maps.begin(), maps.end());
24 maps_state_ = (result == NodeProperties::kUnreliableMaps)
25 ? kUnreliableDontNeedGuard
26 : kReliableOrGuarded;
27 DCHECK_EQ(maps_.empty(), result == NodeProperties::kNoMaps);
28 }
29
~MapInference()30 MapInference::~MapInference() { CHECK(Safe()); }
31
Safe() const32 bool MapInference::Safe() const { return maps_state_ != kUnreliableNeedGuard; }
33
SetNeedGuardIfUnreliable()34 void MapInference::SetNeedGuardIfUnreliable() {
35 CHECK(HaveMaps());
36 if (maps_state_ == kUnreliableDontNeedGuard) {
37 maps_state_ = kUnreliableNeedGuard;
38 }
39 }
40
SetGuarded()41 void MapInference::SetGuarded() { maps_state_ = kReliableOrGuarded; }
42
HaveMaps() const43 bool MapInference::HaveMaps() const { return !maps_.empty(); }
44
AllOfInstanceTypesAreJSReceiver() const45 bool MapInference::AllOfInstanceTypesAreJSReceiver() const {
46 return AllOfInstanceTypesUnsafe(InstanceTypeChecker::IsJSReceiver);
47 }
48
AllOfInstanceTypesAre(InstanceType type) const49 bool MapInference::AllOfInstanceTypesAre(InstanceType type) const {
50 CHECK(!InstanceTypeChecker::IsString(type));
51 return AllOfInstanceTypesUnsafe(
52 [type](InstanceType other) { return type == other; });
53 }
54
AnyOfInstanceTypesAre(InstanceType type) const55 bool MapInference::AnyOfInstanceTypesAre(InstanceType type) const {
56 CHECK(!InstanceTypeChecker::IsString(type));
57 return AnyOfInstanceTypesUnsafe(
58 [type](InstanceType other) { return type == other; });
59 }
60
AllOfInstanceTypes(std::function<bool (InstanceType)> f)61 bool MapInference::AllOfInstanceTypes(std::function<bool(InstanceType)> f) {
62 SetNeedGuardIfUnreliable();
63 return AllOfInstanceTypesUnsafe(f);
64 }
65
AllOfInstanceTypesUnsafe(std::function<bool (InstanceType)> f) const66 bool MapInference::AllOfInstanceTypesUnsafe(
67 std::function<bool(InstanceType)> f) const {
68 CHECK(HaveMaps());
69
70 auto instance_type = [this, f](Handle<Map> map) {
71 MapRef map_ref(broker_, map);
72 return f(map_ref.instance_type());
73 };
74 return std::all_of(maps_.begin(), maps_.end(), instance_type);
75 }
76
AnyOfInstanceTypesUnsafe(std::function<bool (InstanceType)> f) const77 bool MapInference::AnyOfInstanceTypesUnsafe(
78 std::function<bool(InstanceType)> f) const {
79 CHECK(HaveMaps());
80
81 auto instance_type = [this, f](Handle<Map> map) {
82 MapRef map_ref(broker_, map);
83 return f(map_ref.instance_type());
84 };
85
86 return std::any_of(maps_.begin(), maps_.end(), instance_type);
87 }
88
GetMaps()89 MapHandles const& MapInference::GetMaps() {
90 SetNeedGuardIfUnreliable();
91 return maps_;
92 }
93
Is(Handle<Map> expected_map)94 bool MapInference::Is(Handle<Map> expected_map) {
95 if (!HaveMaps()) return false;
96 const MapHandles& maps = GetMaps();
97 if (maps.size() != 1) return false;
98 return maps[0].equals(expected_map);
99 }
100
InsertMapChecks(JSGraph * jsgraph,Effect * effect,Control control,const FeedbackSource & feedback)101 void MapInference::InsertMapChecks(JSGraph* jsgraph, Effect* effect,
102 Control control,
103 const FeedbackSource& feedback) {
104 CHECK(HaveMaps());
105 CHECK(feedback.IsValid());
106 ZoneHandleSet<Map> maps;
107 for (Handle<Map> map : maps_) maps.insert(map, jsgraph->graph()->zone());
108 *effect = jsgraph->graph()->NewNode(
109 jsgraph->simplified()->CheckMaps(CheckMapsFlag::kNone, maps, feedback),
110 object_, *effect, control);
111 SetGuarded();
112 }
113
RelyOnMapsViaStability(CompilationDependencies * dependencies)114 bool MapInference::RelyOnMapsViaStability(
115 CompilationDependencies* dependencies) {
116 CHECK(HaveMaps());
117 return RelyOnMapsHelper(dependencies, nullptr, nullptr, Control{nullptr}, {});
118 }
119
RelyOnMapsPreferStability(CompilationDependencies * dependencies,JSGraph * jsgraph,Effect * effect,Control control,const FeedbackSource & feedback)120 bool MapInference::RelyOnMapsPreferStability(
121 CompilationDependencies* dependencies, JSGraph* jsgraph, Effect* effect,
122 Control control, const FeedbackSource& feedback) {
123 CHECK(HaveMaps());
124 if (Safe()) return false;
125 if (RelyOnMapsViaStability(dependencies)) return true;
126 CHECK(RelyOnMapsHelper(nullptr, jsgraph, effect, control, feedback));
127 return false;
128 }
129
RelyOnMapsHelper(CompilationDependencies * dependencies,JSGraph * jsgraph,Effect * effect,Control control,const FeedbackSource & feedback)130 bool MapInference::RelyOnMapsHelper(CompilationDependencies* dependencies,
131 JSGraph* jsgraph, Effect* effect,
132 Control control,
133 const FeedbackSource& feedback) {
134 if (Safe()) return true;
135
136 auto is_stable = [this](Handle<Map> map) {
137 MapRef map_ref(broker_, map);
138 return map_ref.is_stable();
139 };
140 if (dependencies != nullptr &&
141 std::all_of(maps_.cbegin(), maps_.cend(), is_stable)) {
142 for (Handle<Map> map : maps_) {
143 dependencies->DependOnStableMap(MapRef(broker_, map));
144 }
145 SetGuarded();
146 return true;
147 } else if (feedback.IsValid()) {
148 InsertMapChecks(jsgraph, effect, control, feedback);
149 return true;
150 } else {
151 return false;
152 }
153 }
154
NoChange()155 Reduction MapInference::NoChange() {
156 SetGuarded();
157 maps_.clear(); // Just to make some CHECKs fail if {this} gets used after.
158 return Reducer::NoChange();
159 }
160
161 } // namespace compiler
162 } // namespace internal
163 } // namespace v8
164