| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/lookup.h" | 5 #include "src/lookup.h" |
| 6 | 6 |
| 7 #include "src/bootstrapper.h" | 7 #include "src/bootstrapper.h" |
| 8 #include "src/deoptimizer.h" | 8 #include "src/deoptimizer.h" |
| 9 #include "src/elements.h" | 9 #include "src/elements.h" |
| 10 #include "src/field-type.h" | 10 #include "src/field-type.h" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 LookupIterator it(isolate, receiver, index, configuration); | 38 LookupIterator it(isolate, receiver, index, configuration); |
| 39 // Here we try to avoid having to rebuild the string later | 39 // Here we try to avoid having to rebuild the string later |
| 40 // by storing it on the indexed LookupIterator. | 40 // by storing it on the indexed LookupIterator. |
| 41 it.name_ = name; | 41 it.name_ = name; |
| 42 return it; | 42 return it; |
| 43 } | 43 } |
| 44 | 44 |
| 45 return LookupIterator(receiver, name, configuration); | 45 return LookupIterator(receiver, name, configuration); |
| 46 } | 46 } |
| 47 | 47 |
| 48 template <bool is_element> |
| 49 void LookupIterator::Start() { |
| 50 DisallowHeapAllocation no_gc; |
| 51 |
| 52 has_property_ = false; |
| 53 state_ = NOT_FOUND; |
| 54 number_ = DescriptorArray::kNotFound; |
| 55 holder_ = initial_holder_; |
| 56 |
| 57 JSReceiver* holder = *holder_; |
| 58 Map* map = holder->map(); |
| 59 |
| 60 state_ = LookupInHolder<is_element>(map, holder); |
| 61 if (IsFound()) return; |
| 62 |
| 63 NextInternal<is_element>(map, holder); |
| 64 } |
| 65 |
| 66 template void LookupIterator::Start<true>(); |
| 67 template void LookupIterator::Start<false>(); |
| 48 | 68 |
| 49 void LookupIterator::Next() { | 69 void LookupIterator::Next() { |
| 50 DCHECK_NE(JSPROXY, state_); | 70 DCHECK_NE(JSPROXY, state_); |
| 51 DCHECK_NE(TRANSITION, state_); | 71 DCHECK_NE(TRANSITION, state_); |
| 52 DisallowHeapAllocation no_gc; | 72 DisallowHeapAllocation no_gc; |
| 53 has_property_ = false; | 73 has_property_ = false; |
| 54 | 74 |
| 55 JSReceiver* holder = *holder_; | 75 JSReceiver* holder = *holder_; |
| 56 Map* map = holder->map(); | 76 Map* map = holder->map(); |
| 57 | 77 |
| 58 // Perform lookup on current holder. | 78 if (map->instance_type() <= LAST_SPECIAL_RECEIVER_TYPE) { |
| 59 state_ = LookupInHolder(map, holder); | 79 state_ = IsElement() ? LookupInSpecialHolder<true>(map, holder) |
| 60 if (IsFound()) return; | 80 : LookupInSpecialHolder<false>(map, holder); |
| 81 if (IsFound()) return; |
| 82 } |
| 61 | 83 |
| 62 // Continue lookup if lookup on current holder failed. | 84 IsElement() ? NextInternal<true>(map, holder) |
| 85 : NextInternal<false>(map, holder); |
| 86 } |
| 87 |
| 88 template <bool is_element> |
| 89 void LookupIterator::NextInternal(Map* map, JSReceiver* holder) { |
| 63 do { | 90 do { |
| 64 JSReceiver* maybe_holder = NextHolder(map); | 91 JSReceiver* maybe_holder = NextHolder(map); |
| 65 if (maybe_holder == nullptr) { | 92 if (maybe_holder == nullptr) { |
| 66 if (interceptor_state_ == InterceptorState::kSkipNonMasking) { | 93 if (interceptor_state_ == InterceptorState::kSkipNonMasking) { |
| 67 RestartLookupForNonMaskingInterceptors(); | 94 RestartLookupForNonMaskingInterceptors<is_element>(); |
| 68 return; | 95 return; |
| 69 } | 96 } |
| 70 break; | 97 state_ = NOT_FOUND; |
| 98 if (holder != *holder_) holder_ = handle(holder, isolate_); |
| 99 return; |
| 71 } | 100 } |
| 72 holder = maybe_holder; | 101 holder = maybe_holder; |
| 73 map = holder->map(); | 102 map = holder->map(); |
| 74 state_ = LookupInHolder(map, holder); | 103 state_ = LookupInHolder<is_element>(map, holder); |
| 75 } while (!IsFound()); | 104 } while (!IsFound()); |
| 76 | 105 |
| 77 if (holder != *holder_) holder_ = handle(holder, isolate_); | 106 holder_ = handle(holder, isolate_); |
| 78 } | 107 } |
| 79 | 108 |
| 80 | 109 template <bool is_element> |
| 81 void LookupIterator::RestartInternal(InterceptorState interceptor_state) { | 110 void LookupIterator::RestartInternal(InterceptorState interceptor_state) { |
| 82 state_ = NOT_FOUND; | |
| 83 interceptor_state_ = interceptor_state; | 111 interceptor_state_ = interceptor_state; |
| 84 property_details_ = PropertyDetails::Empty(); | 112 property_details_ = PropertyDetails::Empty(); |
| 85 holder_ = initial_holder_; | 113 Start<is_element>(); |
| 86 number_ = DescriptorArray::kNotFound; | |
| 87 Next(); | |
| 88 } | 114 } |
| 89 | 115 |
| 116 template void LookupIterator::RestartInternal<true>(InterceptorState); |
| 117 template void LookupIterator::RestartInternal<false>(InterceptorState); |
| 90 | 118 |
| 91 // static | 119 // static |
| 92 Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver( | 120 Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver( |
| 93 Isolate* isolate, Handle<Object> receiver, uint32_t index) { | 121 Isolate* isolate, Handle<Object> receiver, uint32_t index) { |
| 94 // Strings are the only objects with properties (only elements) directly on | 122 // Strings are the only objects with properties (only elements) directly on |
| 95 // the wrapper. Hence we can skip generating the wrapper for all other cases. | 123 // the wrapper. Hence we can skip generating the wrapper for all other cases. |
| 96 if (index != kMaxUInt32 && receiver->IsString() && | 124 if (index != kMaxUInt32 && receiver->IsString() && |
| 97 index < static_cast<uint32_t>(String::cast(*receiver)->length())) { | 125 index < static_cast<uint32_t>(String::cast(*receiver)->length())) { |
| 98 // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native | 126 // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native |
| 99 // context, ensuring that we don't leak it into JS? | 127 // context, ensuring that we don't leak it into JS? |
| 100 Handle<JSFunction> constructor = isolate->string_function(); | 128 Handle<JSFunction> constructor = isolate->string_function(); |
| 101 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); | 129 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); |
| 102 Handle<JSValue>::cast(result)->set_value(*receiver); | 130 Handle<JSValue>::cast(result)->set_value(*receiver); |
| 103 return result; | 131 return result; |
| 104 } | 132 } |
| 105 auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate); | 133 auto root = handle(receiver->GetRootMap(isolate)->prototype(), isolate); |
| 106 if (root->IsNull()) { | 134 if (root->IsNull()) { |
| 107 unsigned int magic = 0xbbbbbbbb; | 135 unsigned int magic = 0xbbbbbbbb; |
| 108 isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic); | 136 isolate->PushStackTraceAndDie(magic, *receiver, NULL, magic); |
| 109 } | 137 } |
| 110 return Handle<JSReceiver>::cast(root); | 138 return Handle<JSReceiver>::cast(root); |
| 111 } | 139 } |
| 112 | 140 |
| 113 | 141 |
| 114 Handle<Map> LookupIterator::GetReceiverMap() const { | 142 Handle<Map> LookupIterator::GetReceiverMap() const { |
| 115 if (receiver_->IsNumber()) return factory()->heap_number_map(); | 143 if (receiver_->IsNumber()) return factory()->heap_number_map(); |
| 116 return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_); | 144 return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_); |
| 117 } | 145 } |
| 118 | 146 |
| 119 | |
| 120 Handle<JSObject> LookupIterator::GetStoreTarget() const { | |
| 121 if (receiver_->IsJSGlobalProxy()) { | |
| 122 Object* prototype = JSGlobalProxy::cast(*receiver_)->map()->prototype(); | |
| 123 if (!prototype->IsNull()) { | |
| 124 return handle(JSGlobalObject::cast(prototype), isolate_); | |
| 125 } | |
| 126 } | |
| 127 return Handle<JSObject>::cast(receiver_); | |
| 128 } | |
| 129 | |
| 130 | |
| 131 bool LookupIterator::HasAccess() const { | 147 bool LookupIterator::HasAccess() const { |
| 132 DCHECK_EQ(ACCESS_CHECK, state_); | 148 DCHECK_EQ(ACCESS_CHECK, state_); |
| 133 return isolate_->MayAccess(handle(isolate_->context()), | 149 return isolate_->MayAccess(handle(isolate_->context()), |
| 134 GetHolder<JSObject>()); | 150 GetHolder<JSObject>()); |
| 135 } | 151 } |
| 136 | 152 |
| 137 | 153 template <bool is_element> |
| 138 void LookupIterator::ReloadPropertyInformation() { | 154 void LookupIterator::ReloadPropertyInformation() { |
| 139 state_ = BEFORE_PROPERTY; | 155 state_ = BEFORE_PROPERTY; |
| 140 interceptor_state_ = InterceptorState::kUninitialized; | 156 interceptor_state_ = InterceptorState::kUninitialized; |
| 141 state_ = LookupInHolder(holder_->map(), *holder_); | 157 state_ = LookupInHolder<is_element>(holder_->map(), *holder_); |
| 142 DCHECK(IsFound() || !holder_->HasFastProperties()); | 158 DCHECK(IsFound() || !holder_->HasFastProperties()); |
| 143 } | 159 } |
| 144 | 160 |
| 145 bool LookupIterator::HolderIsInContextIndex(uint32_t index) const { | 161 bool LookupIterator::HolderIsInContextIndex(uint32_t index) const { |
| 146 DisallowHeapAllocation no_gc; | 162 DisallowHeapAllocation no_gc; |
| 147 | 163 |
| 148 Object* context = heap()->native_contexts_list(); | 164 Object* context = heap()->native_contexts_list(); |
| 149 while (!context->IsUndefined()) { | 165 while (!context->IsUndefined()) { |
| 150 Context* current_context = Context::cast(context); | 166 Context* current_context = Context::cast(context); |
| 151 if (current_context->get(index) == *holder_) { | 167 if (current_context->get(index) == *holder_) { |
| 152 return true; | 168 return true; |
| 153 } | 169 } |
| 154 context = current_context->get(Context::NEXT_CONTEXT_LINK); | 170 context = current_context->get(Context::NEXT_CONTEXT_LINK); |
| 155 } | 171 } |
| 156 return false; | 172 return false; |
| 157 } | 173 } |
| 158 | 174 |
| 159 void LookupIterator::UpdateProtector() { | 175 void LookupIterator::InternalUpdateProtector() { |
| 160 if (!FLAG_harmony_species) return; | |
| 161 | |
| 162 if (IsElement()) return; | |
| 163 if (isolate_->bootstrapper()->IsActive()) return; | 176 if (isolate_->bootstrapper()->IsActive()) return; |
| 164 if (!isolate_->IsArraySpeciesLookupChainIntact()) return; | 177 if (!isolate_->IsArraySpeciesLookupChainIntact()) return; |
| 165 | 178 |
| 166 if (*name_ == *isolate_->factory()->constructor_string()) { | 179 if (*name_ == heap()->constructor_string()) { |
| 167 // Setting the constructor property could change an instance's @@species | 180 // Setting the constructor property could change an instance's @@species |
| 168 if (holder_->IsJSArray()) { | 181 if (holder_->IsJSArray()) { |
| 169 isolate_->CountUsage( | 182 isolate_->CountUsage( |
| 170 v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified); | 183 v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified); |
| 171 isolate_->InvalidateArraySpeciesProtector(); | 184 isolate_->InvalidateArraySpeciesProtector(); |
| 172 } else if (holder_->map()->is_prototype_map()) { | 185 } else if (holder_->map()->is_prototype_map()) { |
| 173 // Setting the constructor of Array.prototype of any realm also needs | 186 // Setting the constructor of Array.prototype of any realm also needs |
| 174 // to invalidate the species protector | 187 // to invalidate the species protector |
| 175 if (HolderIsInContextIndex(Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) { | 188 if (HolderIsInContextIndex(Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) { |
| 176 isolate_->CountUsage(v8::Isolate::UseCounterFeature:: | 189 isolate_->CountUsage(v8::Isolate::UseCounterFeature:: |
| 177 kArrayPrototypeConstructorModified); | 190 kArrayPrototypeConstructorModified); |
| 178 isolate_->InvalidateArraySpeciesProtector(); | 191 isolate_->InvalidateArraySpeciesProtector(); |
| 179 } | 192 } |
| 180 } | 193 } |
| 181 } else if (*name_ == *isolate_->factory()->species_symbol()) { | 194 } else if (*name_ == heap()->species_symbol()) { |
| 182 // Setting the Symbol.species property of any Array constructor invalidates | 195 // Setting the Symbol.species property of any Array constructor invalidates |
| 183 // the species protector | 196 // the species protector |
| 184 if (HolderIsInContextIndex(Context::ARRAY_FUNCTION_INDEX)) { | 197 if (HolderIsInContextIndex(Context::ARRAY_FUNCTION_INDEX)) { |
| 185 isolate_->CountUsage( | 198 isolate_->CountUsage( |
| 186 v8::Isolate::UseCounterFeature::kArraySpeciesModified); | 199 v8::Isolate::UseCounterFeature::kArraySpeciesModified); |
| 187 isolate_->InvalidateArraySpeciesProtector(); | 200 isolate_->InvalidateArraySpeciesProtector(); |
| 188 } | 201 } |
| 189 } | 202 } |
| 190 } | 203 } |
| 191 | 204 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 221 if (old_map.is_identical_to(new_map)) { | 234 if (old_map.is_identical_to(new_map)) { |
| 222 // Update the property details if the representation was None. | 235 // Update the property details if the representation was None. |
| 223 if (representation().IsNone()) { | 236 if (representation().IsNone()) { |
| 224 property_details_ = | 237 property_details_ = |
| 225 new_map->instance_descriptors()->GetDetails(descriptor_number()); | 238 new_map->instance_descriptors()->GetDetails(descriptor_number()); |
| 226 } | 239 } |
| 227 return; | 240 return; |
| 228 } | 241 } |
| 229 | 242 |
| 230 JSObject::MigrateToMap(holder, new_map); | 243 JSObject::MigrateToMap(holder, new_map); |
| 231 ReloadPropertyInformation(); | 244 ReloadPropertyInformation<false>(); |
| 232 } | 245 } |
| 233 | 246 |
| 234 | 247 |
| 235 void LookupIterator::ReconfigureDataProperty(Handle<Object> value, | 248 void LookupIterator::ReconfigureDataProperty(Handle<Object> value, |
| 236 PropertyAttributes attributes) { | 249 PropertyAttributes attributes) { |
| 237 DCHECK(state_ == DATA || state_ == ACCESSOR); | 250 DCHECK(state_ == DATA || state_ == ACCESSOR); |
| 238 DCHECK(HolderIsReceiverOrHiddenPrototype()); | 251 DCHECK(HolderIsReceiverOrHiddenPrototype()); |
| 239 Handle<JSObject> holder = GetHolder<JSObject>(); | 252 Handle<JSObject> holder = GetHolder<JSObject>(); |
| 240 if (IsElement()) { | 253 if (IsElement()) { |
| 241 DCHECK(!holder->HasFixedTypedArrayElements()); | 254 DCHECK(!holder->HasFixedTypedArrayElements()); |
| 242 DCHECK(attributes != NONE || !holder->HasFastElements()); | 255 DCHECK(attributes != NONE || !holder->HasFastElements()); |
| 243 Handle<FixedArrayBase> elements(holder->elements()); | 256 Handle<FixedArrayBase> elements(holder->elements()); |
| 244 holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value, | 257 holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value, |
| 245 attributes); | 258 attributes); |
| 246 } else if (!holder->HasFastProperties()) { | 259 ReloadPropertyInformation<true>(); |
| 247 PropertyDetails details(attributes, v8::internal::DATA, 0, | |
| 248 PropertyCellType::kMutable); | |
| 249 JSObject::SetNormalizedProperty(holder, name(), value, details); | |
| 250 } else { | 260 } else { |
| 251 Handle<Map> old_map(holder->map(), isolate_); | 261 if (!holder->HasFastProperties()) { |
| 252 Handle<Map> new_map = Map::ReconfigureExistingProperty( | 262 PropertyDetails details(attributes, v8::internal::DATA, 0, |
| 253 old_map, descriptor_number(), i::kData, attributes); | 263 PropertyCellType::kMutable); |
| 254 new_map = Map::PrepareForDataProperty(new_map, descriptor_number(), value); | 264 JSObject::SetNormalizedProperty(holder, name(), value, details); |
| 255 JSObject::MigrateToMap(holder, new_map); | 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>(); |
| 256 } | 274 } |
| 257 | 275 |
| 258 ReloadPropertyInformation(); | |
| 259 WriteDataValue(value); | 276 WriteDataValue(value); |
| 260 | 277 |
| 261 #if VERIFY_HEAP | 278 #if VERIFY_HEAP |
| 262 if (FLAG_verify_heap) { | 279 if (FLAG_verify_heap) { |
| 263 holder->JSObjectVerify(); | 280 holder->JSObjectVerify(); |
| 264 } | 281 } |
| 265 #endif | 282 #endif |
| 266 } | 283 } |
| 267 | 284 |
| 268 // Can only be called when the receiver is a JSObject. JSProxy has to be handled | 285 // Can only be called when the receiver is a JSObject. JSProxy has to be handled |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 Handle<Map> transition = transition_map(); | 333 Handle<Map> transition = transition_map(); |
| 317 bool simple_transition = transition->GetBackPointer() == receiver->map(); | 334 bool simple_transition = transition->GetBackPointer() == receiver->map(); |
| 318 JSObject::MigrateToMap(receiver, transition); | 335 JSObject::MigrateToMap(receiver, transition); |
| 319 | 336 |
| 320 if (simple_transition) { | 337 if (simple_transition) { |
| 321 int number = transition->LastAdded(); | 338 int number = transition->LastAdded(); |
| 322 number_ = static_cast<uint32_t>(number); | 339 number_ = static_cast<uint32_t>(number); |
| 323 property_details_ = transition->GetLastDescriptorDetails(); | 340 property_details_ = transition->GetLastDescriptorDetails(); |
| 324 state_ = DATA; | 341 state_ = DATA; |
| 325 } else { | 342 } else { |
| 326 ReloadPropertyInformation(); | 343 ReloadPropertyInformation<false>(); |
| 327 } | 344 } |
| 328 } | 345 } |
| 329 | 346 |
| 330 | 347 |
| 331 void LookupIterator::Delete() { | 348 void LookupIterator::Delete() { |
| 332 Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_); | 349 Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_); |
| 333 if (IsElement()) { | 350 if (IsElement()) { |
| 334 Handle<JSObject> object = Handle<JSObject>::cast(holder); | 351 Handle<JSObject> object = Handle<JSObject>::cast(holder); |
| 335 ElementsAccessor* accessor = object->GetElementsAccessor(); | 352 ElementsAccessor* accessor = object->GetElementsAccessor(); |
| 336 accessor->Delete(object, number_); | 353 accessor->Delete(object, number_); |
| 337 } else { | 354 } else { |
| 338 PropertyNormalizationMode mode = holder->map()->is_prototype_map() | 355 PropertyNormalizationMode mode = holder->map()->is_prototype_map() |
| 339 ? KEEP_INOBJECT_PROPERTIES | 356 ? KEEP_INOBJECT_PROPERTIES |
| 340 : CLEAR_INOBJECT_PROPERTIES; | 357 : CLEAR_INOBJECT_PROPERTIES; |
| 341 | 358 |
| 342 if (holder->HasFastProperties()) { | 359 if (holder->HasFastProperties()) { |
| 343 JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0, | 360 JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0, |
| 344 "DeletingProperty"); | 361 "DeletingProperty"); |
| 345 ReloadPropertyInformation(); | 362 ReloadPropertyInformation<false>(); |
| 346 } | 363 } |
| 347 // TODO(verwaest): Get rid of the name_ argument. | 364 // TODO(verwaest): Get rid of the name_ argument. |
| 348 JSReceiver::DeleteNormalizedProperty(holder, name_, number_); | 365 JSReceiver::DeleteNormalizedProperty(holder, name_, number_); |
| 349 if (holder->IsJSObject()) { | 366 if (holder->IsJSObject()) { |
| 350 JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder)); | 367 JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder)); |
| 351 } | 368 } |
| 352 } | 369 } |
| 353 state_ = NOT_FOUND; | 370 state_ = NOT_FOUND; |
| 354 } | 371 } |
| 355 | 372 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 372 JSObject::MigrateToMap(receiver, new_map); | 389 JSObject::MigrateToMap(receiver, new_map); |
| 373 | 390 |
| 374 if (simple_transition) { | 391 if (simple_transition) { |
| 375 int number = new_map->LastAdded(); | 392 int number = new_map->LastAdded(); |
| 376 number_ = static_cast<uint32_t>(number); | 393 number_ = static_cast<uint32_t>(number); |
| 377 property_details_ = new_map->GetLastDescriptorDetails(); | 394 property_details_ = new_map->GetLastDescriptorDetails(); |
| 378 state_ = ACCESSOR; | 395 state_ = ACCESSOR; |
| 379 return; | 396 return; |
| 380 } | 397 } |
| 381 | 398 |
| 382 ReloadPropertyInformation(); | 399 ReloadPropertyInformation<false>(); |
| 383 if (!new_map->is_dictionary_map()) return; | 400 if (!new_map->is_dictionary_map()) return; |
| 384 } | 401 } |
| 385 | 402 |
| 386 Handle<AccessorPair> pair; | 403 Handle<AccessorPair> pair; |
| 387 if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) { | 404 if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) { |
| 388 pair = Handle<AccessorPair>::cast(GetAccessors()); | 405 pair = Handle<AccessorPair>::cast(GetAccessors()); |
| 389 // If the component and attributes are identical, nothing has to be done. | 406 // If the component and attributes are identical, nothing has to be done. |
| 390 if (pair->get(component) == *accessor) { | 407 if (pair->get(component) == *accessor) { |
| 391 if (property_details().attributes() == attributes) return; | 408 if (property_details().attributes() == attributes) return; |
| 392 } else { | 409 } else { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 if (receiver->HasSlowArgumentsElements()) { | 448 if (receiver->HasSlowArgumentsElements()) { |
| 432 FixedArray* parameter_map = FixedArray::cast(receiver->elements()); | 449 FixedArray* parameter_map = FixedArray::cast(receiver->elements()); |
| 433 uint32_t length = parameter_map->length() - 2; | 450 uint32_t length = parameter_map->length() - 2; |
| 434 if (number_ < length) { | 451 if (number_ < length) { |
| 435 parameter_map->set(number_ + 2, heap()->the_hole_value()); | 452 parameter_map->set(number_ + 2, heap()->the_hole_value()); |
| 436 } | 453 } |
| 437 FixedArray::cast(receiver->elements())->set(1, *dictionary); | 454 FixedArray::cast(receiver->elements())->set(1, *dictionary); |
| 438 } else { | 455 } else { |
| 439 receiver->set_elements(*dictionary); | 456 receiver->set_elements(*dictionary); |
| 440 } | 457 } |
| 458 |
| 459 ReloadPropertyInformation<true>(); |
| 441 } else { | 460 } else { |
| 442 PropertyNormalizationMode mode = receiver->map()->is_prototype_map() | 461 PropertyNormalizationMode mode = receiver->map()->is_prototype_map() |
| 443 ? KEEP_INOBJECT_PROPERTIES | 462 ? KEEP_INOBJECT_PROPERTIES |
| 444 : CLEAR_INOBJECT_PROPERTIES; | 463 : CLEAR_INOBJECT_PROPERTIES; |
| 445 // Normalize object to make this operation simple. | 464 // Normalize object to make this operation simple. |
| 446 JSObject::NormalizeProperties(receiver, mode, 0, | 465 JSObject::NormalizeProperties(receiver, mode, 0, |
| 447 "TransitionToAccessorPair"); | 466 "TransitionToAccessorPair"); |
| 448 | 467 |
| 449 JSObject::SetNormalizedProperty(receiver, name_, pair, details); | 468 JSObject::SetNormalizedProperty(receiver, name_, pair, details); |
| 450 JSObject::ReoptimizeIfPrototype(receiver); | 469 JSObject::ReoptimizeIfPrototype(receiver); |
| 470 |
| 471 ReloadPropertyInformation<false>(); |
| 451 } | 472 } |
| 452 | |
| 453 ReloadPropertyInformation(); | |
| 454 } | 473 } |
| 455 | 474 |
| 456 | 475 |
| 457 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { | 476 bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { |
| 458 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); | 477 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); |
| 459 // Optimization that only works if configuration_ is not mutable. | 478 // Optimization that only works if configuration_ is not mutable. |
| 460 if (!check_prototype_chain()) return true; | 479 if (!check_prototype_chain()) return true; |
| 461 DisallowHeapAllocation no_gc; | 480 DisallowHeapAllocation no_gc; |
| 462 if (*receiver_ == *holder_) return true; | 481 if (*receiver_ == *holder_) return true; |
| 463 if (!receiver_->IsJSReceiver()) return false; | 482 if (!receiver_->IsJSReceiver()) return false; |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 583 handle(JSObject::cast(*holder)->global_dictionary()); | 602 handle(JSObject::cast(*holder)->global_dictionary()); |
| 584 PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value, | 603 PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value, |
| 585 property_details_); | 604 property_details_); |
| 586 } else { | 605 } else { |
| 587 NameDictionary* property_dictionary = holder->property_dictionary(); | 606 NameDictionary* property_dictionary = holder->property_dictionary(); |
| 588 property_dictionary->ValueAtPut(dictionary_entry(), *value); | 607 property_dictionary->ValueAtPut(dictionary_entry(), *value); |
| 589 } | 608 } |
| 590 } | 609 } |
| 591 | 610 |
| 592 | 611 |
| 593 bool LookupIterator::HasInterceptor(Map* map) const { | |
| 594 if (IsElement()) return map->has_indexed_interceptor(); | |
| 595 return map->has_named_interceptor(); | |
| 596 } | |
| 597 | |
| 598 | |
| 599 bool LookupIterator::SkipInterceptor(JSObject* holder) { | 612 bool LookupIterator::SkipInterceptor(JSObject* holder) { |
| 600 auto info = GetInterceptor(holder); | 613 auto info = GetInterceptor(holder); |
| 601 // TODO(dcarney): check for symbol/can_intercept_symbols here as well. | 614 // TODO(dcarney): check for symbol/can_intercept_symbols here as well. |
| 602 if (info->non_masking()) { | 615 if (info->non_masking()) { |
| 603 switch (interceptor_state_) { | 616 switch (interceptor_state_) { |
| 604 case InterceptorState::kUninitialized: | 617 case InterceptorState::kUninitialized: |
| 605 interceptor_state_ = InterceptorState::kSkipNonMasking; | 618 interceptor_state_ = InterceptorState::kSkipNonMasking; |
| 606 // Fall through. | 619 // Fall through. |
| 607 case InterceptorState::kSkipNonMasking: | 620 case InterceptorState::kSkipNonMasking: |
| 608 return true; | 621 return true; |
| 609 case InterceptorState::kProcessNonMasking: | 622 case InterceptorState::kProcessNonMasking: |
| 610 return false; | 623 return false; |
| 611 } | 624 } |
| 612 } | 625 } |
| 613 return interceptor_state_ == InterceptorState::kProcessNonMasking; | 626 return interceptor_state_ == InterceptorState::kProcessNonMasking; |
| 614 } | 627 } |
| 615 | 628 |
| 616 | |
| 617 JSReceiver* LookupIterator::NextHolder(Map* map) { | 629 JSReceiver* LookupIterator::NextHolder(Map* map) { |
| 618 DisallowHeapAllocation no_gc; | 630 DisallowHeapAllocation no_gc; |
| 619 if (!map->prototype()->IsJSReceiver()) return NULL; | 631 if (map->prototype() == heap()->null_value()) return NULL; |
| 620 | 632 |
| 621 DCHECK(!map->IsJSGlobalProxyMap() || map->has_hidden_prototype()); | 633 DCHECK(!map->IsJSGlobalProxyMap() || map->has_hidden_prototype()); |
| 622 | 634 |
| 623 if (!check_prototype_chain() && | 635 if (!check_prototype_chain() && |
| 624 !(check_hidden() && map->has_hidden_prototype()) && | 636 !(check_hidden() && map->has_hidden_prototype()) && |
| 625 // Always lookup behind the JSGlobalProxy into the JSGlobalObject, even | 637 // Always lookup behind the JSGlobalProxy into the JSGlobalObject, even |
| 626 // when not checking other hidden prototypes. | 638 // when not checking other hidden prototypes. |
| 627 !map->IsJSGlobalProxyMap()) { | 639 !map->IsJSGlobalProxyMap()) { |
| 628 return NULL; | 640 return NULL; |
| 629 } | 641 } |
| 630 | 642 |
| 631 return JSReceiver::cast(map->prototype()); | 643 return JSReceiver::cast(map->prototype()); |
| 632 } | 644 } |
| 633 | 645 |
| 634 LookupIterator::State LookupIterator::NotFound(JSReceiver* const holder) const { | 646 LookupIterator::State LookupIterator::NotFound(JSReceiver* const holder) const { |
| 635 DCHECK(!IsElement()); | 647 DCHECK(!IsElement()); |
| 636 if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND; | 648 if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND; |
| 637 | 649 |
| 638 Handle<String> name_string = Handle<String>::cast(name_); | 650 Handle<String> name_string = Handle<String>::cast(name_); |
| 639 if (name_string->length() == 0) return NOT_FOUND; | 651 if (name_string->length() == 0) return NOT_FOUND; |
| 640 | 652 |
| 641 return IsSpecialIndex(isolate_->unicode_cache(), *name_string) | 653 return IsSpecialIndex(isolate_->unicode_cache(), *name_string) |
| 642 ? INTEGER_INDEXED_EXOTIC | 654 ? INTEGER_INDEXED_EXOTIC |
| 643 : NOT_FOUND; | 655 : NOT_FOUND; |
| 644 } | 656 } |
| 645 | 657 |
| 646 LookupIterator::State LookupIterator::LookupInHolder(Map* const map, | 658 namespace { |
| 647 JSReceiver* const holder) { | 659 |
| 660 template <bool is_element> |
| 661 bool HasInterceptor(Map* map) { |
| 662 return is_element ? map->has_indexed_interceptor() |
| 663 : map->has_named_interceptor(); |
| 664 } |
| 665 |
| 666 } // namespace |
| 667 |
| 668 template <bool is_element> |
| 669 LookupIterator::State LookupIterator::LookupInSpecialHolder( |
| 670 Map* const map, JSReceiver* const holder) { |
| 648 STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY); | 671 STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY); |
| 649 DisallowHeapAllocation no_gc; | |
| 650 if (interceptor_state_ == InterceptorState::kProcessNonMasking) { | |
| 651 return LookupNonMaskingInterceptorInHolder(map, holder); | |
| 652 } | |
| 653 switch (state_) { | 672 switch (state_) { |
| 654 case NOT_FOUND: | 673 case NOT_FOUND: |
| 655 if (map->IsJSProxyMap()) { | 674 if (map->IsJSProxyMap()) { |
| 656 if (IsElement() || !name_->IsPrivate()) return JSPROXY; | 675 if (is_element || !name_->IsPrivate()) return JSPROXY; |
| 657 } | 676 } |
| 658 if (map->is_access_check_needed()) { | 677 if (map->is_access_check_needed()) { |
| 659 if (IsElement() || !name_->IsPrivate()) return ACCESS_CHECK; | 678 if (is_element || !name_->IsPrivate()) return ACCESS_CHECK; |
| 660 } | 679 } |
| 661 // Fall through. | 680 // Fall through. |
| 662 case ACCESS_CHECK: | 681 case ACCESS_CHECK: |
| 663 if (check_interceptor() && HasInterceptor(map) && | 682 if (check_interceptor() && HasInterceptor<is_element>(map) && |
| 664 !SkipInterceptor(JSObject::cast(holder))) { | 683 !SkipInterceptor(JSObject::cast(holder))) { |
| 665 if (IsElement() || !name_->IsPrivate()) return INTERCEPTOR; | 684 if (is_element || !name_->IsPrivate()) return INTERCEPTOR; |
| 666 } | 685 } |
| 667 // Fall through. | 686 // Fall through. |
| 668 case INTERCEPTOR: | 687 case INTERCEPTOR: |
| 669 if (IsElement()) { | 688 if (!is_element && map->IsJSGlobalObjectMap()) { |
| 670 JSObject* js_object = JSObject::cast(holder); | |
| 671 ElementsAccessor* accessor = js_object->GetElementsAccessor(); | |
| 672 FixedArrayBase* backing_store = js_object->elements(); | |
| 673 number_ = accessor->GetEntryForIndex(js_object, backing_store, index_); | |
| 674 if (number_ == kMaxUInt32) { | |
| 675 return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND; | |
| 676 } | |
| 677 property_details_ = accessor->GetDetails(js_object, number_); | |
| 678 } else if (!map->is_dictionary_map()) { | |
| 679 DescriptorArray* descriptors = map->instance_descriptors(); | |
| 680 int number = descriptors->SearchWithCache(isolate_, *name_, map); | |
| 681 if (number == DescriptorArray::kNotFound) return NotFound(holder); | |
| 682 number_ = static_cast<uint32_t>(number); | |
| 683 property_details_ = descriptors->GetDetails(number_); | |
| 684 } else if (map->IsJSGlobalObjectMap()) { | |
| 685 GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary(); | 689 GlobalDictionary* dict = JSObject::cast(holder)->global_dictionary(); |
| 686 int number = dict->FindEntry(name_); | 690 int number = dict->FindEntry(name_); |
| 687 if (number == GlobalDictionary::kNotFound) return NOT_FOUND; | 691 if (number == GlobalDictionary::kNotFound) return NOT_FOUND; |
| 688 number_ = static_cast<uint32_t>(number); | 692 number_ = static_cast<uint32_t>(number); |
| 689 DCHECK(dict->ValueAt(number_)->IsPropertyCell()); | 693 DCHECK(dict->ValueAt(number_)->IsPropertyCell()); |
| 690 PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_)); | 694 PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_)); |
| 691 if (cell->value()->IsTheHole()) return NOT_FOUND; | 695 if (cell->value()->IsTheHole()) return NOT_FOUND; |
| 692 property_details_ = cell->property_details(); | 696 property_details_ = cell->property_details(); |
| 693 } else { | 697 has_property_ = true; |
| 694 NameDictionary* dict = holder->property_dictionary(); | 698 switch (property_details_.kind()) { |
| 695 int number = dict->FindEntry(name_); | 699 case v8::internal::kData: |
| 696 if (number == NameDictionary::kNotFound) return NotFound(holder); | 700 return DATA; |
| 697 number_ = static_cast<uint32_t>(number); | 701 case v8::internal::kAccessor: |
| 698 property_details_ = dict->DetailsAt(number_); | 702 return ACCESSOR; |
| 703 } |
| 699 } | 704 } |
| 700 has_property_ = true; | 705 return LookupInRegularHolder<is_element>(map, holder); |
| 701 switch (property_details_.kind()) { | |
| 702 case v8::internal::kData: | |
| 703 return DATA; | |
| 704 case v8::internal::kAccessor: | |
| 705 return ACCESSOR; | |
| 706 } | |
| 707 case ACCESSOR: | 706 case ACCESSOR: |
| 708 case DATA: | 707 case DATA: |
| 709 return NOT_FOUND; | 708 return NOT_FOUND; |
| 710 case INTEGER_INDEXED_EXOTIC: | 709 case INTEGER_INDEXED_EXOTIC: |
| 711 case JSPROXY: | 710 case JSPROXY: |
| 712 case TRANSITION: | 711 case TRANSITION: |
| 713 UNREACHABLE(); | 712 UNREACHABLE(); |
| 714 } | 713 } |
| 715 UNREACHABLE(); | 714 UNREACHABLE(); |
| 716 return state_; | 715 return NOT_FOUND; |
| 717 } | 716 } |
| 718 | 717 |
| 718 template <bool is_element> |
| 719 LookupIterator::State LookupIterator::LookupInRegularHolder( |
| 720 Map* const map, JSReceiver* const holder) { |
| 721 DisallowHeapAllocation no_gc; |
| 722 if (interceptor_state_ == InterceptorState::kProcessNonMasking) { |
| 723 return NOT_FOUND; |
| 724 } |
| 719 | 725 |
| 720 LookupIterator::State LookupIterator::LookupNonMaskingInterceptorInHolder( | 726 if (is_element) { |
| 721 Map* const map, JSReceiver* const holder) { | 727 JSObject* js_object = JSObject::cast(holder); |
| 722 switch (state_) { | 728 ElementsAccessor* accessor = js_object->GetElementsAccessor(); |
| 723 case NOT_FOUND: | 729 FixedArrayBase* backing_store = js_object->elements(); |
| 724 if (check_interceptor() && HasInterceptor(map) && | 730 number_ = accessor->GetEntryForIndex(js_object, backing_store, index_); |
| 725 !SkipInterceptor(JSObject::cast(holder))) { | 731 if (number_ == kMaxUInt32) { |
| 726 return INTERCEPTOR; | 732 return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND; |
| 727 } | 733 } |
| 728 // Fall through. | 734 property_details_ = accessor->GetDetails(js_object, number_); |
| 729 default: | 735 } else if (!map->is_dictionary_map()) { |
| 730 return NOT_FOUND; | 736 DescriptorArray* descriptors = map->instance_descriptors(); |
| 737 int number = descriptors->SearchWithCache(isolate_, *name_, map); |
| 738 if (number == DescriptorArray::kNotFound) return NotFound(holder); |
| 739 number_ = static_cast<uint32_t>(number); |
| 740 property_details_ = descriptors->GetDetails(number_); |
| 741 } else { |
| 742 NameDictionary* dict = holder->property_dictionary(); |
| 743 int number = dict->FindEntry(name_); |
| 744 if (number == NameDictionary::kNotFound) return NotFound(holder); |
| 745 number_ = static_cast<uint32_t>(number); |
| 746 property_details_ = dict->DetailsAt(number_); |
| 731 } | 747 } |
| 748 has_property_ = true; |
| 749 switch (property_details_.kind()) { |
| 750 case v8::internal::kData: |
| 751 return DATA; |
| 752 case v8::internal::kAccessor: |
| 753 return ACCESSOR; |
| 754 } |
| 755 |
| 732 UNREACHABLE(); | 756 UNREACHABLE(); |
| 733 return state_; | 757 return state_; |
| 734 } | 758 } |
| 735 | 759 |
| 736 } // namespace internal | 760 } // namespace internal |
| 737 } // namespace v8 | 761 } // namespace v8 |
| OLD | NEW |