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