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
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16
MapInference(JSHeapBroker * broker,Node * object,Effect effect)17 MapInference::MapInference(JSHeapBroker* broker, Node* object, Effect effect)
18 : broker_(broker), object_(object), maps_(broker->zone()) {
19 ZoneRefUnorderedSet<MapRef> maps(broker->zone());
20 auto result =
21 NodeProperties::InferMapsUnsafe(broker_, object_, effect, &maps);
22 maps_.insert(maps_.end(), maps.begin(), maps.end());
23 maps_state_ = (result == NodeProperties::kUnreliableMaps)
24 ? kUnreliableDontNeedGuard
25 : kReliableOrGuarded;
26 DCHECK_EQ(maps_.empty(), result == NodeProperties::kNoMaps);
27 }
28
~MapInference()29 MapInference::~MapInference() { CHECK(Safe()); }
30
Safe() const31 bool MapInference::Safe() const { return maps_state_ != kUnreliableNeedGuard; }
32
SetNeedGuardIfUnreliable()33 void MapInference::SetNeedGuardIfUnreliable() {
34 CHECK(HaveMaps());
35 if (maps_state_ == kUnreliableDontNeedGuard) {
36 maps_state_ = kUnreliableNeedGuard;
37 }
38 }
39
SetGuarded()40 void MapInference::SetGuarded() { maps_state_ = kReliableOrGuarded; }
41
HaveMaps() const42 bool MapInference::HaveMaps() const { return !maps_.empty(); }
43
AllOfInstanceTypesAreJSReceiver() const44 bool MapInference::AllOfInstanceTypesAreJSReceiver() const {
45 return AllOfInstanceTypesUnsafe(InstanceTypeChecker::IsJSReceiver);
46 }
47
AllOfInstanceTypesAre(InstanceType type) const48 bool MapInference::AllOfInstanceTypesAre(InstanceType type) const {
49 CHECK(!InstanceTypeChecker::IsString(type));
50 return AllOfInstanceTypesUnsafe(
51 [type](InstanceType other) { return type == other; });
52 }
53
AnyOfInstanceTypesAre(InstanceType type) const54 bool MapInference::AnyOfInstanceTypesAre(InstanceType type) const {
55 CHECK(!InstanceTypeChecker::IsString(type));
56 return AnyOfInstanceTypesUnsafe(
57 [type](InstanceType other) { return type == other; });
58 }
59
AllOfInstanceTypes(std::function<bool (InstanceType)> f)60 bool MapInference::AllOfInstanceTypes(std::function<bool(InstanceType)> f) {
61 SetNeedGuardIfUnreliable();
62 return AllOfInstanceTypesUnsafe(f);
63 }
64
AllOfInstanceTypesUnsafe(std::function<bool (InstanceType)> f) const65 bool MapInference::AllOfInstanceTypesUnsafe(
66 std::function<bool(InstanceType)> f) const {
67 CHECK(HaveMaps());
68
69 auto instance_type = [f](const MapRef& map) {
70 return f(map.instance_type());
71 };
72 return std::all_of(maps_.begin(), maps_.end(), instance_type);
73 }
74
AnyOfInstanceTypesUnsafe(std::function<bool (InstanceType)> f) const75 bool MapInference::AnyOfInstanceTypesUnsafe(
76 std::function<bool(InstanceType)> f) const {
77 CHECK(HaveMaps());
78
79 auto instance_type = [f](const MapRef& map) {
80 return f(map.instance_type());
81 };
82
83 return std::any_of(maps_.begin(), maps_.end(), instance_type);
84 }
85
GetMaps()86 ZoneVector<MapRef> const& MapInference::GetMaps() {
87 SetNeedGuardIfUnreliable();
88 return maps_;
89 }
90
Is(const MapRef & expected_map)91 bool MapInference::Is(const MapRef& expected_map) {
92 if (!HaveMaps()) return false;
93 const ZoneVector<MapRef>& maps = GetMaps();
94 if (maps.size() != 1) return false;
95 return maps[0].equals(expected_map);
96 }
97
InsertMapChecks(JSGraph * jsgraph,Effect * effect,Control control,const FeedbackSource & feedback)98 void MapInference::InsertMapChecks(JSGraph* jsgraph, Effect* effect,
99 Control control,
100 const FeedbackSource& feedback) {
101 CHECK(HaveMaps());
102 CHECK(feedback.IsValid());
103 ZoneHandleSet<Map> maps;
104 for (const MapRef& map : maps_) {
105 maps.insert(map.object(), jsgraph->graph()->zone());
106 }
107 *effect = jsgraph->graph()->NewNode(
108 jsgraph->simplified()->CheckMaps(CheckMapsFlag::kNone, maps, feedback),
109 object_, *effect, control);
110 SetGuarded();
111 }
112
RelyOnMapsViaStability(CompilationDependencies * dependencies)113 bool MapInference::RelyOnMapsViaStability(
114 CompilationDependencies* dependencies) {
115 CHECK(HaveMaps());
116 return RelyOnMapsHelper(dependencies, nullptr, nullptr, Control{nullptr}, {});
117 }
118
RelyOnMapsPreferStability(CompilationDependencies * dependencies,JSGraph * jsgraph,Effect * effect,Control control,const FeedbackSource & feedback)119 bool MapInference::RelyOnMapsPreferStability(
120 CompilationDependencies* dependencies, JSGraph* jsgraph, Effect* effect,
121 Control control, const FeedbackSource& feedback) {
122 CHECK(HaveMaps());
123 if (Safe()) return false;
124 if (RelyOnMapsViaStability(dependencies)) return true;
125 CHECK(RelyOnMapsHelper(nullptr, jsgraph, effect, control, feedback));
126 return false;
127 }
128
RelyOnMapsHelper(CompilationDependencies * dependencies,JSGraph * jsgraph,Effect * effect,Control control,const FeedbackSource & feedback)129 bool MapInference::RelyOnMapsHelper(CompilationDependencies* dependencies,
130 JSGraph* jsgraph, Effect* effect,
131 Control control,
132 const FeedbackSource& feedback) {
133 if (Safe()) return true;
134
135 auto is_stable = [](const MapRef& map) { return map.is_stable(); };
136 if (dependencies != nullptr &&
137 std::all_of(maps_.cbegin(), maps_.cend(), is_stable)) {
138 for (const MapRef& map : maps_) {
139 dependencies->DependOnStableMap(map);
140 }
141 SetGuarded();
142 return true;
143 } else if (feedback.IsValid()) {
144 InsertMapChecks(jsgraph, effect, control, feedback);
145 return true;
146 } else {
147 return false;
148 }
149 }
150
NoChange()151 Reduction MapInference::NoChange() {
152 SetGuarded();
153 maps_.clear(); // Just to make some CHECKs fail if {this} gets used after.
154 return Reducer::NoChange();
155 }
156
157 } // namespace compiler
158 } // namespace internal
159 } // namespace v8
160