lookup.h 11.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 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_

#include "src/factory.h"
#include "src/isolate.h"
#include "src/objects.h"

namespace v8 {
namespace internal {

15
class LookupIterator final BASE_EMBEDDED {
16
 public:
17
  enum Configuration {
18
    // Configuration bits.
19 20 21
    kHidden = 1 << 0,
    kInterceptor = 1 << 1,
    kPrototypeChain = 1 << 2,
22 23

    // Convience combinations of bits.
24 25 26 27 28
    OWN_SKIP_INTERCEPTOR = 0,
    OWN = kInterceptor,
    HIDDEN_SKIP_INTERCEPTOR = kHidden,
    HIDDEN = kHidden | kInterceptor,
    PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kHidden | kPrototypeChain,
29 30
    PROTOTYPE_CHAIN = kHidden | kPrototypeChain | kInterceptor,
    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
  LookupIterator(Handle<Object> receiver, Handle<Name> name,
48
                 Configuration configuration = DEFAULT)
49
      : configuration_(ComputeConfiguration(configuration, name)),
50
        state_(NOT_FOUND),
51
        interceptor_state_(InterceptorState::kUninitialized),
52
        property_details_(PropertyDetails::Empty()),
53
        isolate_(name->GetIsolate()),
54
        name_(isolate_->factory()->InternalizeName(name)),
55 56
        // kMaxUInt32 isn't a valid index.
        index_(kMaxUInt32),
57
        receiver_(receiver),
58
        holder_(GetRoot(isolate_, receiver)),
59
        initial_holder_(holder_),
60
        number_(DescriptorArray::kNotFound) {
61 62 63 64
#ifdef DEBUG
    uint32_t index;  // Assert that the name is not an array index.
    DCHECK(!name->AsArrayIndex(&index));
#endif  // DEBUG
65 66 67
    Next();
  }

68
  LookupIterator(Handle<Object> receiver, Handle<Name> name,
69
                 Handle<JSReceiver> holder,
70
                 Configuration configuration = DEFAULT)
71
      : configuration_(ComputeConfiguration(configuration, name)),
72
        state_(NOT_FOUND),
73
        interceptor_state_(InterceptorState::kUninitialized),
74
        property_details_(PropertyDetails::Empty()),
75
        isolate_(name->GetIsolate()),
76
        name_(isolate_->factory()->InternalizeName(name)),
77 78
        // kMaxUInt32 isn't a valid index.
        index_(kMaxUInt32),
79 80
        receiver_(receiver),
        holder_(holder),
81
        initial_holder_(holder_),
82
        number_(DescriptorArray::kNotFound) {
83 84 85 86
#ifdef DEBUG
    uint32_t index;  // Assert that the name is not an array index.
    DCHECK(!name->AsArrayIndex(&index));
#endif  // DEBUG
87 88 89
    Next();
  }

90
  LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
91
                 Configuration configuration = DEFAULT)
92 93 94 95 96 97 98 99
      : configuration_(configuration),
        state_(NOT_FOUND),
        interceptor_state_(InterceptorState::kUninitialized),
        property_details_(PropertyDetails::Empty()),
        isolate_(isolate),
        name_(),
        index_(index),
        receiver_(receiver),
100
        holder_(GetRoot(isolate, receiver, index)),
101 102 103 104 105 106 107 108 109
        initial_holder_(holder_),
        number_(DescriptorArray::kNotFound) {
    // kMaxUInt32 isn't a valid index.
    DCHECK_NE(kMaxUInt32, index_);
    Next();
  }

  LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
                 Handle<JSReceiver> holder,
110
                 Configuration configuration = DEFAULT)
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
      : configuration_(configuration),
        state_(NOT_FOUND),
        interceptor_state_(InterceptorState::kUninitialized),
        property_details_(PropertyDetails::Empty()),
        isolate_(isolate),
        name_(),
        index_(index),
        receiver_(receiver),
        holder_(holder),
        initial_holder_(holder_),
        number_(DescriptorArray::kNotFound) {
    // kMaxUInt32 isn't a valid index.
    DCHECK_NE(kMaxUInt32, index_);
    Next();
  }

127 128 129 130
  static LookupIterator PropertyOrElement(
      Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
      Configuration configuration = DEFAULT) {
    uint32_t index;
131 132 133 134 135 136 137
    if (name->AsArrayIndex(&index)) {
      LookupIterator it =
          LookupIterator(isolate, receiver, index, configuration);
      it.name_ = name;
      return it;
    }
    return LookupIterator(receiver, name, configuration);
138 139 140 141 142 143
  }

