lookup.h 10.4 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2014 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.

#ifndef V8_LOOKUP_H_
#define V8_LOOKUP_H_

8
#include "src/globals.h"
9
#include "src/heap/factory.h"
10 11
#include "src/isolate.h"
#include "src/objects.h"
12
#include "src/objects/descriptor-array.h"
13
#include "src/objects/map.h"
14 15 16 17

namespace v8 {
namespace internal {

18
class V8_EXPORT_PRIVATE LookupIterator final {
19
 public:
20
  enum Configuration {
21
    // Configuration bits.
22 23
    kInterceptor = 1 << 0,
    kPrototypeChain = 1 << 1,
24

25
    // Convenience combinations of bits.
26 27
    OWN_SKIP_INTERCEPTOR = 0,
    OWN = kInterceptor,
28 29
    PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain,
    PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor,
30
    DEFAULT = PROTOTYPE_CHAIN
31 32 33
  };

  enum State {
34
    ACCESS_CHECK,
35
    INTEGER_INDEXED_EXOTIC,
36 37
    INTERCEPTOR,
    JSPROXY,
38
    NOT_FOUND,
39 40
    ACCESSOR,
    DATA,
41
    TRANSITION,
42 43 44
    // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
    // PROPERTY lookup.
    BEFORE_PROPERTY = INTERCEPTOR
45 46
  };

47 48 49 50
  LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
                 Configuration configuration = DEFAULT)
      : LookupIterator(isolate, receiver, name, GetRoot(isolate, receiver),
                       configuration) {}
51

52 53 54
  inline LookupIterator(Handle<Object> receiver, Handle<Name> name,
                        Handle<JSReceiver> holder,
                        Configuration configuration = DEFAULT);
55

56 57 58
  inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
                        Handle<Name> name, Handle<JSReceiver> holder,
                        Configuration configuration = DEFAULT);
59

60
  LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
61
                 Configuration configuration = DEFAULT)
62 63
      : LookupIterator(isolate, receiver, index,
                       GetRoot(isolate, receiver, index), configuration) {}
64 65 66

  LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
                 Handle<JSReceiver> holder,
67
                 Configuration configuration = DEFAULT)
68 69 70 71 72
      : configuration_(configuration),
        interceptor_state_(InterceptorState::kUninitialized),
        property_details_(PropertyDetails::Empty()),
        isolate_(isolate),
        receiver_(receiver),
73 74
        initial_holder_(holder),
        index_(index),
75
        number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) {
76 77
    // kMaxUInt32 isn't a valid index.
    DCHECK_NE(kMaxUInt32, index_);
78
    Start<true>();
79 80
  }

81
  static inline LookupIterator PropertyOrElement(
82
      Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
83
      Configuration configuration = DEFAULT);
84

85
  static inline LookupIterator PropertyOrElement(
86
      Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
87
      Handle<JSReceiver> holder, Configuration configuration = DEFAULT);
88

89 90 91 92 93
  static LookupIterator PropertyOrElement(
      Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
      bool* success, Handle<JSReceiver> holder,
      Configuration configuration = DEFAULT);

94 95 96 97
  static LookupIterator PropertyOrElement(
      Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
      bool* success, Configuration configuration = DEFAULT);

98 99 100
  static LookupIterator ForTransitionHandler(
      Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
      Handle<Object> value, MaybeHandle<Map> maybe_transition_map);
101

102 103 104 105
  void Restart() {
    InterceptorState state = InterceptorState::kUninitialized;
    IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
  }
106

107 108
  Isolate* isolate() const { return isolate_; }
  State state() const { return state_; }
109

110 111 112 113
  Handle<Name> name() const {
    DCHECK(!IsElement());
    return name_;
  }
114
  inline Handle<Name> GetName();
115 116 117
  uint32_t index() const { return index_; }

  bool IsElement() const { return index_ != kMaxUInt32; }
118 119 120

  bool IsFound() const { return state_ != NOT_FOUND; }
  void Next();
121 122 123 124
  void NotFound() {
    has_property_ = false;
    state_ = NOT_FOUND;
  }
125

126
  Heap* heap() const { return isolate_->heap(); }
127
  Factory* factory() const { return isolate_->factory(); }
128
  Handle<Object> GetReceiver() const { return receiver_; }
129

130
  template <class T>
131
  inline Handle<T> GetStoreTarget() const;
132
  inline bool is_dictionary_holder() const;
133 134
  Handle<Map> transition_map() const {
    DCHECK_EQ(TRANSITION, state_);
135
    return Handle<Map>::cast(transition_);
136
  }
137 138 139 140
  Handle<PropertyCell> transition_cell() const {
    DCHECK_EQ(TRANSITION, state_);
    return Handle<PropertyCell>::cast(transition_);
  }
141 142
  template <class T>
  Handle<T> GetHolder() const {
143
    DCHECK(IsFound());
144
    return Handle<T>::cast(holder_);
145
  }
146

147
  bool HolderIsReceiver() const;
148
  bool HolderIsReceiverOrHiddenPrototype() const;
149

neis's avatar
neis committed
150 151 152 153
  bool check_prototype_chain() const {
    return (configuration_ & kPrototypeChain) != 0;
  }

154
  /* ACCESS_CHECK */
155
  bool HasAccess() const;
156 157

  /* PROPERTY */
158
  inline bool ExtendingNonExtensible(Handle<JSReceiver> receiver);
159
  void PrepareForDataProperty(Handle<Object> value);
160
  void PrepareTransitionToDataProperty(Handle<JSReceiver> receiver,
161
                                       Handle<Object> value,
162
                                       PropertyAttributes attributes,
163
                                       StoreOrigin store_origin);
164
  inline bool IsCacheableTransition();
