• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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