  static LookupIterator PropertyOrElement(
      Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
      Handle<JSReceiver> holder, Configuration configuration = DEFAULT) {
    uint32_t index;
144 145 146 147 148 149 150
    if (name->AsArrayIndex(&index)) {
      LookupIterator it =
          LookupIterator(isolate, receiver, index, holder, configuration);
      it.name_ = name;
      return it;
    }
    return LookupIterator(receiver, name, holder, configuration);
151
  }
152

153 154 155 156
  static LookupIterator PropertyOrElement(
      Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
      bool* success, Configuration configuration = DEFAULT);

157 158
  void Restart() { RestartInternal(InterceptorState::kUninitialized); }

159 160
  Isolate* isolate() const { return isolate_; }
  State state() const { return state_; }
161

162 163 164 165 166 167 168
  Handle<Name> name() const {
    DCHECK(!IsElement());
    return name_;
  }
  Handle<Name> GetName() {
    if (name_.is_null()) {
      DCHECK(IsElement());
169
      name_ = factory()->Uint32ToString(index_);
170 171 172
    }
    return name_;
  }
173 174 175
  uint32_t index() const { return index_; }

  bool IsElement() const { return index_ != kMaxUInt32; }
176 177 178

  bool IsFound() const { return state_ != NOT_FOUND; }
  void Next();
179 180 181 182
  void NotFound() {
    has_property_ = false;
    state_ = NOT_FOUND;
  }
183

184
  Heap* heap() const { return isolate_->heap(); }
185
  Factory* factory() const { return isolate_->factory(); }
186
  Handle<Object> GetReceiver() const { return receiver_; }
187
  Handle<JSObject> GetStoreTarget() const;
188
  bool is_dictionary_holder() const { return !holder_->HasFastProperties(); }
189 190
  Handle<Map> transition_map() const {
    DCHECK_EQ(TRANSITION, state_);
191
    return Handle<Map>::cast(transition_);
192
  }
193 194
  template <class T>
  Handle<T> GetHolder() const {
195
    DCHECK(IsFound());
196
    return Handle<T>::cast(holder_);
197
  }
198

199
  bool HolderIsReceiverOrHiddenPrototype() const;
200

neis's avatar
neis committed
201 202 203 204
  bool check_prototype_chain() const {
    return (configuration_ & kPrototypeChain) != 0;
  }

205
  /* ACCESS_CHECK */
206
  bool HasAccess() const;
207 208

  /* PROPERTY */
209 210 211
  bool ExtendingNonExtensible(Handle<JSObject> receiver) {
    DCHECK(receiver.is_identical_to(GetStoreTarget()));
    return !receiver->map()->is_extensible() &&
212
           (IsElement() || !name_->IsPrivate());
213
  }
214
  void PrepareForDataProperty(Handle<Object> value);
215 216
  void PrepareTransitionToDataProperty(Handle<JSObject> receiver,
                                       Handle<Object> value,
217 218 219
                                       PropertyAttributes attributes,
                                       Object::StoreFromKeyed store_mode);
  bool IsCacheableTransition() {
220
    DCHECK_EQ(TRANSITION, state_);
221
    return transition_->IsPropertyCell() ||
222 223
           (!transition_map()->is_dictionary_map() &&
            transition_map()->GetBackPointer()->IsMap());
224
  }
225
  void ApplyTransitionToDataProperty(Handle<JSObject> receiver);
226 227
  void ReconfigureDataProperty(Handle<Object> value,
                               PropertyAttributes attributes);
228
  void Delete();
229 230 231
  void TransitionToAccessorProperty(AccessorComponent component,
                                    Handle<Object> accessor,
                                    PropertyAttributes attributes);
232 233
  void TransitionToAccessorPair(Handle<Object> pair,
                                PropertyAttributes attributes);
234
  PropertyDetails property_details() const {
235
    DCHECK(has_property_);
236 237
    return property_details_;
  }
238 239 240
  PropertyAttributes property_attributes() const {
    return property_details().attributes();
  }
241
  bool IsConfigurable() const { return property_details().IsConfigurable(); }
242
  bool IsReadOnly() const { return property_details().IsReadOnly(); }
243
  bool IsEnumerable() const { return property_details().IsEnumerable(); }
244 245
  Representation representation() const {
    return property_details().representation();
246
  }
247
  FieldIndex GetFieldIndex() const;
248
  Handle<FieldType> GetFieldType() const;
249
  int GetAccessorIndex() const;
250
  int GetConstantIndex() const;
251
  Handle<PropertyCell> GetPropertyCell() const;
252
  Handle<Object> GetAccessors() const;
253 254 255 256
  inline Handle<InterceptorInfo> GetInterceptor() const {
    DCHECK_EQ(INTERCEPTOR, state_);
    return handle(GetInterceptor(JSObject::cast(*holder_)), isolate_);
  }
257
  Handle<Object> GetDataValue() const;
258
  void WriteDataValue(Handle<Object> value);
259 260

