access-info.h 13 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#ifndef V8_COMPILER_ACCESS_INFO_H_
#define V8_COMPILER_ACCESS_INFO_H_
7 8 9

#include <iosfwd>

10
#include "src/codegen/machine-type.h"
11
#include "src/compiler/types.h"
12
#include "src/objects/feedback-vector.h"
13
#include "src/objects/field-index.h"
14
#include "src/objects/map.h"
15
#include "src/objects/objects.h"
16
#include "src/zone/zone-containers.h"
17 18 19 20 21 22 23 24 25

namespace v8 {
namespace internal {

// Forward declarations.
class Factory;

namespace compiler {

26
// Forward declarations.
27 28
class CompilationDependencies;
class CompilationDependency;
29
class ElementAccessFeedback;
30
class JSHeapBroker;
31
class MinimorphicLoadPropertyAccessFeedback;
32
class TypeCache;
33
struct ConstFieldInfo;
34

35 36 37 38 39
std::ostream& operator<<(std::ostream&, AccessMode);

// This class encapsulates all information required to access a certain element.
class ElementAccessInfo final {
 public:
40
  ElementAccessInfo(ZoneVector<Handle<Map>>&& lookup_start_object_maps,
41
                    ElementsKind elements_kind, Zone* zone);
42 43

  ElementsKind elements_kind() const { return elements_kind_; }
44 45
  ZoneVector<Handle<Map>> const& lookup_start_object_maps() const {
    return lookup_start_object_maps_;
46 47 48 49
  }
  ZoneVector<Handle<Map>> const& transition_sources() const {
    return transition_sources_;
  }
50 51

  void AddTransitionSource(Handle<Map> map) {
52
    CHECK_EQ(lookup_start_object_maps_.size(), 1);
53 54
    transition_sources_.push_back(map);
  }
55 56 57

 private:
  ElementsKind elements_kind_;
58
  ZoneVector<Handle<Map>> lookup_start_object_maps_;
59
  ZoneVector<Handle<Map>> transition_sources_;
60
};
61 62 63 64 65

// This class encapsulates all information required to access a certain
// object property, either on the object itself or on the prototype chain.
class PropertyAccessInfo final {
 public:
66 67 68 69
  enum Kind {
    kInvalid,
    kNotFound,
    kDataField,
70 71 72 73
    kFastDataConstant,
    kDictionaryProtoDataConstant,
    kFastAccessorConstant,
    kDictionaryProtoAccessorConstant,
74 75
    kModuleExport,
    kStringLength
76
  };
77

78
  static PropertyAccessInfo NotFound(Zone* zone, Handle<Map> receiver_map,
79
                                     MaybeHandle<JSObject> holder);
80
  static PropertyAccessInfo DataField(
81
      Zone* zone, Handle<Map> receiver_map,
82
      ZoneVector<CompilationDependency const*>&& unrecorded_dependencies,
83
      FieldIndex field_index, Representation field_representation,
84 85
      Type field_type, Handle<Map> field_owner_map,
      MaybeHandle<Map> field_map = MaybeHandle<Map>(),
86
      MaybeHandle<JSObject> holder = MaybeHandle<JSObject>(),
87
      MaybeHandle<Map> transition_map = MaybeHandle<Map>());
88
  static PropertyAccessInfo FastDataConstant(
89
      Zone* zone, Handle<Map> receiver_map,
90
      ZoneVector<CompilationDependency const*>&& unrecorded_dependencies,
91
      FieldIndex field_index, Representation field_representation,
92 93
      Type field_type, Handle<Map> field_owner_map, MaybeHandle<Map> field_map,
      MaybeHandle<JSObject> holder,
94
      MaybeHandle<Map> transition_map = MaybeHandle<Map>());
95 96 97 98
  static PropertyAccessInfo FastAccessorConstant(Zone* zone,
                                                 Handle<Map> receiver_map,
                                                 Handle<Object> constant,
                                                 MaybeHandle<JSObject> holder);
99
  static PropertyAccessInfo ModuleExport(Zone* zone, Handle<Map> receiver_map,
100
                                         Handle<Cell> cell);
101 102
  static PropertyAccessInfo StringLength(Zone* zone, Handle<Map> receiver_map);
  static PropertyAccessInfo Invalid(Zone* zone);
103 104
  static PropertyAccessInfo DictionaryProtoDataConstant(
      Zone* zone, Handle<Map> receiver_map, Handle<JSObject> holder,
105
      InternalIndex dict_index, Handle<Name> name);
106 107
  static PropertyAccessInfo DictionaryProtoAccessorConstant(
      Zone* zone, Handle<Map> receiver_map, MaybeHandle<JSObject> holder,
108
      Handle<Object> constant, Handle<Name> name);
109

110
  bool Merge(PropertyAccessInfo const* that, AccessMode access_mode,
111
             Zone* zone) V8_WARN_UNUSED_RESULT;
112

113 114
  void RecordDependencies(CompilationDependencies* dependencies);

115
  bool IsInvalid() const { return kind() == kInvalid; }
116
  bool IsNotFound() const { return kind() == kNotFound; }
117
  bool IsDataField() const { return kind() == kDataField; }
118 119 120 121
  bool IsFastDataConstant() const { return kind() == kFastDataConstant; }
  bool IsFastAccessorConstant() const {
    return kind() == kFastAccessorConstant;
  }
122
  bool IsModuleExport() const { return kind() == kModuleExport; }
123
  bool IsStringLength() const { return kind() == kStringLength; }
124 125 126 127 128 129
  bool IsDictionaryProtoDataConstant() const {
    return kind() == kDictionaryProtoDataConstant;
  }
  bool IsDictionaryProtoAccessorConstant() const {
    return kind() == kDictionaryProtoAccessorConstant;
  }
130

131
  bool HasTransitionMap() const { return !transition_map().is_null(); }
132 133 134 135
  bool HasDictionaryHolder() const {
    return kind_ == kDictionaryProtoDataConstant ||
           kind_ == kDictionaryProtoAccessorConstant;
  }
136
  ConstFieldInfo GetConstFieldInfo() const;
137

138
  Kind kind() const { return kind_; }
139
  MaybeHandle<JSObject> holder() const {
140 141 142
    // TODO(neis): There was a CHECK here that tries to protect against
    // using the access info without recording its dependencies first.
    // Find a more suitable place for it.
143 144
    return holder_;
  }
145 146 147 148
  MaybeHandle<Map> transition_map() const {
    DCHECK(!HasDictionaryHolder());
    return transition_map_;
  }
149
  Handle<Object> constant() const { return constant_; }
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
  FieldIndex field_index() const {
    DCHECK(!HasDictionaryHolder());
    return field_index_;
  }

