lookup-inl.h 10.1 KB
Newer Older
1 2 3 4
// 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.

5 6
#ifndef V8_OBJECTS_LOOKUP_INL_H_
#define V8_OBJECTS_LOOKUP_INL_H_
7

8
#include "src/objects/lookup.h"
9

10
#include "src/handles/handles-inl.h"
11
#include "src/heap/factory-inl.h"
12
#include "src/logging/counters.h"
13
#include "src/objects/api-callbacks.h"
14
#include "src/objects/internal-index.h"
15
#include "src/objects/map-inl.h"
16
#include "src/objects/name-inl.h"
17
#include "src/objects/objects-inl.h"
18 19 20 21

namespace v8 {
namespace internal {

22 23
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
                               Handle<Name> name, Configuration configuration)
24 25
    : LookupIterator(isolate, receiver, name, kInvalidIndex, receiver,
                     configuration) {}
26 27

LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
28 29
                               Handle<Name> name,
                               Handle<Object> lookup_start_object,
30
                               Configuration configuration)
31 32
    : LookupIterator(isolate, receiver, name, kInvalidIndex,
                     lookup_start_object, configuration) {}
33

34 35
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
                               size_t index, Configuration configuration)
36 37
    : LookupIterator(isolate, receiver, Handle<Name>(), index, receiver,
                     configuration) {
38 39 40 41
  DCHECK_NE(index, kInvalidIndex);
}

LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
42
                               size_t index, Handle<Object> lookup_start_object,
43
                               Configuration configuration)
44 45
    : LookupIterator(isolate, receiver, Handle<Name>(), index,
                     lookup_start_object, configuration) {
46 47 48 49 50
  DCHECK_NE(index, kInvalidIndex);
}

LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
                               const Key& key, Configuration configuration)
51 52
    : LookupIterator(isolate, receiver, key.name(), key.index(), receiver,
                     configuration) {}
53 54

LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
55 56
                               const Key& key,
                               Handle<Object> lookup_start_object,
57
                               Configuration configuration)
58 59
    : LookupIterator(isolate, receiver, key.name(), key.index(),
                     lookup_start_object, configuration) {}
60

61 62
// This private constructor is the central bottleneck that all the other
// constructors use.
63
LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
64
                               Handle<Name> name, size_t index,
65
                               Handle<Object> lookup_start_object,
66
                               Configuration configuration)
67
    : configuration_(ComputeConfiguration(isolate, configuration, name)),
68
      isolate_(isolate),
69
      name_(name),
70
      receiver_(receiver),
71
      lookup_start_object_(lookup_start_object),
72 73 74 75
      index_(index) {
  if (IsElement()) {
    // If we're not looking at a TypedArray, we will need the key represented
    // as an internalized string.
76 77
    if (index_ > JSArray::kMaxArrayIndex &&
        !lookup_start_object->IsJSTypedArray()) {
78 79 80 81 82 83 84 85 86 87 88
      if (name_.is_null()) {
        name_ = isolate->factory()->SizeToString(index_);
      }
      name_ = isolate->factory()->InternalizeName(name_);
    } else if (!name_.is_null() && !name_->IsInternalizedString()) {
      // Maintain the invariant that if name_ is present, it is internalized.
      name_ = Handle<Name>();
    }
    Start<true>();
  } else {
    name_ = isolate->factory()->InternalizeName(name_);
89
#ifdef DEBUG
90
    // Assert that the name is not an index.
91 92
    // If we're not looking at the prototype chain and the lookup start object
    // is not a typed array, then this means "array index", otherwise we need to
93
    // ensure the full generality so that typed arrays are handled correctly.
94
    if (!check_prototype_chain() && !lookup_start_object->IsJSTypedArray()) {
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
      uint32_t index;
      DCHECK(!name_->AsArrayIndex(&index));
    } else {
      size_t index;
      DCHECK(!name_->AsIntegerIndex(&index));
    }
#endif  // DEBUG
    Start<false>();
  }
}

