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 | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 161 | bool LookupIterator::HolderIsInContextIndex(uint32_t index) const { |
| 162 | DisallowHeapAllocation no_gc; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 163 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 164 | Object* context = heap()->native_contexts_list(); |
| 165 | while (!context->IsUndefined()) { |
| 166 | Context* current_context = Context::cast(context); |
| 167 | if (current_context->get(index) == *holder_) { |
| 168 | return true; |
| 169 | } |
| 170 | context = current_context->get(Context::NEXT_CONTEXT_LINK); |
| 171 | } |
| 172 | return false; |
| 173 | } |
| 174 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 175 | void LookupIterator::InternalUpdateProtector() { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 176 | if (isolate_->bootstrapper()->IsActive()) return; |
| 177 | if (!isolate_->IsArraySpeciesLookupChainIntact()) return; |
| 178 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 179 | if (*name_ == heap()->constructor_string()) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 180 | // Setting the constructor property could change an instance's @@species |
| 181 | if (holder_->IsJSArray()) { |
| 182 | isolate_->CountUsage( |
| 183 | v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified); |
| 184 | isolate_->InvalidateArraySpeciesProtector(); |
| 185 | } else if (holder_->map()->is_prototype_map()) { |
| 186 | // Setting the constructor of Array.prototype of any realm also needs |
| 187 | // to invalidate the species protector |
| 188 | if (HolderIsInContextIndex(Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) { |
| 189 | isolate_->CountUsage(v8::Isolate::UseCounterFeature:: |
| 190 | kArrayPrototypeConstructorModified); |
| 191 | isolate_->InvalidateArraySpeciesProtector(); |
| 192 | } |
| 193 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 194 | } else if (*name_ == heap()->species_symbol()) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 195 | // Setting the Symbol.species property of any Array constructor invalidates |
| 196 | // the species protector |
| 197 | if (HolderIsInContextIndex(Context::ARRAY_FUNCTION_INDEX)) { |
| 198 | isolate_->CountUsage( |
| 199 | v8::Isolate::UseCounterFeature::kArraySpeciesModified); |
| 200 | isolate_->InvalidateArraySpeciesProtector(); |
| 201 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 202 | } |
| 203 | } |
| 204 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 205 | void LookupIterator::PrepareForDataProperty(Handle<Object> value) { |
| 206 | DCHECK(state_ == DATA || state_ == ACCESSOR); |
| 207 | DCHECK(HolderIsReceiverOrHiddenPrototype()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 208 | |
| 209 | Handle<JSObject> holder = GetHolder<JSObject>(); |
| 210 | |
| 211 | if (IsElement()) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 212 | ElementsKind kind = holder->GetElementsKind(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 213 | ElementsKind to = value->OptimalElementsKind(); |
| 214 | if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to); |
| 215 | to = GetMoreGeneralElementsKind(kind, to); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 216 | |
| 217 | if (kind != to) { |
| 218 | JSObject::TransitionElementsKind(holder, to); |
| 219 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 220 | |
| 221 | // Copy the backing store if it is copy-on-write. |
| 222 | if (IsFastSmiOrObjectElementsKind(to)) { |
| 223 | JSObject::EnsureWritableFastElements(holder); |
| 224 | } |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 225 | return; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 226 | } |
| 227 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 228 | if (!holder->HasFastProperties()) return; |
| 229 | |
| 230 | Handle<Map> old_map(holder->map(), isolate_); |
| 231 | Handle<Map> new_map = |
| 232 | Map::PrepareForDataProperty(old_map, descriptor_number(), value); |
| 233 | |
| 234 | if (old_map.is_identical_to(new_map)) { |
| 235 | // Update the property details if the representation was None. |
| 236 | if (representation().IsNone()) { |
| 237 | property_details_ = |
| 238 | new_map->instance_descriptors()->GetDetails(descriptor_number()); |
| 239 | } |
| 240 | return; |
| 241 | } |
| 242 | |
| 243 | JSObject::MigrateToMap(holder, new_map); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 244 | ReloadPropertyInformation<false>(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 245 | } |
| 246 | |
| 247 | |
| 248 | void LookupIterator::ReconfigureDataProperty(Handle<Object> value, |
| 249 | PropertyAttributes attributes) { |
| 250 | DCHECK(state_ == DATA || state_ == ACCESSOR); |
| 251 | DCHECK(HolderIsReceiverOrHiddenPrototype()); |
| 252 | Handle<JSObject> holder = GetHolder<JSObject>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 253 | if (IsElement()) { |
| 254 | DCHECK(!holder->HasFixedTypedArrayElements()); |
| 255 | DCHECK(attributes != NONE || !holder->HasFastElements()); |
| 256 | Handle<FixedArrayBase> elements(holder->elements()); |
| 257 | holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value, |
| 258 | attributes); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 259 | ReloadPropertyInformation<true>(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 260 | } else { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 261 | if (!holder->HasFastProperties()) { |
| 262 | PropertyDetails details(attributes, v8::internal::DATA, 0, |
| 263 | PropertyCellType::kMutable); |
| 264 | JSObject::SetNormalizedProperty(holder, name(), value, details); |
| 265 | } else { |
| 266 | Handle<Map> old_map(holder->map(), isolate_); |
| 267 | Handle<Map> new_map = Map::ReconfigureExistingProperty( |
| 268 | old_map, descriptor_number(), i::kData, attributes); |
| 269 | new_map = |
| 270 | Map::PrepareForDataProperty(new_map, descriptor_number(), value); |
| 271 | JSObject::MigrateToMap(holder, new_map); |
| 272 | } |
| 273 | ReloadPropertyInformation<false>(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 274 | } |
| 275 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 276 | WriteDataValue(value); |
| 277 | |
| 278 | #if VERIFY_HEAP |
| 279 | if (FLAG_verify_heap) { |
| 280 | holder->JSObjectVerify(); |
| 281 | } |
| 282 | #endif |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 283 | } |
| 284 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 285 | // Can only be called when the receiver is a JSObject. JSProxy has to be handled |
| 286 | // via a trap. Adding properties to primitive values is not observable. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 287 | void LookupIterator::PrepareTransitionToDataProperty( |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 288 | Handle<JSObject> receiver, Handle<Object> value, |
| 289 | PropertyAttributes attributes, Object::StoreFromKeyed store_mode) { |
| 290 | DCHECK(receiver.is_identical_to(GetStoreTarget())); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 291 | if (state_ == TRANSITION) return; |
| 292 | DCHECK(state_ != LookupIterator::ACCESSOR || |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 293 | (GetAccessors()->IsAccessorInfo() && |
| 294 | AccessorInfo::cast(*GetAccessors())->is_special_data_property())); |
| 295 | DCHECK_NE(INTEGER_INDEXED_EXOTIC, state_); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 296 | DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 297 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 298 | Handle<Map> map(receiver->map(), isolate_); |
| 299 | |
| 300 | // Dictionary maps can always have additional data properties. |
| 301 | if (map->is_dictionary_map()) { |
| 302 | state_ = TRANSITION; |
| 303 | if (map->IsJSGlobalObjectMap()) { |
| 304 | // Install a property cell. |
| 305 | auto cell = JSGlobalObject::EnsurePropertyCell( |
| 306 | Handle<JSGlobalObject>::cast(receiver), name()); |
| 307 | DCHECK(cell->value()->IsTheHole()); |
| 308 | transition_ = cell; |
| 309 | } else { |
| 310 | transition_ = map; |
| 311 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 312 | return; |
| 313 | } |
| 314 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 315 | Handle<Map> transition = |
| 316 | Map::TransitionToDataProperty(map, name_, value, attributes, store_mode); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 317 | state_ = TRANSITION; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 318 | transition_ = transition; |
| 319 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 320 | if (!transition->is_dictionary_map()) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 321 | property_details_ = transition->GetLastDescriptorDetails(); |
| 322 | has_property_ = true; |
| 323 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 324 | } |
| 325 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 326 | void LookupIterator::ApplyTransitionToDataProperty(Handle<JSObject> receiver) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 327 | DCHECK_EQ(TRANSITION, state_); |
| 328 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 329 | DCHECK(receiver.is_identical_to(GetStoreTarget())); |
| 330 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 331 | if (receiver->IsJSGlobalObject()) return; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 332 | holder_ = receiver; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 333 | Handle<Map> transition = transition_map(); |
| 334 | bool simple_transition = transition->GetBackPointer() == receiver->map(); |
| 335 | JSObject::MigrateToMap(receiver, transition); |
| 336 | |
| 337 | if (simple_transition) { |
| 338 | int number = transition->LastAdded(); |
| 339 | number_ = static_cast<uint32_t>(number); |
| 340 | property_details_ = transition->GetLastDescriptorDetails(); |
| 341 | state_ = DATA; |
| 342 | } else { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 343 | ReloadPropertyInformation<false>(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 344 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 345 | } |
| 346 | |
| 347 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 348 | void LookupIterator::Delete() { |
| 349 | Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_); |
| 350 | if (IsElement()) { |
| 351 | Handle<JSObject> object = Handle<JSObject>::cast(holder); |
| 352 | ElementsAccessor* accessor = object->GetElementsAccessor(); |
| 353 | accessor->Delete(object, number_); |
| 354 | } else { |
| 355 | PropertyNormalizationMode mode = holder->map()->is_prototype_map() |
| 356 | ? KEEP_INOBJECT_PROPERTIES |
| 357 | : CLEAR_INOBJECT_PROPERTIES; |
| 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 | |
| 373 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 374 | void LookupIterator::TransitionToAccessorProperty( |
| 375 | AccessorComponent component, Handle<Object> accessor, |
| 376 | PropertyAttributes attributes) { |
| 377 | DCHECK(!accessor->IsNull()); |
| 378 | // Can only be called when the receiver is a JSObject. JSProxy has to be |
| 379 | // handled via a trap. Adding properties to primitive values is not |
| 380 | // observable. |
| 381 | Handle<JSObject> receiver = GetStoreTarget(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 382 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 383 | if (!IsElement() && !receiver->map()->is_dictionary_map()) { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 384 | Handle<Map> old_map(receiver->map(), isolate_); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 385 | |
| 386 | if (!holder_.is_identical_to(receiver)) { |
| 387 | holder_ = receiver; |
| 388 | state_ = NOT_FOUND; |
| 389 | } else if (state_ == INTERCEPTOR) { |
| 390 | LookupInRegularHolder<false>(*old_map, *holder_); |
| 391 | } |
| 392 | int descriptor = |
| 393 | IsFound() ? static_cast<int>(number_) : DescriptorArray::kNotFound; |
| 394 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 395 | Handle<Map> new_map = Map::TransitionToAccessorProperty( |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 396 | old_map, name_, descriptor, component, accessor, attributes); |
| 397 | bool simple_transition = new_map->GetBackPointer() == receiver->map(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 398 | JSObject::MigrateToMap(receiver, new_map); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 399 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 400 | if (simple_transition) { |
| 401 | int number = new_map->LastAdded(); |
| 402 | number_ = static_cast<uint32_t>(number); |
| 403 | property_details_ = new_map->GetLastDescriptorDetails(); |
| 404 | state_ = ACCESSOR; |
| 405 | return; |
| 406 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 407 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 408 | ReloadPropertyInformation<false>(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 409 | if (!new_map->is_dictionary_map()) return; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 410 | } |
| 411 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 412 | Handle<AccessorPair> pair; |
| 413 | if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) { |
| 414 | pair = Handle<AccessorPair>::cast(GetAccessors()); |
| 415 | // If the component and attributes are identical, nothing has to be done. |
| 416 | if (pair->get(component) == *accessor) { |
| 417 | if (property_details().attributes() == attributes) return; |
| 418 | } else { |
| 419 | pair = AccessorPair::Copy(pair); |
| 420 | pair->set(component, *accessor); |
| 421 | } |
| 422 | } else { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 423 | pair = factory()->NewAccessorPair(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 424 | pair->set(component, *accessor); |
| 425 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 426 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 427 | TransitionToAccessorPair(pair, attributes); |
| 428 | |
| 429 | #if VERIFY_HEAP |
| 430 | if (FLAG_verify_heap) { |
| 431 | receiver->JSObjectVerify(); |
| 432 | } |
| 433 | #endif |
| 434 | } |
| 435 | |
| 436 | |
| 437 | void LookupIterator::TransitionToAccessorPair(Handle<Object> pair, |
| 438 | PropertyAttributes attributes) { |
| 439 | Handle<JSObject> receiver = GetStoreTarget(); |
| 440 | holder_ = receiver; |
| 441 | |
| 442 | PropertyDetails details(attributes, ACCESSOR_CONSTANT, 0, |
| 443 | PropertyCellType::kMutable); |
| 444 | |
| 445 | if (IsElement()) { |
| 446 | // TODO(verwaest): Move code into the element accessor. |
| 447 | Handle<SeededNumberDictionary> dictionary = |
| 448 | JSObject::NormalizeElements(receiver); |
| 449 | |
| 450 | // We unconditionally pass used_as_prototype=false here because the call |
| 451 | // to RequireSlowElements takes care of the required IC clearing and |
| 452 | // we don't want to walk the heap twice. |
| 453 | dictionary = |
| 454 | SeededNumberDictionary::Set(dictionary, index_, pair, details, false); |
| 455 | receiver->RequireSlowElements(*dictionary); |
| 456 | |
| 457 | if (receiver->HasSlowArgumentsElements()) { |
| 458 | FixedArray* parameter_map = FixedArray::cast(receiver->elements()); |
| 459 | uint32_t length = parameter_map->length() - 2; |
| 460 | if (number_ < length) { |
| 461 | parameter_map->set(number_ + 2, heap()->the_hole_value()); |
| 462 | } |
| 463 | FixedArray::cast(receiver->elements())->set(1, *dictionary); |
| 464 | } else { |
| 465 | receiver->set_elements(*dictionary); |
| 466 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 467 | |
| 468 | ReloadPropertyInformation<true>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 469 | } else { |
| 470 | PropertyNormalizationMode mode = receiver->map()->is_prototype_map() |
| 471 | ? KEEP_INOBJECT_PROPERTIES |
| 472 | : CLEAR_INOBJECT_PROPERTIES; |
| 473 | // Normalize object to make this operation simple. |
| 474 | JSObject::NormalizeProperties(receiver, mode, 0, |
| 475 | "TransitionToAccessorPair"); |
| 476 | |
| 477 | JSObject::SetNormalizedProperty(receiver, name_, pair, details); |
| 478 | JSObject::ReoptimizeIfPrototype(receiver); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 479 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 480 | ReloadPropertyInformation<false>(); |
| 481 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 482 | } |
| 483 | |
| 484 | |
| 485 | bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { |
| 486 | DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); |
| 487 | // Optimization that only works if configuration_ is not mutable. |
| 488 | if (!check_prototype_chain()) return true; |
| 489 | DisallowHeapAllocation no_gc; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 490 | if (*receiver_ == *holder_) return true; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 491 | if (!receiver_->IsJSReceiver()) return false; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 492 | JSReceiver* current = JSReceiver::cast(*receiver_); |
| 493 | JSReceiver* object = *holder_; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 494 | if (!current->map()->has_hidden_prototype()) return false; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 495 | // JSProxy do not occur as hidden prototypes. |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 496 | if (object->IsJSProxy()) return false; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 497 | PrototypeIterator iter(isolate(), current, |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 498 | PrototypeIterator::START_AT_PROTOTYPE, |
| 499 | PrototypeIterator::END_AT_NON_HIDDEN); |
| 500 | while (!iter.IsAtEnd()) { |
| 501 | if (iter.GetCurrent<JSReceiver>() == object) return true; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 502 | iter.Advance(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 503 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 504 | return false; |
| 505 | } |
| 506 | |
| 507 | |
| 508 | Handle<Object> LookupIterator::FetchValue() const { |
| 509 | Object* result = NULL; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 510 | if (IsElement()) { |
| 511 | Handle<JSObject> holder = GetHolder<JSObject>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 512 | ElementsAccessor* accessor = holder->GetElementsAccessor(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 513 | return accessor->Get(holder, number_); |
| 514 | } else if (holder_->IsJSGlobalObject()) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 515 | Handle<JSObject> holder = GetHolder<JSObject>(); |
| 516 | result = holder->global_dictionary()->ValueAt(number_); |
| 517 | DCHECK(result->IsPropertyCell()); |
| 518 | result = PropertyCell::cast(result)->value(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 519 | } else if (!holder_->HasFastProperties()) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 520 | result = holder_->property_dictionary()->ValueAt(number_); |
| 521 | } else if (property_details_.type() == v8::internal::DATA) { |
| 522 | Handle<JSObject> holder = GetHolder<JSObject>(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 523 | FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 524 | return JSObject::FastPropertyAt(holder, property_details_.representation(), |
| 525 | field_index); |
| 526 | } else { |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 527 | result = holder_->map()->instance_descriptors()->GetValue(number_); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 528 | } |
| 529 | return handle(result, isolate_); |
| 530 | } |
| 531 | |
| 532 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 533 | int LookupIterator::GetAccessorIndex() const { |
| 534 | DCHECK(has_property_); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 535 | DCHECK(holder_->HasFastProperties()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 536 | DCHECK_EQ(v8::internal::ACCESSOR_CONSTANT, property_details_.type()); |
| 537 | return descriptor_number(); |
| 538 | } |
| 539 | |
| 540 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 541 | int LookupIterator::GetConstantIndex() const { |
| 542 | DCHECK(has_property_); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 543 | DCHECK(holder_->HasFastProperties()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 544 | DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type()); |
| 545 | DCHECK(!IsElement()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 546 | return descriptor_number(); |
| 547 | } |
| 548 | |
| 549 | |
| 550 | FieldIndex LookupIterator::GetFieldIndex() const { |
| 551 | DCHECK(has_property_); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 552 | DCHECK(holder_->HasFastProperties()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 553 | DCHECK_EQ(v8::internal::DATA, property_details_.type()); |
| 554 | DCHECK(!IsElement()); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 555 | Map* holder_map = holder_->map(); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 556 | int index = |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 557 | holder_map->instance_descriptors()->GetFieldIndex(descriptor_number()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 558 | bool is_double = representation().IsDouble(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 559 | return FieldIndex::ForPropertyIndex(holder_map, index, is_double); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 560 | } |
| 561 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 562 | Handle<FieldType> LookupIterator::GetFieldType() const { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 563 | DCHECK(has_property_); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 564 | DCHECK(holder_->HasFastProperties()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 565 | DCHECK_EQ(v8::internal::DATA, property_details_.type()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 566 | return handle( |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 567 | holder_->map()->instance_descriptors()->GetFieldType(descriptor_number()), |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 568 | isolate_); |
| 569 | } |
| 570 | |
| 571 | |
| 572 | Handle<PropertyCell> LookupIterator::GetPropertyCell() const { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 573 | DCHECK(!IsElement()); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 574 | Handle<JSObject> holder = GetHolder<JSObject>(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 575 | Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder); |
| 576 | Object* value = global->global_dictionary()->ValueAt(dictionary_entry()); |
| 577 | DCHECK(value->IsPropertyCell()); |
| 578 | return handle(PropertyCell::cast(value)); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 579 | } |
| 580 | |
| 581 | |
| 582 | Handle<Object> LookupIterator::GetAccessors() const { |
| 583 | DCHECK_EQ(ACCESSOR, state_); |
| 584 | return FetchValue(); |
| 585 | } |
| 586 | |
| 587 | |
| 588 | Handle<Object> LookupIterator::GetDataValue() const { |
| 589 | DCHECK_EQ(DATA, state_); |
| 590 | Handle<Object> value = FetchValue(); |
| 591 | return value; |
| 592 | } |
| 593 | |
| 594 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 595 | void LookupIterator::WriteDataValue(Handle<Object> value) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 596 | DCHECK_EQ(DATA, state_); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 597 | Handle<JSReceiver> holder = GetHolder<JSReceiver>(); |
| 598 | if (IsElement()) { |
| 599 | Handle<JSObject> object = Handle<JSObject>::cast(holder); |
| 600 | ElementsAccessor* accessor = object->GetElementsAccessor(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 601 | accessor->Set(object, number_, *value); |
| 602 | } else if (holder->HasFastProperties()) { |
| 603 | if (property_details_.type() == v8::internal::DATA) { |
| 604 | JSObject::cast(*holder)->WriteToField(descriptor_number(), |
| 605 | property_details_, *value); |
| 606 | } else { |
| 607 | DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type()); |
| 608 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 609 | } else if (holder->IsJSGlobalObject()) { |
| 610 | Handle<GlobalDictionary> property_dictionary = |
| 611 | handle(JSObject::cast(*holder)->global_dictionary()); |
| 612 | PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value, |
| 613 | property_details_); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 614 | } else { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 615 | NameDictionary* property_dictionary = holder->property_dictionary(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 616 | property_dictionary->ValueAtPut(dictionary_entry(), *value); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 617 | } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 618 | } |
| 619 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 620 | template <bool is_element> |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 621 | bool LookupIterator::SkipInterceptor(JSObject* holder) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 622 | auto info = GetInterceptor<is_element>(holder); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 623 | // TODO(dcarney): check for symbol/can_intercept_symbols here as well. |
| 624 | if (info->non_masking()) { |
| 625 | switch (interceptor_state_) { |
| 626 | case InterceptorState::kUninitialized: |
| 627 | interceptor_state_ = InterceptorState::kSkipNonMasking; |
| 628 | // Fall through. |
| 629 | case InterceptorState::kSkipNonMasking: |
| 630 | return true; |
| 631 | case InterceptorState::kProcessNonMasking: |
| 632 | return false; |
| 633 | } |
| 634 | } |
| 635 | return interceptor_state_ == InterceptorState::kProcessNonMasking; |
| 636 | } |
| 637 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 638 | JSReceiver* LookupIterator::NextHolder(Map* map) { |
| 639 | DisallowHeapAllocation no_gc; |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 640 | if (map->prototype() == heap()->null_value()) return NULL; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 641 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 642 | DCHECK(!map->IsJSGlobalProxyMap() || map->has_hidden_prototype()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 643 | |
| 644 | if (!check_prototype_chain() && |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 645 | !(check_hidden() && map->has_hidden_prototype()) && |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 646 | // Always lookup behind the JSGlobalProxy into the JSGlobalObject, even |
| 647 | // when not checking other hidden prototypes. |
| 648 | !map->IsJSGlobalProxyMap()) { |
| 649 | return NULL; |
| 650 | } |
| 651 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 652 | return JSReceiver::cast(map->prototype()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 653 | } |
| 654 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 655 | LookupIterator::State LookupIterator::NotFound(JSReceiver* const holder) const { |
| 656 | DCHECK(!IsElement()); |
| 657 | if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND; |
| 658 | |
| 659 | Handle<String> name_string = Handle<String>::cast(name_); |
| 660 | if (name_string->length() == 0) return NOT_FOUND; |
| 661 | |
| 662 | return IsSpecialIndex(isolate_->unicode_cache(), *name_string) |
| 663 | ? INTEGER_INDEXED_EXOTIC |
| 664 | : NOT_FOUND; |
| 665 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 666 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 667 | namespace { |
| 668 | |
| 669 | template <bool is_element> |
| 670 | bool HasInterceptor(Map* map) { |
| 671 | return is_element ? map->has_indexed_interceptor() |
| 672 | : map->has_named_interceptor(); |
| 673 | } |
| 674 | |
| 675 | } // namespace |
| 676 | |
| 677 | template <bool is_element> |
| 678 | LookupIterator::State LookupIterator::LookupInSpecialHolder( |
| 679 | Map* const map, JSReceiver* const holder) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 680 | STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 681 | switch (state_) { |
| 682 | case NOT_FOUND: |
| 683 | if (map->IsJSProxyMap()) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 684 | if (is_element || !name_->IsPrivate()) return JSPROXY; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 685 | } |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 686 | if (map->is_access_check_needed()) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 687 | if (is_element || !name_->IsPrivate()) return ACCESS_CHECK; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 688 | } |
| 689 | // Fall through. |
| 690 | case ACCESS_CHECK: |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 691 | if (check_interceptor() && HasInterceptor<is_element>(map) && |
| 692 | !SkipInterceptor<is_element>(JSObject::cast(holder))) { |
| 693 | if (is_element || !name_->IsPrivate()) return INTERCEPTOR; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 694 | } |
| 695 | // Fall through. |
| 696 | case INTERCEPTOR: |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 697 | if (!is_element && map->IsJSGlobalObjectMap()) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 698 | GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary(); |
| 699 | int number = dict->FindEntry(name_); |
| 700 | if (number == GlobalDictionary::kNotFound) return NOT_FOUND; |
| 701 | number_ = static_cast<uint32_t>(number); |
| 702 | DCHECK(dict->ValueAt(number_)->IsPropertyCell()); |
| 703 | PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_)); |
| 704 | if (cell->value()->IsTheHole()) return NOT_FOUND; |
| 705 | property_details_ = cell->property_details(); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 706 | has_property_ = true; |
| 707 | switch (property_details_.kind()) { |
| 708 | case v8::internal::kData: |
| 709 | return DATA; |
| 710 | case v8::internal::kAccessor: |
| 711 | return ACCESSOR; |
| 712 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 713 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 714 | return LookupInRegularHolder<is_element>(map, holder); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 715 | case ACCESSOR: |
| 716 | case DATA: |
| 717 | return NOT_FOUND; |
| 718 | case INTEGER_INDEXED_EXOTIC: |
| 719 | case JSPROXY: |
| 720 | case TRANSITION: |
| 721 | UNREACHABLE(); |
| 722 | } |
| 723 | UNREACHABLE(); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 724 | return NOT_FOUND; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 725 | } |
| 726 | |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 727 | template <bool is_element> |
| 728 | LookupIterator::State LookupIterator::LookupInRegularHolder( |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 729 | Map* const map, JSReceiver* const holder) { |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 730 | DisallowHeapAllocation no_gc; |
| 731 | if (interceptor_state_ == InterceptorState::kProcessNonMasking) { |
| 732 | return NOT_FOUND; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 733 | } |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame^] | 734 | |
| 735 | if (is_element) { |
| 736 | JSObject* js_object = JSObject::cast(holder); |
| 737 | ElementsAccessor* accessor = js_object->GetElementsAccessor(); |
| 738 | FixedArrayBase* backing_store = js_object->elements(); |
| 739 | number_ = accessor->GetEntryForIndex(js_object, backing_store, index_); |
| 740 | if (number_ == kMaxUInt32) { |
| 741 | return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND; |
| 742 | } |
| 743 | property_details_ = accessor->GetDetails(js_object, number_); |
| 744 | } else if (!map->is_dictionary_map()) { |
| 745 | DescriptorArray* descriptors = map->instance_descriptors(); |
| 746 | int number = descriptors->SearchWithCache(isolate_, *name_, map); |
| 747 | if (number == DescriptorArray::kNotFound) return NotFound(holder); |
| 748 | number_ = static_cast<uint32_t>(number); |
| 749 | property_details_ = descriptors->GetDetails(number_); |
| 750 | } else { |
| 751 | NameDictionary* dict = holder->property_dictionary(); |
| 752 | int number = dict->FindEntry(name_); |
| 753 | if (number == NameDictionary::kNotFound) return NotFound(holder); |
| 754 | number_ = static_cast<uint32_t>(number); |
| 755 | property_details_ = dict->DetailsAt(number_); |
| 756 | } |
| 757 | has_property_ = true; |
| 758 | switch (property_details_.kind()) { |
| 759 | case v8::internal::kData: |
| 760 | return DATA; |
| 761 | case v8::internal::kAccessor: |
| 762 | return ACCESSOR; |
| 763 | } |
| 764 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 765 | UNREACHABLE(); |
| 766 | return state_; |
| 767 | } |
| 768 | |
| 769 | } // namespace internal |
| 770 | } // namespace v8 |