• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #ifndef V8_COMPILER_ACCESS_INFO_H_
6 #define V8_COMPILER_ACCESS_INFO_H_
7 
8 #include "src/compiler/heap-refs.h"
9 #include "src/compiler/types.h"
10 #include "src/zone/zone-containers.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 // Forward declarations.
16 class Factory;
17 
18 namespace compiler {
19 
20 // Forward declarations.
21 class CompilationDependencies;
22 class CompilationDependency;
23 class ElementAccessFeedback;
24 class JSHeapBroker;
25 class TypeCache;
26 struct ConstFieldInfo;
27 
28 std::ostream& operator<<(std::ostream&, AccessMode);
29 
30 // This class encapsulates all information required to access a certain element.
31 class ElementAccessInfo final {
32  public:
33   ElementAccessInfo(ZoneVector<MapRef>&& lookup_start_object_maps,
34                     ElementsKind elements_kind, Zone* zone);
35 
elements_kind()36   ElementsKind elements_kind() const { return elements_kind_; }
lookup_start_object_maps()37   ZoneVector<MapRef> const& lookup_start_object_maps() const {
38     return lookup_start_object_maps_;
39   }
transition_sources()40   ZoneVector<MapRef> const& transition_sources() const {
41     return transition_sources_;
42   }
43 
AddTransitionSource(MapRef map)44   void AddTransitionSource(MapRef map) {
45     CHECK_EQ(lookup_start_object_maps_.size(), 1);
46     transition_sources_.push_back(map);
47   }
48 
49  private:
50   ElementsKind elements_kind_;
51   ZoneVector<MapRef> lookup_start_object_maps_;
52   ZoneVector<MapRef> transition_sources_;
53 };
54 
55 // This class encapsulates all information required to access a certain
56 // object property, either on the object itself or on the prototype chain.
57 class PropertyAccessInfo final {
58  public:
59   enum Kind {
60     kInvalid,
61     kNotFound,
62     kDataField,
63     kFastDataConstant,
64     kDictionaryProtoDataConstant,
65     kFastAccessorConstant,
66     kDictionaryProtoAccessorConstant,
67     kModuleExport,
68     kStringLength
69   };
70 
71   static PropertyAccessInfo NotFound(Zone* zone, MapRef receiver_map,
72                                      base::Optional<JSObjectRef> holder);
73   static PropertyAccessInfo DataField(
74       Zone* zone, MapRef receiver_map,
75       ZoneVector<CompilationDependency const*>&& unrecorded_dependencies,
76       FieldIndex field_index, Representation field_representation,
77       Type field_type, MapRef field_owner_map, base::Optional<MapRef> field_map,
78       base::Optional<JSObjectRef> holder,
79       base::Optional<MapRef> transition_map);
80   static PropertyAccessInfo FastDataConstant(
81       Zone* zone, MapRef receiver_map,
82       ZoneVector<CompilationDependency const*>&& unrecorded_dependencies,
83       FieldIndex field_index, Representation field_representation,
84       Type field_type, MapRef field_owner_map, base::Optional<MapRef> field_map,
85       base::Optional<JSObjectRef> holder,
86       base::Optional<MapRef> transition_map);
87   static PropertyAccessInfo FastAccessorConstant(
88       Zone* zone, MapRef receiver_map, base::Optional<ObjectRef> constant,
89       base::Optional<JSObjectRef> holder);
90   static PropertyAccessInfo ModuleExport(Zone* zone, MapRef receiver_map,
91                                          CellRef cell);
92   static PropertyAccessInfo StringLength(Zone* zone, MapRef receiver_map);
93   static PropertyAccessInfo Invalid(Zone* zone);
94   static PropertyAccessInfo DictionaryProtoDataConstant(
95       Zone* zone, MapRef receiver_map, JSObjectRef holder,
96       InternalIndex dict_index, NameRef name);
97   static PropertyAccessInfo DictionaryProtoAccessorConstant(
98       Zone* zone, MapRef receiver_map, base::Optional<JSObjectRef> holder,
99       ObjectRef constant, NameRef name);
100 
101   bool Merge(PropertyAccessInfo const* that, AccessMode access_mode,
102              Zone* zone) V8_WARN_UNUSED_RESULT;
103 
104   void RecordDependencies(CompilationDependencies* dependencies);
105 
IsInvalid()106   bool IsInvalid() const { return kind() == kInvalid; }
IsNotFound()107   bool IsNotFound() const { return kind() == kNotFound; }
IsDataField()108   bool IsDataField() const { return kind() == kDataField; }
IsFastDataConstant()109   bool IsFastDataConstant() const { return kind() == kFastDataConstant; }
IsFastAccessorConstant()110   bool IsFastAccessorConstant() const {
111     return kind() == kFastAccessorConstant;
112   }
IsModuleExport()113   bool IsModuleExport() const { return kind() == kModuleExport; }
IsStringLength()114   bool IsStringLength() const { return kind() == kStringLength; }
IsDictionaryProtoDataConstant()115   bool IsDictionaryProtoDataConstant() const {
116     return kind() == kDictionaryProtoDataConstant;
117   }
IsDictionaryProtoAccessorConstant()118   bool IsDictionaryProtoAccessorConstant() const {
119     return kind() == kDictionaryProtoAccessorConstant;
120   }
121 
HasTransitionMap()122   bool HasTransitionMap() const { return transition_map().has_value(); }
HasDictionaryHolder()123   bool HasDictionaryHolder() const {
124     return kind_ == kDictionaryProtoDataConstant ||
125            kind_ == kDictionaryProtoAccessorConstant;
126   }
127   ConstFieldInfo GetConstFieldInfo() const;
128 
kind()129   Kind kind() const { return kind_; }
holder()130   base::Optional<JSObjectRef> holder() const {
131     // TODO(neis): There was a CHECK here that tries to protect against
132     // using the access info without recording its dependencies first.
133     // Find a more suitable place for it.
134     return holder_;
135   }
transition_map()136   base::Optional<MapRef> transition_map() const {
137     DCHECK(!HasDictionaryHolder());
138     return transition_map_;
139   }
constant()140   base::Optional<ObjectRef> constant() const {
141     DCHECK_IMPLIES(constant_.has_value(),
142                    IsModuleExport() || IsFastAccessorConstant() ||
143                        IsDictionaryProtoAccessorConstant());
144     return constant_;
145   }
field_index()146   FieldIndex field_index() const {
147     DCHECK(!HasDictionaryHolder());
148     return field_index_;
149   }
150 
field_type()151   Type field_type() const {
152     DCHECK(!HasDictionaryHolder());
153     return field_type_;
154   }
field_representation()155   Representation field_representation() const {
156     DCHECK(!HasDictionaryHolder());
157     return field_representation_;
158   }
field_map()159   base::Optional<MapRef> field_map() const {
160     DCHECK(!HasDictionaryHolder());
161     return field_map_;
162   }
lookup_start_object_maps()163   ZoneVector<MapRef> const& lookup_start_object_maps() const {
164     return lookup_start_object_maps_;
165   }
166 
dictionary_index()167   InternalIndex dictionary_index() const {
168     DCHECK(HasDictionaryHolder());
169     return dictionary_index_;
170   }
171 
name()172   NameRef name() const {
173     DCHECK(HasDictionaryHolder());
174     return name_.value();
175   }
176 
177  private:
178   explicit PropertyAccessInfo(Zone* zone);
179   PropertyAccessInfo(Zone* zone, Kind kind, base::Optional<JSObjectRef> holder,
180                      ZoneVector<MapRef>&& lookup_start_object_maps);
181   PropertyAccessInfo(Zone* zone, Kind kind, base::Optional<JSObjectRef> holder,
182                      base::Optional<ObjectRef> constant,
183                      base::Optional<NameRef> name,
184                      ZoneVector<MapRef>&& lookup_start_object_maps);
185   PropertyAccessInfo(Kind kind, base::Optional<JSObjectRef> holder,
186                      base::Optional<MapRef> transition_map,
187                      FieldIndex field_index,
188                      Representation field_representation, Type field_type,
189                      MapRef field_owner_map, base::Optional<MapRef> field_map,
190                      ZoneVector<MapRef>&& lookup_start_object_maps,
191                      ZoneVector<CompilationDependency const*>&& dependencies);
192   PropertyAccessInfo(Zone* zone, Kind kind, base::Optional<JSObjectRef> holder,
193                      ZoneVector<MapRef>&& lookup_start_object_maps,
194                      InternalIndex dictionary_index, NameRef name);
195 
196   // Members used for fast and dictionary mode holders:
197   Kind kind_;
198   ZoneVector<MapRef> lookup_start_object_maps_;
199   base::Optional<ObjectRef> constant_;
200   base::Optional<JSObjectRef> holder_;
201 
202   // Members only used for fast mode holders:
203   ZoneVector<CompilationDependency const*> unrecorded_dependencies_;
204   base::Optional<MapRef> transition_map_;
205   FieldIndex field_index_;
206   Representation field_representation_;
207   Type field_type_;
208   base::Optional<MapRef> field_owner_map_;
209   base::Optional<MapRef> field_map_;
210 
211   // Members only used for dictionary mode holders:
212   InternalIndex dictionary_index_;
213   base::Optional<NameRef> name_;
214 };
215 
216 // Factory class for {ElementAccessInfo}s and {PropertyAccessInfo}s.
217 class AccessInfoFactory final {
218  public:
219   AccessInfoFactory(JSHeapBroker* broker, CompilationDependencies* dependencies,
220                     Zone* zone);
221 
222   base::Optional<ElementAccessInfo> ComputeElementAccessInfo(
223       MapRef map, AccessMode access_mode) const;
224   bool ComputeElementAccessInfos(
225       ElementAccessFeedback const& feedback,
226       ZoneVector<ElementAccessInfo>* access_infos) const;
227 
228   PropertyAccessInfo ComputePropertyAccessInfo(MapRef map, NameRef name,
229                                                AccessMode access_mode) const;
230 
231   PropertyAccessInfo ComputeDictionaryProtoAccessInfo(
232       MapRef receiver_map, NameRef name, JSObjectRef holder,
233       InternalIndex dict_index, AccessMode access_mode,
234       PropertyDetails details) const;
235 
236   // Merge as many of the given {infos} as possible and record any dependencies.
237   // Return false iff any of them was invalid, in which case no dependencies are
238   // recorded.
239   // TODO(neis): Make access_mode part of access info?
240   bool FinalizePropertyAccessInfos(
241       ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode,
242       ZoneVector<PropertyAccessInfo>* result) const;
243 
244   // Merge the given {infos} to a single one and record any dependencies. If the
245   // merge is not possible, the result has kind {kInvalid} and no dependencies
246   // are recorded.
247   PropertyAccessInfo FinalizePropertyAccessInfosAsOne(
248       ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode) const;
249 
250  private:
251   base::Optional<ElementAccessInfo> ConsolidateElementLoad(
252       ElementAccessFeedback const& feedback) const;
253   PropertyAccessInfo LookupSpecialFieldAccessor(MapRef map, NameRef name) const;
254   PropertyAccessInfo LookupTransition(MapRef map, NameRef name,
255                                       base::Optional<JSObjectRef> holder,
256                                       PropertyAttributes attrs) const;
257   PropertyAccessInfo ComputeDataFieldAccessInfo(
258       MapRef receiver_map, MapRef map, NameRef name,
259       base::Optional<JSObjectRef> holder, InternalIndex descriptor,
260       AccessMode access_mode) const;
261   PropertyAccessInfo ComputeAccessorDescriptorAccessInfo(
262       MapRef receiver_map, NameRef name, MapRef map,
263       base::Optional<JSObjectRef> holder, InternalIndex descriptor,
264       AccessMode access_mode) const;
265 
Invalid()266   PropertyAccessInfo Invalid() const {
267     return PropertyAccessInfo::Invalid(zone());
268   }
269 
270   void MergePropertyAccessInfos(ZoneVector<PropertyAccessInfo> infos,
271                                 AccessMode access_mode,
272                                 ZoneVector<PropertyAccessInfo>* result) const;
273 
274   bool TryLoadPropertyDetails(MapRef map,
275                               base::Optional<JSObjectRef> maybe_holder,
276                               NameRef name, InternalIndex* index_out,
277                               PropertyDetails* details_out) const;
278 
dependencies()279   CompilationDependencies* dependencies() const { return dependencies_; }
broker()280   JSHeapBroker* broker() const { return broker_; }
281   Isolate* isolate() const;
zone()282   Zone* zone() const { return zone_; }
283 
284   JSHeapBroker* const broker_;
285   CompilationDependencies* const dependencies_;
286   TypeCache const* const type_cache_;
287   Zone* const zone_;
288 
289   AccessInfoFactory(const AccessInfoFactory&) = delete;
290   AccessInfoFactory& operator=(const AccessInfoFactory&) = delete;
291 };
292 
293 }  // namespace compiler
294 }  // namespace internal
295 }  // namespace v8
296 
297 #endif  // V8_COMPILER_ACCESS_INFO_H_
298