Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 1 | // 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 5 | #include "src/lookup.h" |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 6 | |
| 7 | #include "src/bootstrapper.h" |
| 8 | #include "src/deoptimizer.h" |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 9 | #include "src/elements.h" |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 10 | #include "src/field-type.h" |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 11 | #include "src/isolate-inl.h" |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 12 | |
| 13 | namespace v8 { |
| 14 | namespace internal { |
| 15 | |
| 16 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 17 | // static |
| 18 | LookupIterator 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 Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 48 | template <bool is_element> |
| 49 | void 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 | |
| 65 | template void LookupIterator::Start<true>(); |
| 66 | template void LookupIterator::Start<false>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 67 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 68 | void 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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 75 | Map* map = holder->map(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 76 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 77 | 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 Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 82 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 83 | IsElement() ? NextInternal<true>(map, holder) |
| 84 | : NextInternal<false>(map, holder); |
| 85 | } |
| 86 | |
| 87 | template <bool is_element> |
| 88 | void LookupIterator::NextInternal(Map* map, JSReceiver* holder) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 89 | do { |
| 90 | JSReceiver* maybe_holder = NextHolder(map); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 91 | if (maybe_holder == nullptr) { |
| 92 | if (interceptor_state_ == InterceptorState::kSkipNonMasking) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 93 | RestartLookupForNonMaskingInterceptors<is_element>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 94 | return; |
| 95 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 96 | state_ = NOT_FOUND; |
| 97 | if (holder != *holder_) holder_ = handle(holder, isolate_); |
| 98 | return; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 99 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 100 | holder = maybe_holder; |
| 101 | map = holder->map(); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 102 | state_ = LookupInHolder<is_element>(map, holder); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 103 | } while (!IsFound()); |
| 104 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 105 | holder_ = handle(holder, isolate_); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 106 | } |
| 107 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 108 | template <bool is_element> |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 109 | void LookupIterator::RestartInternal(InterceptorState interceptor_state) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 110 | interceptor_state_ = interceptor_state; |
| 111 | property_details_ = PropertyDetails::Empty(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 112 | number_ = DescriptorArray::kNotFound; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 113 | Start<is_element>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 114 | } |
| 115 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 116 | template void LookupIterator::RestartInternal<true>(InterceptorState); |
| 117 | template void LookupIterator::RestartInternal<false>(InterceptorState); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 118 | |
| 119 | // static |
| 120 | Handle<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); |
| 134 | if (root->IsNull()) { |
| 135 | unsigned int magic = 0xbbbbbbbb; |
| 136 | isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic); |
| 137 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 138 | return Handle<JSReceiver>::cast(root); |
| 139 | } |
| 140 | |
| 141 | |
| 142 | Handle<Map> LookupIterator::GetReceiverMap() const { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 143 | if (receiver_->IsNumber()) return factory()->heap_number_map(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 144 | return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_); |
| 145 | } |
| 146 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 147 | bool LookupIterator::HasAccess() const { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 148 | DCHECK_EQ(ACCESS_CHECK, state_); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 149 | return isolate_->MayAccess(handle(isolate_->context()), |
| 150 | GetHolder<JSObject>()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 151 | } |
| 152 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 153 | template <bool is_element> |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 154 | void LookupIterator::ReloadPropertyInformation() { |
| 155 | state_ = BEFORE_PROPERTY; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 156 | interceptor_state_ = InterceptorState::kUninitialized; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 157 | state_ = LookupInHolder<is_element>(holder_->map(), *holder_); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 158 | DCHECK(IsFound() || !holder_->HasFastProperties()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 159 | } |
| 160 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 161 | void LookupIterator::InternalUpdateProtector() { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 162 | if (isolate_->bootstrapper()->IsActive()) return; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 163 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 164 | if (*name_ == heap()->constructor_string()) { |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 165 | if (!isolate_->IsArraySpeciesLookupChainIntact()) return; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 166 | // 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 Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 172 | DisallowHeapAllocation no_gc; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 173 | // Setting the constructor of Array.prototype of any realm also needs |
| 174 | // to invalidate the species protector |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 175 | if (isolate_->IsInAnyContext(*holder_, |
| 176 | Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 177 | isolate_->CountUsage(v8::Isolate::UseCounterFeature:: |
| 178 | kArrayPrototypeConstructorModified); |
| 179 | isolate_->InvalidateArraySpeciesProtector(); |
| 180 | } |
| 181 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 182 | } else if (*name_ == heap()->species_symbol()) { |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 183 | if (!isolate_->IsArraySpeciesLookupChainIntact()) return; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 184 | // Setting the Symbol.species property of any Array constructor invalidates |
| 185 | // the species protector |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 186 | if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX)) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 187 | isolate_->CountUsage( |
| 188 | v8::Isolate::UseCounterFeature::kArraySpeciesModified); |
| 189 | isolate_->InvalidateArraySpeciesProtector(); |
| 190 | } |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 191 | } 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 197 | } |
| 198 | } |
| 199 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 200 | void LookupIterator::PrepareForDataProperty(Handle<Object> value) { |
| 201 | DCHECK(state_ == DATA || state_ == ACCESSOR); |
| 202 | DCHECK(HolderIsReceiverOrHiddenPrototype()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 203 | |
| 204 | Handle<JSObject> holder = GetHolder<JSObject>(); |
| 205 | |
| 206 | if (IsElement()) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 207 | ElementsKind kind = holder->GetElementsKind(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 208 | ElementsKind to = value->OptimalElementsKind(); |
| 209 | if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to); |
| 210 | to = GetMoreGeneralElementsKind(kind, to); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 211 | |
| 212 | if (kind != to) { |
| 213 | JSObject::TransitionElementsKind(holder, to); |
| 214 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 215 | |
| 216 | // Copy the backing store if it is copy-on-write. |
| 217 | if (IsFastSmiOrObjectElementsKind(to)) { |
| 218 | JSObject::EnsureWritableFastElements(holder); |
| 219 | } |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 220 | return; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 221 | } |
| 222 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 223 | 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 Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 239 | ReloadPropertyInformation<false>(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 240 | } |
| 241 | |
| 242 | |
| 243 | void LookupIterator::ReconfigureDataProperty(Handle<Object> value, |
| 244 | PropertyAttributes attributes) { |
| 245 | DCHECK(state_ == DATA || state_ == ACCESSOR); |
| 246 | DCHECK(HolderIsReceiverOrHiddenPrototype()); |
| 247 | Handle<JSObject> holder = GetHolder<JSObject>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 248 | 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 Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 254 | ReloadPropertyInformation<true>(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 255 | } else { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 256 | 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 Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 269 | } |
| 270 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 271 | WriteDataValue(value); |
| 272 | |
| 273 | #if VERIFY_HEAP |
| 274 | if (FLAG_verify_heap) { |
| 275 | holder->JSObjectVerify(); |
| 276 | } |
| 277 | #endif |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 278 | } |
| 279 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 280 | // 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 Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 282 | void LookupIterator::PrepareTransitionToDataProperty( |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 283 | Handle<JSObject> receiver, Handle<Object> value, |
| 284 | PropertyAttributes attributes, Object::StoreFromKeyed store_mode) { |
| 285 | DCHECK(receiver.is_identical_to(GetStoreTarget())); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 286 | if (state_ == TRANSITION) return; |
| 287 | DCHECK(state_ != LookupIterator::ACCESSOR || |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 288 | (GetAccessors()->IsAccessorInfo() && |
| 289 | AccessorInfo::cast(*GetAccessors())->is_special_data_property())); |
| 290 | DCHECK_NE(INTEGER_INDEXED_EXOTIC, state_); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 291 | DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 292 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 293 | 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()); |
| 302 | DCHECK(cell->value()->IsTheHole()); |
| 303 | transition_ = cell; |
| 304 | } else { |
| 305 | transition_ = map; |
| 306 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 307 | return; |
| 308 | } |
| 309 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 310 | Handle<Map> transition = |
| 311 | Map::TransitionToDataProperty(map, name_, value, attributes, store_mode); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 312 | state_ = TRANSITION; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 313 | transition_ = transition; |
| 314 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 315 | if (!transition->is_dictionary_map()) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 316 | property_details_ = transition->GetLastDescriptorDetails(); |
| 317 | has_property_ = true; |
| 318 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 319 | } |
| 320 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 321 | void LookupIterator::ApplyTransitionToDataProperty(Handle<JSObject> receiver) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 322 | DCHECK_EQ(TRANSITION, state_); |
| 323 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 324 | DCHECK(receiver.is_identical_to(GetStoreTarget())); |
| 325 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 326 | if (receiver->IsJSGlobalObject()) return; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 327 | holder_ = receiver; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 328 | 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 Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 338 | ReloadPropertyInformation<false>(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 339 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 340 | } |
| 341 | |
| 342 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 343 | void 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 Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 350 | 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 358 | |
| 359 | if (holder->HasFastProperties()) { |
| 360 | JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0, |
| 361 | "DeletingProperty"); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 362 | ReloadPropertyInformation<false>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 363 | } |
| 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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 370 | state_ = NOT_FOUND; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 371 | } |
| 372 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 373 | void LookupIterator::TransitionToAccessorProperty( |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 374 | Handle<Object> getter, Handle<Object> setter, |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 375 | PropertyAttributes attributes) { |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 376 | DCHECK(!getter->IsNull() || !setter->IsNull()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 377 | // 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 Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 381 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 382 | if (!IsElement() && !receiver->map()->is_dictionary_map()) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 383 | Handle<Map> old_map(receiver->map(), isolate_); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 384 | |
| 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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 394 | Handle<Map> new_map = Map::TransitionToAccessorProperty( |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 395 | isolate_, old_map, name_, descriptor, getter, setter, attributes); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 396 | bool simple_transition = new_map->GetBackPointer() == receiver->map(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 397 | JSObject::MigrateToMap(receiver, new_map); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 398 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 399 | 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 Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 406 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 407 | ReloadPropertyInformation<false>(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 408 | if (!new_map->is_dictionary_map()) return; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 409 | } |
| 410 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 411 | 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 Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 415 | if (pair->Equals(*getter, *setter)) { |
| 416 | if (property_details().attributes() == attributes) { |
| 417 | if (!IsElement()) JSObject::ReoptimizeIfPrototype(receiver); |
| 418 | return; |
| 419 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 420 | } else { |
| 421 | pair = AccessorPair::Copy(pair); |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 422 | pair->SetComponents(*getter, *setter); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 423 | } |
| 424 | } else { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 425 | pair = factory()->NewAccessorPair(); |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 426 | pair->SetComponents(*getter, *setter); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 427 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 428 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 429 | TransitionToAccessorPair(pair, attributes); |
| 430 | |
| 431 | #if VERIFY_HEAP |
| 432 | if (FLAG_verify_heap) { |
| 433 | receiver->JSObjectVerify(); |
| 434 | } |
| 435 | #endif |
| 436 | } |
| 437 | |
| 438 | |
| 439 | void 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 Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 469 | |
| 470 | ReloadPropertyInformation<true>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 471 | } 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 481 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 482 | ReloadPropertyInformation<false>(); |
| 483 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 484 | } |
| 485 | |
| 486 | |
| 487 | bool 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 Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 492 | if (*receiver_ == *holder_) return true; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 493 | if (!receiver_->IsJSReceiver()) return false; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 494 | JSReceiver* current = JSReceiver::cast(*receiver_); |
| 495 | JSReceiver* object = *holder_; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 496 | if (!current->map()->has_hidden_prototype()) return false; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 497 | // JSProxy do not occur as hidden prototypes. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 498 | if (object->IsJSProxy()) return false; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 499 | PrototypeIterator iter(isolate(), current, |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 500 | PrototypeIterator::START_AT_PROTOTYPE, |
| 501 | PrototypeIterator::END_AT_NON_HIDDEN); |
| 502 | while (!iter.IsAtEnd()) { |
| 503 | if (iter.GetCurrent<JSReceiver>() == object) return true; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 504 | iter.Advance(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 505 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 506 | return false; |
| 507 | } |
| 508 | |
| 509 | |
| 510 | Handle<Object> LookupIterator::FetchValue() const { |
| 511 | Object* result = NULL; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 512 | if (IsElement()) { |
| 513 | Handle<JSObject> holder = GetHolder<JSObject>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 514 | ElementsAccessor* accessor = holder->GetElementsAccessor(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 515 | return accessor->Get(holder, number_); |
| 516 | } else if (holder_->IsJSGlobalObject()) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 517 | Handle<JSObject> holder = GetHolder<JSObject>(); |
| 518 | result = holder->global_dictionary()->ValueAt(number_); |
| 519 | DCHECK(result->IsPropertyCell()); |
| 520 | result = PropertyCell::cast(result)->value(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 521 | } else if (!holder_->HasFastProperties()) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 522 | result = holder_->property_dictionary()->ValueAt(number_); |
| 523 | } else if (property_details_.type() == v8::internal::DATA) { |
| 524 | Handle<JSObject> holder = GetHolder<JSObject>(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 525 | FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 526 | return JSObject::FastPropertyAt(holder, property_details_.representation(), |
| 527 | field_index); |
| 528 | } else { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 529 | result = holder_->map()->instance_descriptors()->GetValue(number_); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 530 | } |
| 531 | return handle(result, isolate_); |
| 532 | } |
| 533 | |
| 534 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 535 | int LookupIterator::GetAccessorIndex() const { |
| 536 | DCHECK(has_property_); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 537 | DCHECK(holder_->HasFastProperties()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 538 | DCHECK_EQ(v8::internal::ACCESSOR_CONSTANT, property_details_.type()); |
| 539 | return descriptor_number(); |
| 540 | } |
| 541 | |
| 542 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 543 | int LookupIterator::GetConstantIndex() const { |
| 544 | DCHECK(has_property_); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 545 | DCHECK(holder_->HasFastProperties()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 546 | DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type()); |
| 547 | DCHECK(!IsElement()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 548 | return descriptor_number(); |
| 549 | } |
| 550 | |
| 551 | |
| 552 | FieldIndex LookupIterator::GetFieldIndex() const { |
| 553 | DCHECK(has_property_); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 554 | DCHECK(holder_->HasFastProperties()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 555 | DCHECK_EQ(v8::internal::DATA, property_details_.type()); |
| 556 | DCHECK(!IsElement()); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 557 | Map* holder_map = holder_->map(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 558 | int index = |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 559 | holder_map->instance_descriptors()->GetFieldIndex(descriptor_number()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 560 | bool is_double = representation().IsDouble(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 561 | return FieldIndex::ForPropertyIndex(holder_map, index, is_double); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 562 | } |
| 563 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 564 | Handle<FieldType> LookupIterator::GetFieldType() const { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 565 | DCHECK(has_property_); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 566 | DCHECK(holder_->HasFastProperties()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 567 | DCHECK_EQ(v8::internal::DATA, property_details_.type()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 568 | return handle( |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 569 | holder_->map()->instance_descriptors()->GetFieldType(descriptor_number()), |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 570 | isolate_); |
| 571 | } |
| 572 | |
| 573 | |
| 574 | Handle<PropertyCell> LookupIterator::GetPropertyCell() const { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 575 | DCHECK(!IsElement()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 576 | Handle<JSObject> holder = GetHolder<JSObject>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 577 | Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder); |
| 578 | Object* value = global->global_dictionary()->ValueAt(dictionary_entry()); |
| 579 | DCHECK(value->IsPropertyCell()); |
| 580 | return handle(PropertyCell::cast(value)); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 581 | } |
| 582 | |
| 583 | |
| 584 | Handle<Object> LookupIterator::GetAccessors() const { |
| 585 | DCHECK_EQ(ACCESSOR, state_); |
| 586 | return FetchValue(); |
| 587 | } |
| 588 | |
| 589 | |
| 590 | Handle<Object> LookupIterator::GetDataValue() const { |
| 591 | DCHECK_EQ(DATA, state_); |
| 592 | Handle<Object> value = FetchValue(); |
| 593 | return value; |
| 594 | } |
| 595 | |
| 596 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 597 | void LookupIterator::WriteDataValue(Handle<Object> value) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 598 | DCHECK_EQ(DATA, state_); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 599 | Handle<JSReceiver> holder = GetHolder<JSReceiver>(); |
| 600 | if (IsElement()) { |
| 601 | Handle<JSObject> object = Handle<JSObject>::cast(holder); |
| 602 | ElementsAccessor* accessor = object->GetElementsAccessor(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 603 | accessor->Set(object, number_, *value); |
| 604 | } else if (holder->HasFastProperties()) { |
| 605 | if (property_details_.type() == v8::internal::DATA) { |
| 606 | JSObject::cast(*holder)->WriteToField(descriptor_number(), |
| 607 | property_details_, *value); |
| 608 | } else { |
| 609 | DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type()); |
| 610 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 611 | } else if (holder->IsJSGlobalObject()) { |
| 612 | Handle<GlobalDictionary> property_dictionary = |
| 613 | handle(JSObject::cast(*holder)->global_dictionary()); |
| 614 | PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value, |
| 615 | property_details_); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 616 | } else { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 617 | NameDictionary* property_dictionary = holder->property_dictionary(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 618 | property_dictionary->ValueAtPut(dictionary_entry(), *value); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 619 | } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 620 | } |
| 621 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 622 | template <bool is_element> |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 623 | bool LookupIterator::SkipInterceptor(JSObject* holder) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 624 | auto info = GetInterceptor<is_element>(holder); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 625 | // TODO(dcarney): check for symbol/can_intercept_symbols here as well. |
| 626 | if (info->non_masking()) { |
| 627 | switch (interceptor_state_) { |
| 628 | case InterceptorState::kUninitialized: |
| 629 | interceptor_state_ = InterceptorState::kSkipNonMasking; |
| 630 | // Fall through. |
| 631 | case InterceptorState::kSkipNonMasking: |
| 632 | return true; |
| 633 | case InterceptorState::kProcessNonMasking: |
| 634 | return false; |
| 635 | } |
| 636 | } |
| 637 | return interceptor_state_ == InterceptorState::kProcessNonMasking; |
| 638 | } |
| 639 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 640 | JSReceiver* LookupIterator::NextHolder(Map* map) { |
| 641 | DisallowHeapAllocation no_gc; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 642 | if (map->prototype() == heap()->null_value()) return NULL; |
Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 643 | if (!check_prototype_chain() && !map->has_hidden_prototype()) return NULL; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 644 | return JSReceiver::cast(map->prototype()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 645 | } |
| 646 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 647 | LookupIterator::State LookupIterator::NotFound(JSReceiver* const holder) const { |
| 648 | DCHECK(!IsElement()); |
| 649 | if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND; |
| 650 | |
| 651 | Handle<String> name_string = Handle<String>::cast(name_); |
| 652 | if (name_string->length() == 0) return NOT_FOUND; |
| 653 | |
| 654 | return IsSpecialIndex(isolate_->unicode_cache(), *name_string) |
| 655 | ? INTEGER_INDEXED_EXOTIC |
| 656 | : NOT_FOUND; |
| 657 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 658 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 659 | namespace { |
| 660 | |
| 661 | template <bool is_element> |
| 662 | bool HasInterceptor(Map* map) { |
| 663 | return is_element ? map->has_indexed_interceptor() |
| 664 | : map->has_named_interceptor(); |
| 665 | } |
| 666 | |
| 667 | } // namespace |
| 668 | |
| 669 | template <bool is_element> |
| 670 | LookupIterator::State LookupIterator::LookupInSpecialHolder( |
| 671 | Map* const map, JSReceiver* const holder) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 672 | STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 673 | switch (state_) { |
| 674 | case NOT_FOUND: |
| 675 | if (map->IsJSProxyMap()) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 676 | if (is_element || !name_->IsPrivate()) return JSPROXY; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 677 | } |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 678 | if (map->is_access_check_needed()) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 679 | if (is_element || !name_->IsPrivate()) return ACCESS_CHECK; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 680 | } |
| 681 | // Fall through. |
| 682 | case ACCESS_CHECK: |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 683 | if (check_interceptor() && HasInterceptor<is_element>(map) && |
| 684 | !SkipInterceptor<is_element>(JSObject::cast(holder))) { |
| 685 | if (is_element || !name_->IsPrivate()) return INTERCEPTOR; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 686 | } |
| 687 | // Fall through. |
| 688 | case INTERCEPTOR: |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 689 | if (!is_element && map->IsJSGlobalObjectMap()) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 690 | GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary(); |
| 691 | int number = dict->FindEntry(name_); |
| 692 | if (number == GlobalDictionary::kNotFound) return NOT_FOUND; |
| 693 | number_ = static_cast<uint32_t>(number); |
| 694 | DCHECK(dict->ValueAt(number_)->IsPropertyCell()); |
| 695 | PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_)); |
| 696 | if (cell->value()->IsTheHole()) return NOT_FOUND; |
| 697 | property_details_ = cell->property_details(); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 698 | has_property_ = true; |
| 699 | switch (property_details_.kind()) { |
| 700 | case v8::internal::kData: |
| 701 | return DATA; |
| 702 | case v8::internal::kAccessor: |
| 703 | return ACCESSOR; |
| 704 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 705 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 706 | return LookupInRegularHolder<is_element>(map, holder); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 707 | case ACCESSOR: |
| 708 | case DATA: |
| 709 | return NOT_FOUND; |
| 710 | case INTEGER_INDEXED_EXOTIC: |
| 711 | case JSPROXY: |
| 712 | case TRANSITION: |
| 713 | UNREACHABLE(); |
| 714 | } |
| 715 | UNREACHABLE(); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 716 | return NOT_FOUND; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 717 | } |
| 718 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 719 | template <bool is_element> |
| 720 | LookupIterator::State LookupIterator::LookupInRegularHolder( |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 721 | Map* const map, JSReceiver* const holder) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 722 | DisallowHeapAllocation no_gc; |
| 723 | if (interceptor_state_ == InterceptorState::kProcessNonMasking) { |
| 724 | return NOT_FOUND; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 725 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 726 | |
| 727 | if (is_element) { |
| 728 | JSObject* js_object = JSObject::cast(holder); |
| 729 | ElementsAccessor* accessor = js_object->GetElementsAccessor(); |
| 730 | FixedArrayBase* backing_store = js_object->elements(); |
| 731 | number_ = accessor->GetEntryForIndex(js_object, backing_store, index_); |
| 732 | if (number_ == kMaxUInt32) { |
| 733 | return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND; |
| 734 | } |
| 735 | property_details_ = accessor->GetDetails(js_object, number_); |
| 736 | } else if (!map->is_dictionary_map()) { |
| 737 | DescriptorArray* descriptors = map->instance_descriptors(); |
| 738 | int number = descriptors->SearchWithCache(isolate_, *name_, map); |
| 739 | if (number == DescriptorArray::kNotFound) return NotFound(holder); |
| 740 | number_ = static_cast<uint32_t>(number); |
| 741 | property_details_ = descriptors->GetDetails(number_); |
| 742 | } else { |
| 743 | NameDictionary* dict = holder->property_dictionary(); |
| 744 | int number = dict->FindEntry(name_); |
| 745 | if (number == NameDictionary::kNotFound) return NotFound(holder); |
| 746 | number_ = static_cast<uint32_t>(number); |
| 747 | property_details_ = dict->DetailsAt(number_); |
| 748 | } |
| 749 | has_property_ = true; |
| 750 | switch (property_details_.kind()) { |
| 751 | case v8::internal::kData: |
| 752 | return DATA; |
| 753 | case v8::internal::kAccessor: |
| 754 | return ACCESSOR; |
| 755 | } |
| 756 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 757 | UNREACHABLE(); |
| 758 | return state_; |
| 759 | } |
| 760 | |
| 761 | } // namespace internal |
| 762 | } // namespace v8 |