• 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 
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