LookupIterator::Key::Key(Isolate* isolate, double index) {
  DCHECK_EQ(index, static_cast<uint64_t>(index));
#if V8_TARGET_ARCH_32_BIT
  if (index <= JSArray::kMaxArrayIndex) {
    index_ = static_cast<size_t>(index);
111
  } else {
112 113 114 115
    index_ = LookupIterator::kInvalidIndex;
    name_ = isolate->factory()->InternalizeString(
        isolate->factory()->HeapNumberToString(
            isolate->factory()->NewHeapNumber(index), index));
116
  }
117 118 119
#else
  index_ = static_cast<size_t>(index);
#endif
120 121
}

122 123 124 125 126 127 128 129
LookupIterator::Key::Key(Isolate* isolate, Handle<Name> name) {
  if (name->AsIntegerIndex(&index_)) {
    name_ = name;
  } else {
    index_ = LookupIterator::kInvalidIndex;
    name_ = isolate->factory()->InternalizeName(name);
  }
}
130

131 132 133 134 135 136
LookupIterator::Key::Key(Isolate* isolate, Handle<Object> valid_key) {
  DCHECK(valid_key->IsName() || valid_key->IsNumber());
  if (valid_key->ToIntegerIndex(&index_)) return;
  if (valid_key->IsNumber()) {
    // Negative or out of range -> treat as named property.
    valid_key = isolate->factory()->NumberToString(valid_key);
137
  }
138 139 140 141 142
  DCHECK(valid_key->IsName());
  name_ = Handle<Name>::cast(valid_key);
  if (!name_->AsIntegerIndex(&index_)) {
    index_ = LookupIterator::kInvalidIndex;
    name_ = isolate->factory()->InternalizeName(name_);
143 144 145
  }
}

146 147 148 149
Handle<Name> LookupIterator::Key::GetName(Isolate* isolate) {
  if (name_.is_null()) {
    DCHECK(is_element());
    name_ = isolate->factory()->SizeToString(index_);
150
  }
151
  return name_;
152 153
}

154 155 156 157 158
Handle<Name> LookupIterator::name() const {
  DCHECK(!IsElement(*holder_));
  return name_;
}

159 160 161
Handle<Name> LookupIterator::GetName() {
  if (name_.is_null()) {
    DCHECK(IsElement());
162
    name_ = factory()->SizeToString(index_);
163 164 165 166
  }
  return name_;
}

167 168 169 170 171
bool LookupIterator::IsElement(JSReceiver object) const {
  return index_ <= JSArray::kMaxArrayIndex ||
         (index_ != kInvalidIndex && object.map().has_typed_array_elements());
}

172
bool LookupIterator::is_dictionary_holder() const {
173
  return !holder_->HasFastProperties(isolate_);
174 175
}

176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
Handle<Map> LookupIterator::transition_map() const {
  DCHECK_EQ(TRANSITION, state_);
  return Handle<Map>::cast(transition_);
}

Handle<PropertyCell> LookupIterator::transition_cell() const {
  DCHECK_EQ(TRANSITION, state_);
  return Handle<PropertyCell>::cast(transition_);
}

template <class T>
Handle<T> LookupIterator::GetHolder() const {
  DCHECK(IsFound());
  return Handle<T>::cast(holder_);
}

192 193
bool LookupIterator::ExtendingNonExtensible(Handle<JSReceiver> receiver) {
  DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>()));
194 195
  return !receiver->map(isolate_).is_extensible() &&
         (IsElement() || !name_->IsPrivate(isolate_));
196 197 198 199
}

bool LookupIterator::IsCacheableTransition() {
  DCHECK_EQ(TRANSITION, state_);
200
  return transition_->IsPropertyCell(isolate_) ||
201
         (transition_map()->is_dictionary_map() &&
202 203
          !GetStoreTarget<JSReceiver>()->HasFastProperties(isolate_)) ||
         transition_map()->GetBackPointer(isolate_).IsMap(isolate_);
204 205
}

