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