  Type field_type() const {
    DCHECK(!HasDictionaryHolder());
    return field_type_;
  }
  Representation field_representation() const {
    DCHECK(!HasDictionaryHolder());
    return field_representation_;
  }
  MaybeHandle<Map> field_map() const {
    DCHECK(!HasDictionaryHolder());
    return field_map_;
  }
167 168
  ZoneVector<Handle<Map>> const& lookup_start_object_maps() const {
    return lookup_start_object_maps_;
169
  }
170

171 172 173 174 175
  InternalIndex dictionary_index() const {
    DCHECK(HasDictionaryHolder());
    return dictionary_index_;
  }

176 177 178 179 180
  Handle<Name> name() const {
    DCHECK(HasDictionaryHolder());
    return name_.ToHandleChecked();
  }

181
 private:
182 183
  explicit PropertyAccessInfo(Zone* zone);
  PropertyAccessInfo(Zone* zone, Kind kind, MaybeHandle<JSObject> holder,
184
                     ZoneVector<Handle<Map>>&& lookup_start_object_maps);
185
  PropertyAccessInfo(Zone* zone, Kind kind, MaybeHandle<JSObject> holder,
186
                     Handle<Object> constant, MaybeHandle<Name> name,
187
                     ZoneVector<Handle<Map>>&& lookup_start_object_maps);
188 189 190
  PropertyAccessInfo(Kind kind, MaybeHandle<JSObject> holder,
                     MaybeHandle<Map> transition_map, FieldIndex field_index,
                     Representation field_representation, Type field_type,
191
                     Handle<Map> field_owner_map, MaybeHandle<Map> field_map,
192
                     ZoneVector<Handle<Map>>&& lookup_start_object_maps,
193
                     ZoneVector<CompilationDependency const*>&& dependencies);
194 195
  PropertyAccessInfo(Zone* zone, Kind kind, MaybeHandle<JSObject> holder,
                     ZoneVector<Handle<Map>>&& lookup_start_object_maps,
196
                     InternalIndex dictionary_index, Handle<Name> name);
197

198
  // Members used for fast and dictionary mode holders:
199
  Kind kind_;
200
  ZoneVector<Handle<Map>> lookup_start_object_maps_;
201 202
  Handle<Object> constant_;
  MaybeHandle<JSObject> holder_;
203 204 205 206

  // Members only used for fast mode holders:
  ZoneVector<CompilationDependency const*> unrecorded_dependencies_;
  MaybeHandle<Map> transition_map_;
207
  FieldIndex field_index_;
208
  Representation field_representation_;
209
  Type field_type_;
210
  MaybeHandle<Map> field_owner_map_;
211
  MaybeHandle<Map> field_map_;
212 213 214

  // Members only used for dictionary mode holders:
  InternalIndex dictionary_index_;
215
  MaybeHandle<Name> name_;
216 217
};

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
// This class encapsulates information required to generate load properties
// by only using the information from handlers. This information is used with
// dynamic map checks.
class MinimorphicLoadPropertyAccessInfo final {
 public:
  enum Kind { kInvalid, kDataField };
  static MinimorphicLoadPropertyAccessInfo DataField(
      int offset, bool is_inobject, Representation field_representation,
      Type field_type);
  static MinimorphicLoadPropertyAccessInfo Invalid();

  bool IsInvalid() const { return kind_ == kInvalid; }
  bool IsDataField() const { return kind_ == kDataField; }
  int offset() const { return offset_; }
  int is_inobject() const { return is_inobject_; }
  Type field_type() const { return field_type_; }
  Representation field_representation() const { return field_representation_; }