206 207 208
// static
void LookupIterator::UpdateProtector(Isolate* isolate, Handle<Object> receiver,
                                     Handle<Name> name) {
209 210
  RuntimeCallTimerScope scope(isolate, RuntimeCallCounterId::kUpdateProtector);

211 212
  // This list must be kept in sync with
  // CodeStubAssembler::CheckForAssociatedProtector!
213 214 215 216 217 218
  ReadOnlyRoots roots(isolate);
  if (*name == roots.is_concat_spreadable_symbol() ||
      *name == roots.constructor_string() || *name == roots.next_string() ||
      *name == roots.species_symbol() || *name == roots.iterator_symbol() ||
      *name == roots.resolve_string() || *name == roots.then_string()) {
    InternalUpdateProtector(isolate, receiver, name);
219 220 221
  }
}

222 223 224 225 226
void LookupIterator::UpdateProtector() {
  if (IsElement()) return;
  UpdateProtector(isolate_, receiver_, name_);
}

227
InternalIndex LookupIterator::descriptor_number() const {
228
  DCHECK(!IsElement(*holder_));
229
  DCHECK(has_property_);
230
  DCHECK(holder_->HasFastProperties(isolate_));
231
  return number_;
232 233
}

234
InternalIndex LookupIterator::dictionary_entry() const {
235
  DCHECK(!IsElement(*holder_));
236
  DCHECK(has_property_);
237
  DCHECK(!holder_->HasFastProperties(isolate_));
238 239 240
  return number_;
}

241
// static
242
LookupIterator::Configuration LookupIterator::ComputeConfiguration(
243
    Isolate* isolate, Configuration configuration, Handle<Name> name) {
244 245
  return (!name.is_null() && name->IsPrivate(isolate)) ? OWN_SKIP_INTERCEPTOR
                                                       : configuration;
246 247
}

248
// static
249
Handle<JSReceiver> LookupIterator::GetRoot(Isolate* isolate,
250
                                           Handle<Object> lookup_start_object,
251
                                           size_t index) {
252 253
  if (lookup_start_object->IsJSReceiver(isolate)) {
    return Handle<JSReceiver>::cast(lookup_start_object);
254
  }
255
  return GetRootForNonJSReceiver(isolate, lookup_start_object, index);
256 257
}

258 259
template <class T>
Handle<T> LookupIterator::GetStoreTarget() const {
260 261 262 263 264
  DCHECK(receiver_->IsJSReceiver(isolate_));
  if (receiver_->IsJSGlobalProxy(isolate_)) {
    HeapObject prototype =
        JSGlobalProxy::cast(*receiver_).map(isolate_).prototype(isolate_);
    if (prototype.IsJSGlobalObject(isolate_)) {
265
      return handle(JSGlobalObject::cast(prototype), isolate_);
266 267 268 269
    }
  }
  return Handle<T>::cast(receiver_);
}
270 271

template <bool is_element>
272 273 274 275 276 277
InterceptorInfo LookupIterator::GetInterceptor(JSObject holder) const {
  if (is_element && index_ <= JSArray::kMaxArrayIndex) {
    return holder.GetIndexedInterceptor(isolate_);
  } else {
    return holder.GetNamedInterceptor(isolate_);
  }
278 279
}

280 281
inline Handle<InterceptorInfo> LookupIterator::GetInterceptor() const {
  DCHECK_EQ(INTERCEPTOR, state_);
282
  JSObject holder = JSObject::cast(*holder_);
283 284
  InterceptorInfo result = IsElement(holder) ? GetInterceptor<true>(holder)
                                             : GetInterceptor<false>(holder);
285 286 287 288 289 290
  return handle(result, isolate_);
}

}  // namespace internal
}  // namespace v8

291
#endif  // V8_OBJECTS_LOOKUP_INL_H_