 private:
261 262 263 264 265 266
  enum class InterceptorState {
    kUninitialized,
    kSkipNonMasking,
    kProcessNonMasking
  };

267 268
  Handle<Map> GetReceiverMap() const;

269
  MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);
270
  inline State LookupInHolder(Map* map, JSReceiver* holder);
271 272 273 274
  void RestartLookupForNonMaskingInterceptors() {
    RestartInternal(InterceptorState::kProcessNonMasking);
  }
  void RestartInternal(InterceptorState interceptor_state);
275
  State LookupNonMaskingInterceptorInHolder(Map* map, JSReceiver* holder);
276
  Handle<Object> FetchValue() const;
277
  void ReloadPropertyInformation();
278
  inline bool SkipInterceptor(JSObject* holder);
279
  bool HasInterceptor(Map* map) const;
280 281 282 283
  inline InterceptorInfo* GetInterceptor(JSObject* holder) const {
    if (IsElement()) return holder->GetIndexedInterceptor();
    return holder->GetNamedInterceptor();
  }
284

285 286
  bool check_hidden() const { return (configuration_ & kHidden) != 0; }
  bool check_interceptor() const {
287
    return (configuration_ & kInterceptor) != 0;
288
  }
289
  int descriptor_number() const {
290
    DCHECK(!IsElement());
291
    DCHECK(has_property_);
292
    DCHECK(holder_->HasFastProperties());
293 294 295
    return number_;
  }
  int dictionary_entry() const {
296
    DCHECK(!IsElement());
297
    DCHECK(has_property_);
298
    DCHECK(!holder_->HasFastProperties());
299 300
    return number_;
  }
301

302 303
  static Configuration ComputeConfiguration(
      Configuration configuration, Handle<Name> name) {
304
    if (name->IsPrivate()) {
305 306
      return static_cast<Configuration>(configuration &
                                        HIDDEN_SKIP_INTERCEPTOR);
307 308 309 310 311
    } else {
      return configuration;
    }
  }

312 313 314 315 316 317 318 319 320
  static Handle<JSReceiver> GetRootForNonJSReceiver(
      Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32);
  inline static Handle<JSReceiver> GetRoot(Isolate* isolate,
                                           Handle<Object> receiver,
                                           uint32_t index = kMaxUInt32) {
    if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver);
    return GetRootForNonJSReceiver(isolate, receiver, index);
  }

321
  State NotFound(JSReceiver* const holder) const;
322

323 324
  // If configuration_ becomes mutable, update
  // HolderIsReceiverOrHiddenPrototype.
325
  const Configuration configuration_;
326 327
  State state_;
  bool has_property_;
328
  InterceptorState interceptor_state_;
329
  PropertyDetails property_details_;
330
  Isolate* const isolate_;
331
  Handle<Name> name_;
332
  uint32_t index_;
333
  Handle<Object> transition_;
334
  const Handle<Object> receiver_;
335
  Handle<JSReceiver> holder_;
336
  const Handle<JSReceiver> initial_holder_;
337
  uint32_t number_;
338 339 340
};


341 342
}  // namespace internal
}  // namespace v8
343 344

#endif  // V8_LOOKUP_H_