 private:
  MinimorphicLoadPropertyAccessInfo(Kind kind, int offset, bool is_inobject,
                                    Representation field_representation,
                                    Type field_type);

  Kind kind_;
  bool is_inobject_;
  int offset_;
  Representation field_representation_;
  Type field_type_;
};
247

248 249
// Factory class for {ElementAccessInfo}s and {PropertyAccessInfo}s.
class AccessInfoFactory final {
250
 public:
251
  AccessInfoFactory(JSHeapBroker* broker, CompilationDependencies* dependencies,
252
                    Zone* zone);
253

254 255
  base::Optional<ElementAccessInfo> ComputeElementAccessInfo(
      Handle<Map> map, AccessMode access_mode) const;
256
  bool ComputeElementAccessInfos(
257
      ElementAccessFeedback const& feedback,
258 259
      ZoneVector<ElementAccessInfo>* access_infos) const;

260 261 262
  PropertyAccessInfo ComputePropertyAccessInfo(Handle<Map> map,
                                               Handle<Name> name,
                                               AccessMode access_mode) const;
263

264 265 266 267 268
  PropertyAccessInfo ComputeDictionaryProtoAccessInfo(
      Handle<Map> receiver_map, Handle<Name> name, Handle<JSObject> holder,
      InternalIndex dict_index, AccessMode access_mode,
      PropertyDetails details) const;

269 270 271
  MinimorphicLoadPropertyAccessInfo ComputePropertyAccessInfo(
      MinimorphicLoadPropertyAccessFeedback const& feedback) const;

272
  // Convenience wrapper around {ComputePropertyAccessInfo} for multiple maps.
273
  void ComputePropertyAccessInfos(
274 275
      MapHandles const& maps, Handle<Name> name, AccessMode access_mode,
      ZoneVector<PropertyAccessInfo>* access_infos) const;
276

277 278 279 280
  // Merge as many of the given {infos} as possible and record any dependencies.
  // Return false iff any of them was invalid, in which case no dependencies are
  // recorded.
  // TODO(neis): Make access_mode part of access info?
281 282 283 284
  bool FinalizePropertyAccessInfos(
      ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode,
      ZoneVector<PropertyAccessInfo>* result) const;

285 286 287 288 289 290
  // Merge the given {infos} to a single one and record any dependencies. If the
  // merge is not possible, the result has kind {kInvalid} and no dependencies
  // are recorded.
  PropertyAccessInfo FinalizePropertyAccessInfosAsOne(
      ZoneVector<PropertyAccessInfo> infos, AccessMode access_mode) const;

291
 private:
292
  base::Optional<ElementAccessInfo> ConsolidateElementLoad(
293
      ElementAccessFeedback const& feedback) const;
294 295 296 297 298 299 300
  PropertyAccessInfo LookupSpecialFieldAccessor(Handle<Map> map,
                                                Handle<Name> name) const;
  PropertyAccessInfo LookupTransition(Handle<Map> map, Handle<Name> name,
                                      MaybeHandle<JSObject> holder) const;
  PropertyAccessInfo ComputeDataFieldAccessInfo(Handle<Map> receiver_map,
                                                Handle<Map> map,
                                                MaybeHandle<JSObject> holder,
301
                                                InternalIndex descriptor,
302 303
                                                AccessMode access_mode) const;
  PropertyAccessInfo ComputeAccessorDescriptorAccessInfo(
304
      Handle<Map> receiver_map, Handle<Name> name, Handle<Map> map,
305
      MaybeHandle<JSObject> holder, InternalIndex descriptor,
306
      AccessMode access_mode) const;
307

308 309 310 311
  PropertyAccessInfo Invalid() const {
    return PropertyAccessInfo::Invalid(zone());
  }

312 313 314 315
  void MergePropertyAccessInfos(ZoneVector<PropertyAccessInfo> infos,
                                AccessMode access_mode,
                                ZoneVector<PropertyAccessInfo>* result) const;

316 317 318 319
  bool TryLoadPropertyDetails(Handle<Map> map, MaybeHandle<JSObject> holder,
                              Handle<Name> name, InternalIndex* index_out,
                              PropertyDetails* details_out) const;

320
  CompilationDependencies* dependencies() const { return dependencies_; }
321
  JSHeapBroker* broker() const { return broker_; }
322
  Isolate* isolate() const;
323 324
  Zone* zone() const { return zone_; }

325
  JSHeapBroker* const broker_;
326
  CompilationDependencies* const dependencies_;
327
  TypeCache const* const type_cache_;
328 329
  Zone* const zone_;

330 331 332
  // TODO(nicohartmann@): Move to public
  AccessInfoFactory(const AccessInfoFactory&) = delete;
  AccessInfoFactory& operator=(const AccessInfoFactory&) = delete;
333 334 335 336 337 338
};

}  // namespace compiler
}  // namespace internal
}  // namespace v8

339
#endif  // V8_COMPILER_ACCESS_INFO_H_