blob: 8e545f747904be31b389eb1c8f11e5b161b8f545 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2014 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/lookup.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006
7#include "src/bootstrapper.h"
8#include "src/deoptimizer.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/elements.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010010#include "src/field-type.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/isolate-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012
13namespace v8 {
14namespace internal {
15
16
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017// static
18LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate,
19 Handle<Object> receiver,
20 Handle<Object> key,
21 bool* success,
22 Configuration configuration) {
23 uint32_t index = 0;
24 if (key->ToArrayIndex(&index)) {
25 *success = true;
26 return LookupIterator(isolate, receiver, index, configuration);
27 }
28
29 Handle<Name> name;
30 *success = Object::ToName(isolate, key).ToHandle(&name);
31 if (!*success) {
32 DCHECK(isolate->has_pending_exception());
33 // Return an unusable dummy.
34 return LookupIterator(receiver, isolate->factory()->empty_string());
35 }
36
37 if (name->AsArrayIndex(&index)) {
38 LookupIterator it(isolate, receiver, index, configuration);
39 // Here we try to avoid having to rebuild the string later
40 // by storing it on the indexed LookupIterator.
41 it.name_ = name;
42 return it;
43 }
44
45 return LookupIterator(receiver, name, configuration);
46}
47
Ben Murdochda12d292016-06-02 14:46:10 +010048template <bool is_element>
49void LookupIterator::Start() {
50 DisallowHeapAllocation no_gc;
51
52 has_property_ = false;
53 state_ = NOT_FOUND;
54 holder_ = initial_holder_;
55
56 JSReceiver* holder = *holder_;
57 Map* map = holder->map();
58
59 state_ = LookupInHolder<is_element>(map, holder);
60 if (IsFound()) return;
61
62 NextInternal<is_element>(map, holder);
63}
64
65template void LookupIterator::Start<true>();
66template void LookupIterator::Start<false>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067
Ben Murdochb8a8cc12014-11-26 15:28:44 +000068void LookupIterator::Next() {
69 DCHECK_NE(JSPROXY, state_);
70 DCHECK_NE(TRANSITION, state_);
71 DisallowHeapAllocation no_gc;
72 has_property_ = false;
73
74 JSReceiver* holder = *holder_;
Ben Murdoch097c5b22016-05-18 11:27:45 +010075 Map* map = holder->map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000076
Ben Murdochda12d292016-06-02 14:46:10 +010077 if (map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) {
78 state_ = IsElement() ? LookupInSpecialHolder<true>(map, holder)
79 : LookupInSpecialHolder<false>(map, holder);
80 if (IsFound()) return;
81 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082
Ben Murdochda12d292016-06-02 14:46:10 +010083 IsElement() ? NextInternal<true>(map, holder)
84 : NextInternal<false>(map, holder);
85}
86
87template <bool is_element>
88void LookupIterator::NextInternal(Map* map, JSReceiver* holder) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089 do {
90 JSReceiver* maybe_holder = NextHolder(map);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000091 if (maybe_holder == nullptr) {
92 if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
Ben Murdochda12d292016-06-02 14:46:10 +010093 RestartLookupForNonMaskingInterceptors<is_element>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000094 return;
95 }
Ben Murdochda12d292016-06-02 14:46:10 +010096 state_ = NOT_FOUND;
97 if (holder != *holder_) holder_ = handle(holder, isolate_);
98 return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 holder = maybe_holder;
101 map = holder->map();
Ben Murdochda12d292016-06-02 14:46:10 +0100102 state_ = LookupInHolder<is_element>(map, holder);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 } while (!IsFound());
104
Ben Murdochda12d292016-06-02 14:46:10 +0100105 holder_ = handle(holder, isolate_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106}
107
Ben Murdochda12d292016-06-02 14:46:10 +0100108template <bool is_element>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110 interceptor_state_ = interceptor_state;
111 property_details_ = PropertyDetails::Empty();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112 number_ = DescriptorArray::kNotFound;
Ben Murdochda12d292016-06-02 14:46:10 +0100113 Start<is_element>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000114}
115
Ben Murdochda12d292016-06-02 14:46:10 +0100116template void LookupIterator::RestartInternal<true>(InterceptorState);
117template void LookupIterator::RestartInternal<false>(InterceptorState);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000118
119// static
120Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
121 Isolate* isolate, Handle<Object> receiver, uint32_t index) {
122 // Strings are the only objects with properties (only elements) directly on
123 // the wrapper. Hence we can skip generating the wrapper for all other cases.
124 if (index != kMaxUInt32 && receiver->IsString() &&
125 index < static_cast<uint32_t>(String::cast(*receiver)->length())) {
126 // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native
127 // context, ensuring that we don't leak it into JS?
128 Handle<JSFunction> constructor = isolate->string_function();
129 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
130 Handle<JSValue>::cast(result)->set_value(*receiver);
131 return result;
132 }
133 auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100134 if (root->IsNull(isolate)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000135 unsigned int magic = 0xbbbbbbbb;
136 isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic);
137 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000138 return Handle<JSReceiver>::cast(root);
139}
140
141
142Handle<Map> LookupIterator::GetReceiverMap() const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 if (receiver_->IsNumber()) return factory()->heap_number_map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_);
145}
146
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000147bool LookupIterator::HasAccess() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 DCHECK_EQ(ACCESS_CHECK, state_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 return isolate_->MayAccess(handle(isolate_->context()),
150 GetHolder<JSObject>());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000151}
152
Ben Murdochda12d292016-06-02 14:46:10 +0100153template <bool is_element>
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000154void LookupIterator::ReloadPropertyInformation() {
155 state_ = BEFORE_PROPERTY;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000156 interceptor_state_ = InterceptorState::kUninitialized;
Ben Murdochda12d292016-06-02 14:46:10 +0100157 state_ = LookupInHolder<is_element>(holder_->map(), *holder_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100158 DCHECK(IsFound() || !holder_->HasFastProperties());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159}
160
Ben Murdochda12d292016-06-02 14:46:10 +0100161void LookupIterator::InternalUpdateProtector() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100162 if (isolate_->bootstrapper()->IsActive()) return;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100163
Ben Murdochda12d292016-06-02 14:46:10 +0100164 if (*name_ == heap()->constructor_string()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100165 if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100166 // Setting the constructor property could change an instance's @@species
167 if (holder_->IsJSArray()) {
168 isolate_->CountUsage(
169 v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
170 isolate_->InvalidateArraySpeciesProtector();
171 } else if (holder_->map()->is_prototype_map()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100172 DisallowHeapAllocation no_gc;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100173 // Setting the constructor of Array.prototype of any realm also needs
174 // to invalidate the species protector
Ben Murdochc5610432016-08-08 18:44:38 +0100175 if (isolate_->IsInAnyContext(*holder_,
176 Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100177 isolate_->CountUsage(v8::Isolate::UseCounterFeature::
178 kArrayPrototypeConstructorModified);
179 isolate_->InvalidateArraySpeciesProtector();
180 }
181 }
Ben Murdochda12d292016-06-02 14:46:10 +0100182 } else if (*name_ == heap()->species_symbol()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100183 if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100184 // Setting the Symbol.species property of any Array constructor invalidates
185 // the species protector
Ben Murdochc5610432016-08-08 18:44:38 +0100186 if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100187 isolate_->CountUsage(
188 v8::Isolate::UseCounterFeature::kArraySpeciesModified);
189 isolate_->InvalidateArraySpeciesProtector();
190 }
Ben Murdochc5610432016-08-08 18:44:38 +0100191 } else if (*name_ == heap()->is_concat_spreadable_symbol()) {
192 if (!isolate_->IsIsConcatSpreadableLookupChainIntact()) return;
193 isolate_->InvalidateIsConcatSpreadableProtector();
194 } else if (*name_ == heap()->has_instance_symbol()) {
195 if (!isolate_->IsHasInstanceLookupChainIntact()) return;
196 isolate_->InvalidateHasInstanceProtector();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197 }
198}
199
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000200void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
201 DCHECK(state_ == DATA || state_ == ACCESSOR);
202 DCHECK(HolderIsReceiverOrHiddenPrototype());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203
204 Handle<JSObject> holder = GetHolder<JSObject>();
205
206 if (IsElement()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100207 ElementsKind kind = holder->GetElementsKind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208 ElementsKind to = value->OptimalElementsKind();
209 if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to);
210 to = GetMoreGeneralElementsKind(kind, to);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100211
212 if (kind != to) {
213 JSObject::TransitionElementsKind(holder, to);
214 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215
216 // Copy the backing store if it is copy-on-write.
217 if (IsFastSmiOrObjectElementsKind(to)) {
218 JSObject::EnsureWritableFastElements(holder);
219 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100220 return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 }
222
Ben Murdoch097c5b22016-05-18 11:27:45 +0100223 if (!holder->HasFastProperties()) return;
224
225 Handle<Map> old_map(holder->map(), isolate_);
226 Handle<Map> new_map =
227 Map::PrepareForDataProperty(old_map, descriptor_number(), value);
228
229 if (old_map.is_identical_to(new_map)) {
230 // Update the property details if the representation was None.
231 if (representation().IsNone()) {
232 property_details_ =
233 new_map->instance_descriptors()->GetDetails(descriptor_number());
234 }
235 return;
236 }
237
238 JSObject::MigrateToMap(holder, new_map);
Ben Murdochda12d292016-06-02 14:46:10 +0100239 ReloadPropertyInformation<false>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000240}
241
242
243void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
244 PropertyAttributes attributes) {
245 DCHECK(state_ == DATA || state_ == ACCESSOR);
246 DCHECK(HolderIsReceiverOrHiddenPrototype());
247 Handle<JSObject> holder = GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000248 if (IsElement()) {
249 DCHECK(!holder->HasFixedTypedArrayElements());
250 DCHECK(attributes != NONE || !holder->HasFastElements());
251 Handle<FixedArrayBase> elements(holder->elements());
252 holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value,
253 attributes);
Ben Murdochda12d292016-06-02 14:46:10 +0100254 ReloadPropertyInformation<true>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100256 if (!holder->HasFastProperties()) {
257 PropertyDetails details(attributes, v8::internal::DATA, 0,
258 PropertyCellType::kMutable);
259 JSObject::SetNormalizedProperty(holder, name(), value, details);
260 } else {
261 Handle<Map> old_map(holder->map(), isolate_);
262 Handle<Map> new_map = Map::ReconfigureExistingProperty(
263 old_map, descriptor_number(), i::kData, attributes);
264 new_map =
265 Map::PrepareForDataProperty(new_map, descriptor_number(), value);
266 JSObject::MigrateToMap(holder, new_map);
267 }
268 ReloadPropertyInformation<false>();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000269 }
270
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000271 WriteDataValue(value);
272
273#if VERIFY_HEAP
274 if (FLAG_verify_heap) {
275 holder->JSObjectVerify();
276 }
277#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278}
279
Ben Murdoch097c5b22016-05-18 11:27:45 +0100280// Can only be called when the receiver is a JSObject. JSProxy has to be handled
281// via a trap. Adding properties to primitive values is not observable.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000282void LookupIterator::PrepareTransitionToDataProperty(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100283 Handle<JSObject> receiver, Handle<Object> value,
284 PropertyAttributes attributes, Object::StoreFromKeyed store_mode) {
285 DCHECK(receiver.is_identical_to(GetStoreTarget()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 if (state_ == TRANSITION) return;
287 DCHECK(state_ != LookupIterator::ACCESSOR ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 (GetAccessors()->IsAccessorInfo() &&
289 AccessorInfo::cast(*GetAccessors())->is_special_data_property()));
290 DCHECK_NE(INTEGER_INDEXED_EXOTIC, state_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000291 DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292
Ben Murdoch097c5b22016-05-18 11:27:45 +0100293 Handle<Map> map(receiver->map(), isolate_);
294
295 // Dictionary maps can always have additional data properties.
296 if (map->is_dictionary_map()) {
297 state_ = TRANSITION;
298 if (map->IsJSGlobalObjectMap()) {
299 // Install a property cell.
300 auto cell = JSGlobalObject::EnsurePropertyCell(
301 Handle<JSGlobalObject>::cast(receiver), name());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100302 DCHECK(cell->value()->IsTheHole(isolate_));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100303 transition_ = cell;
304 } else {
305 transition_ = map;
306 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000307 return;
308 }
309
Ben Murdoch097c5b22016-05-18 11:27:45 +0100310 Handle<Map> transition =
311 Map::TransitionToDataProperty(map, name_, value, attributes, store_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000312 state_ = TRANSITION;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000313 transition_ = transition;
314
Ben Murdoch097c5b22016-05-18 11:27:45 +0100315 if (!transition->is_dictionary_map()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000316 property_details_ = transition->GetLastDescriptorDetails();
317 has_property_ = true;
318 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000319}
320
Ben Murdoch097c5b22016-05-18 11:27:45 +0100321void LookupIterator::ApplyTransitionToDataProperty(Handle<JSObject> receiver) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000322 DCHECK_EQ(TRANSITION, state_);
323
Ben Murdoch097c5b22016-05-18 11:27:45 +0100324 DCHECK(receiver.is_identical_to(GetStoreTarget()));
325
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000326 if (receiver->IsJSGlobalObject()) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000327 holder_ = receiver;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100328 Handle<Map> transition = transition_map();
329 bool simple_transition = transition->GetBackPointer() == receiver->map();
330 JSObject::MigrateToMap(receiver, transition);
331
332 if (simple_transition) {
333 int number = transition->LastAdded();
334 number_ = static_cast<uint32_t>(number);
335 property_details_ = transition->GetLastDescriptorDetails();
336 state_ = DATA;
337 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100338 ReloadPropertyInformation<false>();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100339 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000340}
341
342
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343void LookupIterator::Delete() {
344 Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_);
345 if (IsElement()) {
346 Handle<JSObject> object = Handle<JSObject>::cast(holder);
347 ElementsAccessor* accessor = object->GetElementsAccessor();
348 accessor->Delete(object, number_);
349 } else {
Ben Murdochc5610432016-08-08 18:44:38 +0100350 bool is_prototype_map = holder->map()->is_prototype_map();
351 RuntimeCallTimerScope stats_scope(
352 isolate_, is_prototype_map
353 ? &RuntimeCallStats::PrototypeObject_DeleteProperty
354 : &RuntimeCallStats::Object_DeleteProperty);
355
356 PropertyNormalizationMode mode =
357 is_prototype_map ? KEEP_INOBJECT_PROPERTIES : CLEAR_INOBJECT_PROPERTIES;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000358
359 if (holder->HasFastProperties()) {
360 JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0,
361 "DeletingProperty");
Ben Murdochda12d292016-06-02 14:46:10 +0100362 ReloadPropertyInformation<false>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000363 }
364 // TODO(verwaest): Get rid of the name_ argument.
365 JSReceiver::DeleteNormalizedProperty(holder, name_, number_);
366 if (holder->IsJSObject()) {
367 JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder));
368 }
369 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100370 state_ = NOT_FOUND;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000371}
372
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000373void LookupIterator::TransitionToAccessorProperty(
Ben Murdochc5610432016-08-08 18:44:38 +0100374 Handle<Object> getter, Handle<Object> setter,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000375 PropertyAttributes attributes) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100376 DCHECK(!getter->IsNull(isolate_) || !setter->IsNull(isolate_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000377 // Can only be called when the receiver is a JSObject. JSProxy has to be
378 // handled via a trap. Adding properties to primitive values is not
379 // observable.
380 Handle<JSObject> receiver = GetStoreTarget();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000381
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000382 if (!IsElement() && !receiver->map()->is_dictionary_map()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100383 Handle<Map> old_map(receiver->map(), isolate_);
Ben Murdochda12d292016-06-02 14:46:10 +0100384
385 if (!holder_.is_identical_to(receiver)) {
386 holder_ = receiver;
387 state_ = NOT_FOUND;
388 } else if (state_ == INTERCEPTOR) {
389 LookupInRegularHolder<false>(*old_map, *holder_);
390 }
391 int descriptor =
392 IsFound() ? static_cast<int>(number_) : DescriptorArray::kNotFound;
393
Ben Murdoch097c5b22016-05-18 11:27:45 +0100394 Handle<Map> new_map = Map::TransitionToAccessorProperty(
Ben Murdochc5610432016-08-08 18:44:38 +0100395 isolate_, old_map, name_, descriptor, getter, setter, attributes);
Ben Murdochda12d292016-06-02 14:46:10 +0100396 bool simple_transition = new_map->GetBackPointer() == receiver->map();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100397 JSObject::MigrateToMap(receiver, new_map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000398
Ben Murdochda12d292016-06-02 14:46:10 +0100399 if (simple_transition) {
400 int number = new_map->LastAdded();
401 number_ = static_cast<uint32_t>(number);
402 property_details_ = new_map->GetLastDescriptorDetails();
403 state_ = ACCESSOR;
404 return;
405 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000406
Ben Murdochda12d292016-06-02 14:46:10 +0100407 ReloadPropertyInformation<false>();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100408 if (!new_map->is_dictionary_map()) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000409 }
410
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000411 Handle<AccessorPair> pair;
412 if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) {
413 pair = Handle<AccessorPair>::cast(GetAccessors());
414 // If the component and attributes are identical, nothing has to be done.
Ben Murdochc5610432016-08-08 18:44:38 +0100415 if (pair->Equals(*getter, *setter)) {
416 if (property_details().attributes() == attributes) {
417 if (!IsElement()) JSObject::ReoptimizeIfPrototype(receiver);
418 return;
419 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000420 } else {
421 pair = AccessorPair::Copy(pair);
Ben Murdochc5610432016-08-08 18:44:38 +0100422 pair->SetComponents(*getter, *setter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000423 }
424 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000425 pair = factory()->NewAccessorPair();
Ben Murdochc5610432016-08-08 18:44:38 +0100426 pair->SetComponents(*getter, *setter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000427 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000428
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000429 TransitionToAccessorPair(pair, attributes);
430
431#if VERIFY_HEAP
432 if (FLAG_verify_heap) {
433 receiver->JSObjectVerify();
434 }
435#endif
436}
437
438
439void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
440 PropertyAttributes attributes) {
441 Handle<JSObject> receiver = GetStoreTarget();
442 holder_ = receiver;
443
444 PropertyDetails details(attributes, ACCESSOR_CONSTANT, 0,
445 PropertyCellType::kMutable);
446
447 if (IsElement()) {
448 // TODO(verwaest): Move code into the element accessor.
449 Handle<SeededNumberDictionary> dictionary =
450 JSObject::NormalizeElements(receiver);
451
452 // We unconditionally pass used_as_prototype=false here because the call
453 // to RequireSlowElements takes care of the required IC clearing and
454 // we don't want to walk the heap twice.
455 dictionary =
456 SeededNumberDictionary::Set(dictionary, index_, pair, details, false);
457 receiver->RequireSlowElements(*dictionary);
458
459 if (receiver->HasSlowArgumentsElements()) {
460 FixedArray* parameter_map = FixedArray::cast(receiver->elements());
461 uint32_t length = parameter_map->length() - 2;
462 if (number_ < length) {
463 parameter_map->set(number_ + 2, heap()->the_hole_value());
464 }
465 FixedArray::cast(receiver->elements())->set(1, *dictionary);
466 } else {
467 receiver->set_elements(*dictionary);
468 }
Ben Murdochda12d292016-06-02 14:46:10 +0100469
470 ReloadPropertyInformation<true>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000471 } else {
472 PropertyNormalizationMode mode = receiver->map()->is_prototype_map()
473 ? KEEP_INOBJECT_PROPERTIES
474 : CLEAR_INOBJECT_PROPERTIES;
475 // Normalize object to make this operation simple.
476 JSObject::NormalizeProperties(receiver, mode, 0,
477 "TransitionToAccessorPair");
478
479 JSObject::SetNormalizedProperty(receiver, name_, pair, details);
480 JSObject::ReoptimizeIfPrototype(receiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481
Ben Murdochda12d292016-06-02 14:46:10 +0100482 ReloadPropertyInformation<false>();
483 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000484}
485
486
487bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
488 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
489 // Optimization that only works if configuration_ is not mutable.
490 if (!check_prototype_chain()) return true;
491 DisallowHeapAllocation no_gc;
Ben Murdochda12d292016-06-02 14:46:10 +0100492 if (*receiver_ == *holder_) return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000493 if (!receiver_->IsJSReceiver()) return false;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100494 JSReceiver* current = JSReceiver::cast(*receiver_);
495 JSReceiver* object = *holder_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100496 if (!current->map()->has_hidden_prototype()) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000497 // JSProxy do not occur as hidden prototypes.
Ben Murdochda12d292016-06-02 14:46:10 +0100498 if (object->IsJSProxy()) return false;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100499 PrototypeIterator iter(isolate(), current, kStartAtPrototype,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100500 PrototypeIterator::END_AT_NON_HIDDEN);
501 while (!iter.IsAtEnd()) {
502 if (iter.GetCurrent<JSReceiver>() == object) return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000503 iter.Advance();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100504 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000505 return false;
506}
507
508
509Handle<Object> LookupIterator::FetchValue() const {
510 Object* result = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000511 if (IsElement()) {
512 Handle<JSObject> holder = GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000513 ElementsAccessor* accessor = holder->GetElementsAccessor();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100514 return accessor->Get(holder, number_);
515 } else if (holder_->IsJSGlobalObject()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000516 Handle<JSObject> holder = GetHolder<JSObject>();
517 result = holder->global_dictionary()->ValueAt(number_);
518 DCHECK(result->IsPropertyCell());
519 result = PropertyCell::cast(result)->value();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100520 } else if (!holder_->HasFastProperties()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000521 result = holder_->property_dictionary()->ValueAt(number_);
522 } else if (property_details_.type() == v8::internal::DATA) {
523 Handle<JSObject> holder = GetHolder<JSObject>();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100524 FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000525 return JSObject::FastPropertyAt(holder, property_details_.representation(),
526 field_index);
527 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100528 result = holder_->map()->instance_descriptors()->GetValue(number_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529 }
530 return handle(result, isolate_);
531}
532
533
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000534int LookupIterator::GetAccessorIndex() const {
535 DCHECK(has_property_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100536 DCHECK(holder_->HasFastProperties());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000537 DCHECK_EQ(v8::internal::ACCESSOR_CONSTANT, property_details_.type());
538 return descriptor_number();
539}
540
541
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000542int LookupIterator::GetConstantIndex() const {
543 DCHECK(has_property_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100544 DCHECK(holder_->HasFastProperties());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000545 DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type());
546 DCHECK(!IsElement());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000547 return descriptor_number();
548}
549
550
551FieldIndex LookupIterator::GetFieldIndex() const {
552 DCHECK(has_property_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100553 DCHECK(holder_->HasFastProperties());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000554 DCHECK_EQ(v8::internal::DATA, property_details_.type());
555 DCHECK(!IsElement());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100556 Map* holder_map = holder_->map();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000557 int index =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100558 holder_map->instance_descriptors()->GetFieldIndex(descriptor_number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000559 bool is_double = representation().IsDouble();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100560 return FieldIndex::ForPropertyIndex(holder_map, index, is_double);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561}
562
Ben Murdoch097c5b22016-05-18 11:27:45 +0100563Handle<FieldType> LookupIterator::GetFieldType() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000564 DCHECK(has_property_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100565 DCHECK(holder_->HasFastProperties());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000566 DCHECK_EQ(v8::internal::DATA, property_details_.type());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000567 return handle(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100568 holder_->map()->instance_descriptors()->GetFieldType(descriptor_number()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000569 isolate_);
570}
571
572
573Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000574 DCHECK(!IsElement());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575 Handle<JSObject> holder = GetHolder<JSObject>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000576 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder);
577 Object* value = global->global_dictionary()->ValueAt(dictionary_entry());
578 DCHECK(value->IsPropertyCell());
579 return handle(PropertyCell::cast(value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000580}
581
582
583Handle<Object> LookupIterator::GetAccessors() const {
584 DCHECK_EQ(ACCESSOR, state_);
585 return FetchValue();
586}
587
588
589Handle<Object> LookupIterator::GetDataValue() const {
590 DCHECK_EQ(DATA, state_);
591 Handle<Object> value = FetchValue();
592 return value;
593}
594
595
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000596void LookupIterator::WriteDataValue(Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000597 DCHECK_EQ(DATA, state_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000598 Handle<JSReceiver> holder = GetHolder<JSReceiver>();
599 if (IsElement()) {
600 Handle<JSObject> object = Handle<JSObject>::cast(holder);
601 ElementsAccessor* accessor = object->GetElementsAccessor();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100602 accessor->Set(object, number_, *value);
603 } else if (holder->HasFastProperties()) {
604 if (property_details_.type() == v8::internal::DATA) {
605 JSObject::cast(*holder)->WriteToField(descriptor_number(),
606 property_details_, *value);
607 } else {
608 DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type());
609 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000610 } else if (holder->IsJSGlobalObject()) {
611 Handle<GlobalDictionary> property_dictionary =
612 handle(JSObject::cast(*holder)->global_dictionary());
613 PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value,
614 property_details_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100615 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000616 NameDictionary* property_dictionary = holder->property_dictionary();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000617 property_dictionary->ValueAtPut(dictionary_entry(), *value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000618 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400619}
620
Ben Murdochda12d292016-06-02 14:46:10 +0100621template <bool is_element>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000622bool LookupIterator::SkipInterceptor(JSObject* holder) {
Ben Murdochda12d292016-06-02 14:46:10 +0100623 auto info = GetInterceptor<is_element>(holder);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000624 // TODO(dcarney): check for symbol/can_intercept_symbols here as well.
625 if (info->non_masking()) {
626 switch (interceptor_state_) {
627 case InterceptorState::kUninitialized:
628 interceptor_state_ = InterceptorState::kSkipNonMasking;
629 // Fall through.
630 case InterceptorState::kSkipNonMasking:
631 return true;
632 case InterceptorState::kProcessNonMasking:
633 return false;
634 }
635 }
636 return interceptor_state_ == InterceptorState::kProcessNonMasking;
637}
638
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000639JSReceiver* LookupIterator::NextHolder(Map* map) {
640 DisallowHeapAllocation no_gc;
Ben Murdochda12d292016-06-02 14:46:10 +0100641 if (map->prototype() == heap()->null_value()) return NULL;
Ben Murdochc5610432016-08-08 18:44:38 +0100642 if (!check_prototype_chain() && !map->has_hidden_prototype()) return NULL;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100643 return JSReceiver::cast(map->prototype());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000644}
645
Ben Murdoch097c5b22016-05-18 11:27:45 +0100646LookupIterator::State LookupIterator::NotFound(JSReceiver* const holder) const {
647 DCHECK(!IsElement());
648 if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND;
649
650 Handle<String> name_string = Handle<String>::cast(name_);
651 if (name_string->length() == 0) return NOT_FOUND;
652
653 return IsSpecialIndex(isolate_->unicode_cache(), *name_string)
654 ? INTEGER_INDEXED_EXOTIC
655 : NOT_FOUND;
656}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000657
Ben Murdochda12d292016-06-02 14:46:10 +0100658namespace {
659
660template <bool is_element>
661bool HasInterceptor(Map* map) {
662 return is_element ? map->has_indexed_interceptor()
663 : map->has_named_interceptor();
664}
665
666} // namespace
667
668template <bool is_element>
669LookupIterator::State LookupIterator::LookupInSpecialHolder(
670 Map* const map, JSReceiver* const holder) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000671 STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000672 switch (state_) {
673 case NOT_FOUND:
674 if (map->IsJSProxyMap()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100675 if (is_element || !name_->IsPrivate()) return JSPROXY;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000676 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100677 if (map->is_access_check_needed()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100678 if (is_element || !name_->IsPrivate()) return ACCESS_CHECK;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000679 }
680 // Fall through.
681 case ACCESS_CHECK:
Ben Murdochda12d292016-06-02 14:46:10 +0100682 if (check_interceptor() && HasInterceptor<is_element>(map) &&
683 !SkipInterceptor<is_element>(JSObject::cast(holder))) {
684 if (is_element || !name_->IsPrivate()) return INTERCEPTOR;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000685 }
686 // Fall through.
687 case INTERCEPTOR:
Ben Murdochda12d292016-06-02 14:46:10 +0100688 if (!is_element && map->IsJSGlobalObjectMap()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000689 GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary();
690 int number = dict->FindEntry(name_);
691 if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
692 number_ = static_cast<uint32_t>(number);
693 DCHECK(dict->ValueAt(number_)->IsPropertyCell());
694 PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100695 if (cell->value()->IsTheHole(isolate_)) return NOT_FOUND;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000696 property_details_ = cell->property_details();
Ben Murdochda12d292016-06-02 14:46:10 +0100697 has_property_ = true;
698 switch (property_details_.kind()) {
699 case v8::internal::kData:
700 return DATA;
701 case v8::internal::kAccessor:
702 return ACCESSOR;
703 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000704 }
Ben Murdochda12d292016-06-02 14:46:10 +0100705 return LookupInRegularHolder<is_element>(map, holder);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000706 case ACCESSOR:
707 case DATA:
708 return NOT_FOUND;
709 case INTEGER_INDEXED_EXOTIC:
710 case JSPROXY:
711 case TRANSITION:
712 UNREACHABLE();
713 }
714 UNREACHABLE();
Ben Murdochda12d292016-06-02 14:46:10 +0100715 return NOT_FOUND;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000716}
717
Ben Murdochda12d292016-06-02 14:46:10 +0100718template <bool is_element>
719LookupIterator::State LookupIterator::LookupInRegularHolder(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000720 Map* const map, JSReceiver* const holder) {
Ben Murdochda12d292016-06-02 14:46:10 +0100721 DisallowHeapAllocation no_gc;
722 if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
723 return NOT_FOUND;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000724 }
Ben Murdochda12d292016-06-02 14:46:10 +0100725
726 if (is_element) {
727 JSObject* js_object = JSObject::cast(holder);
728 ElementsAccessor* accessor = js_object->GetElementsAccessor();
729 FixedArrayBase* backing_store = js_object->elements();
730 number_ = accessor->GetEntryForIndex(js_object, backing_store, index_);
731 if (number_ == kMaxUInt32) {
732 return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND;
733 }
734 property_details_ = accessor->GetDetails(js_object, number_);
735 } else if (!map->is_dictionary_map()) {
736 DescriptorArray* descriptors = map->instance_descriptors();
737 int number = descriptors->SearchWithCache(isolate_, *name_, map);
738 if (number == DescriptorArray::kNotFound) return NotFound(holder);
739 number_ = static_cast<uint32_t>(number);
740 property_details_ = descriptors->GetDetails(number_);
741 } else {
742 NameDictionary* dict = holder->property_dictionary();
743 int number = dict->FindEntry(name_);
744 if (number == NameDictionary::kNotFound) return NotFound(holder);
745 number_ = static_cast<uint32_t>(number);
746 property_details_ = dict->DetailsAt(number_);
747 }
748 has_property_ = true;
749 switch (property_details_.kind()) {
750 case v8::internal::kData:
751 return DATA;
752 case v8::internal::kAccessor:
753 return ACCESSOR;
754 }
755
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000756 UNREACHABLE();
757 return state_;
758}
759
Ben Murdoch61f157c2016-09-16 13:49:30 +0100760Handle<InterceptorInfo> LookupIterator::GetInterceptorForFailedAccessCheck()
761 const {
762 DCHECK_EQ(ACCESS_CHECK, state_);
763 DisallowHeapAllocation no_gc;
764 AccessCheckInfo* access_check_info =
765 AccessCheckInfo::Get(isolate_, Handle<JSObject>::cast(holder_));
766 if (access_check_info) {
767 Object* interceptor = IsElement() ? access_check_info->indexed_interceptor()
768 : access_check_info->named_interceptor();
769 if (interceptor) {
770 return handle(InterceptorInfo::cast(interceptor), isolate_);
771 }
772 }
773 return Handle<InterceptorInfo>();
774}
775
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000776} // namespace internal
777} // namespace v8