165
  void ApplyTransitionToDataProperty(Handle<JSReceiver> receiver);
166 167
  void ReconfigureDataProperty(Handle<Object> value,
                               PropertyAttributes attributes);
168
  void Delete();
169 170
  void TransitionToAccessorProperty(Handle<Object> getter,
                                    Handle<Object> setter,
171
                                    PropertyAttributes attributes);
172 173
  void TransitionToAccessorPair(Handle<Object> pair,
                                PropertyAttributes attributes);
174
  PropertyDetails property_details() const {
175
    DCHECK(has_property_);
176 177
    return property_details_;
  }
178 179 180
  PropertyAttributes property_attributes() const {
    return property_details().attributes();
  }
181
  bool IsConfigurable() const { return property_details().IsConfigurable(); }
182
  bool IsReadOnly() const { return property_details().IsReadOnly(); }
183
  bool IsEnumerable() const { return property_details().IsEnumerable(); }
184 185
  Representation representation() const {
    return property_details().representation();
186
  }
187
  PropertyLocation location() const { return property_details().location(); }
188
  PropertyConstness constness() const { return property_details().constness(); }
189
  Handle<Map> GetFieldOwnerMap() const;
190
  FieldIndex GetFieldIndex() const;
191
  Handle<FieldType> GetFieldType() const;
192
  int GetFieldDescriptorIndex() const;
193
  int GetAccessorIndex() const;
194
  int GetConstantIndex() const;
195
  Handle<PropertyCell> GetPropertyCell() const;
196
  Handle<Object> GetAccessors() const;
197
  inline Handle<InterceptorInfo> GetInterceptor() const;
198
  Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const;
199
  Handle<Object> GetDataValue() const;
200
  void WriteDataValue(Handle<Object> value, bool initializing_store);
201
  inline void UpdateProtector();
202

203 204 205 206 207
  // Lookup a 'cached' private property for an accessor.
  // If not found returns false and leaves the LookupIterator unmodified.
  bool TryLookupCachedProperty();
  bool LookupCachedProperty();

208
 private:
209 210 211 212 213
  // For |ForTransitionHandler|.
  LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
                 Handle<Map> transition_map, PropertyDetails details,
                 bool has_property);

214 215
  void InternalUpdateProtector();

216 217 218 219 220 221
  enum class InterceptorState {
    kUninitialized,
    kSkipNonMasking,
    kProcessNonMasking
  };

222 223
  Handle<Map> GetReceiverMap() const;

224
  V8_WARN_UNUSED_RESULT inline JSReceiver* NextHolder(Map* map);
225 226

  template <bool is_element>
227
  V8_EXPORT_PRIVATE void Start();
228 229 230 231
  template <bool is_element>
  void NextInternal(Map* map, JSReceiver* holder);
  template <bool is_element>
  inline State LookupInHolder(Map* map, JSReceiver* holder) {
232
    return map->IsSpecialReceiverMap()
233 234 235 236 237 238 239 240
               ? LookupInSpecialHolder<is_element>(map, holder)
               : LookupInRegularHolder<is_element>(map, holder);
  }
  template <bool is_element>
  State LookupInRegularHolder(Map* map, JSReceiver* holder);
  template <bool is_element>
  State LookupInSpecialHolder(Map* map, JSReceiver* holder);
  template <bool is_element>
241
  void RestartLookupForNonMaskingInterceptors() {
242
    RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
243
  }
244
  template <bool is_element>
245
  void RestartInternal(InterceptorState interceptor_state);
246
  Handle<Object> FetchValue() const;
247
  bool IsConstFieldValueEqualTo(Object* value) const;
248
  template <bool is_element>
249
  void ReloadPropertyInformation();
250

251 252 253
  template <bool is_element>
  bool SkipInterceptor(JSObject* holder);
  template <bool is_element>
254
  inline InterceptorInfo* GetInterceptor(JSObject* holder) const {
255 256
    return is_element ? holder->GetIndexedInterceptor()
                      : holder->GetNamedInterceptor();
257
  }
258

259
  bool check_interceptor() const {
260
    return (configuration_ & kInterceptor) != 0;
261
  }
262
  int descriptor_number() const {
263
    DCHECK(!IsElement());
264
    DCHECK(has_property_);
265
    DCHECK(holder_->HasFastProperties());
266 267 268
    return number_;
  }
  int dictionary_entry() const {
269
    DCHECK(!IsElement());
270
    DCHECK(has_property_);
271
    DCHECK(!holder_->HasFastProperties());
272 273
    return number_;
  }
274

275 276
  static inline Configuration ComputeConfiguration(
      Configuration configuration, Handle<Name> name);
277

278 279
  static Handle<JSReceiver> GetRootForNonJSReceiver(
      Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32);
280
  static inline Handle<JSReceiver> GetRoot(Isolate* isolate,
281
                                           Handle<Object> receiver,
282
                                           uint32_t index = kMaxUInt32);
283

284
  State NotFound(JSReceiver* const holder) const;
285

286 287
  // If configuration_ becomes mutable, update
  // HolderIsReceiverOrHiddenPrototype.
288
  const Configuration configuration_;
289 290
  State state_;
  bool has_property_;
291
  InterceptorState interceptor_state_;
292
  PropertyDetails property_details_;
293
  Isolate* const isolate_;
294
  Handle<Name> name_;
295
  Handle<Object> transition_;
296
  const Handle<Object> receiver_;
297
  Handle<JSReceiver> holder_;
298
  const Handle<JSReceiver> initial_holder_;
299
  const uint32_t index_;
300
  uint32_t number_;
301 302 303
};


304 305
}  // namespace internal
}  // namespace v8
306 307

#endif  // V8_LOOKUP_H_