OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 <iomanip> | 5 #include <iomanip> |
6 #include <sstream> | 6 #include <sstream> |
7 | 7 |
8 #include "src/v8.h" | 8 #include "src/v8.h" |
9 | 9 |
10 #include "src/accessors.h" | 10 #include "src/accessors.h" |
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 return CallTrap( | 300 return CallTrap( |
301 proxy, "get", isolate->derived_get_trap(), arraysize(args), args); | 301 proxy, "get", isolate->derived_get_trap(), arraysize(args), args); |
302 } | 302 } |
303 | 303 |
304 | 304 |
305 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) { | 305 MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) { |
306 Isolate* isolate = it->isolate(); | 306 Isolate* isolate = it->isolate(); |
307 Handle<Object> structure = it->GetAccessors(); | 307 Handle<Object> structure = it->GetAccessors(); |
308 Handle<Object> receiver = it->GetReceiver(); | 308 Handle<Object> receiver = it->GetReceiver(); |
309 | 309 |
| 310 // We should never get here to initialize a const with the hole value since a |
| 311 // const declaration would conflict with the getter. |
310 DCHECK(!structure->IsForeign()); | 312 DCHECK(!structure->IsForeign()); |
311 // api style callbacks. | 313 |
| 314 // API style callbacks. |
312 if (structure->IsAccessorInfo()) { | 315 if (structure->IsAccessorInfo()) { |
313 Handle<JSObject> holder = it->GetHolder<JSObject>(); | 316 Handle<JSObject> holder = it->GetHolder<JSObject>(); |
314 Handle<Name> name = it->GetName(); | 317 Handle<Name> name = it->GetName(); |
315 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure); | 318 Handle<ExecutableAccessorInfo> info = |
| 319 Handle<ExecutableAccessorInfo>::cast(structure); |
316 if (!info->IsCompatibleReceiver(*receiver)) { | 320 if (!info->IsCompatibleReceiver(*receiver)) { |
317 THROW_NEW_ERROR(isolate, | 321 THROW_NEW_ERROR(isolate, |
318 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, | 322 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, |
319 name, receiver), | 323 name, receiver), |
320 Object); | 324 Object); |
321 } | 325 } |
322 | 326 |
323 Handle<ExecutableAccessorInfo> data = | |
324 Handle<ExecutableAccessorInfo>::cast(structure); | |
325 v8::AccessorNameGetterCallback call_fun = | 327 v8::AccessorNameGetterCallback call_fun = |
326 v8::ToCData<v8::AccessorNameGetterCallback>(data->getter()); | 328 v8::ToCData<v8::AccessorNameGetterCallback>(info->getter()); |
327 if (call_fun == NULL) return isolate->factory()->undefined_value(); | 329 if (call_fun == nullptr) return isolate->factory()->undefined_value(); |
328 | 330 |
329 LOG(isolate, ApiNamedPropertyAccess("load", *holder, *name)); | 331 LOG(isolate, ApiNamedPropertyAccess("load", *holder, *name)); |
330 PropertyCallbackArguments args(isolate, data->data(), *receiver, *holder); | 332 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder); |
331 v8::Handle<v8::Value> result = | 333 v8::Handle<v8::Value> result = |
332 args.Call(call_fun, v8::Utils::ToLocal(name)); | 334 args.Call(call_fun, v8::Utils::ToLocal(name)); |
333 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | 335 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
334 if (result.IsEmpty()) { | 336 if (result.IsEmpty()) { |
335 return isolate->factory()->undefined_value(); | 337 return isolate->factory()->undefined_value(); |
336 } | 338 } |
337 Handle<Object> return_value = v8::Utils::OpenHandle(*result); | 339 Handle<Object> return_value = v8::Utils::OpenHandle(*result); |
338 return_value->VerifyApiCallResultType(); | 340 return_value->VerifyApiCallResultType(); |
339 // Rebox handle before return. | 341 // Rebox handle before return. |
340 return handle(*return_value, isolate); | 342 return handle(*return_value, isolate); |
341 } | 343 } |
342 | 344 |
343 // __defineGetter__ callback | 345 // Regular accessor. |
344 Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(), | 346 Handle<Object> getter(AccessorPair::cast(*structure)->getter(), isolate); |
345 isolate); | |
346 if (getter->IsSpecFunction()) { | 347 if (getter->IsSpecFunction()) { |
347 // TODO(rossberg): nicer would be to cast to some JSCallable here... | 348 // TODO(rossberg): nicer would be to cast to some JSCallable here... |
348 return Object::GetPropertyWithDefinedGetter( | 349 return Object::GetPropertyWithDefinedGetter( |
349 receiver, Handle<JSReceiver>::cast(getter)); | 350 receiver, Handle<JSReceiver>::cast(getter)); |
350 } | 351 } |
351 // Getter is not a function. | 352 // Getter is not a function. |
352 return isolate->factory()->undefined_value(); | 353 return isolate->factory()->undefined_value(); |
353 } | 354 } |
354 | 355 |
355 | 356 |
356 bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate, | 357 bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate, |
357 Handle<AccessorInfo> info, | 358 Handle<AccessorInfo> info, |
358 Handle<Map> map) { | 359 Handle<Map> map) { |
359 if (!info->HasExpectedReceiverType()) return true; | 360 if (!info->HasExpectedReceiverType()) return true; |
360 if (!map->IsJSObjectMap()) return false; | 361 if (!map->IsJSObjectMap()) return false; |
361 return FunctionTemplateInfo::cast(info->expected_receiver_type()) | 362 return FunctionTemplateInfo::cast(info->expected_receiver_type()) |
362 ->IsTemplateFor(*map); | 363 ->IsTemplateFor(*map); |
363 } | 364 } |
364 | 365 |
365 | 366 |
366 MaybeHandle<Object> Object::SetPropertyWithAccessor( | 367 MaybeHandle<Object> Object::SetPropertyWithAccessor( |
367 Handle<Object> receiver, Handle<Name> name, Handle<Object> value, | 368 LookupIterator* it, Handle<Object> value, LanguageMode language_mode) { |
368 Handle<JSObject> holder, Handle<Object> structure, | 369 Isolate* isolate = it->isolate(); |
369 LanguageMode language_mode) { | 370 Handle<Object> structure = it->GetAccessors(); |
370 Isolate* isolate = name->GetIsolate(); | 371 Handle<Object> receiver = it->GetReceiver(); |
371 | 372 |
372 // We should never get here to initialize a const with the hole | 373 // We should never get here to initialize a const with the hole value since a |
373 // value since a const declaration would conflict with the setter. | 374 // const declaration would conflict with the setter. |
374 DCHECK(!structure->IsForeign()); | 375 DCHECK(!structure->IsForeign()); |
| 376 |
| 377 // API style callbacks. |
375 if (structure->IsExecutableAccessorInfo()) { | 378 if (structure->IsExecutableAccessorInfo()) { |
376 // Don't call executable accessor setters with non-JSObject receivers. | 379 Handle<JSObject> holder = it->GetHolder<JSObject>(); |
377 if (!receiver->IsJSObject()) return value; | 380 Handle<Name> name = it->GetName(); |
378 // api style callbacks | 381 Handle<ExecutableAccessorInfo> info = |
379 ExecutableAccessorInfo* info = ExecutableAccessorInfo::cast(*structure); | 382 Handle<ExecutableAccessorInfo>::cast(structure); |
380 if (!info->IsCompatibleReceiver(*receiver)) { | 383 if (!info->IsCompatibleReceiver(*receiver)) { |
381 THROW_NEW_ERROR(isolate, | 384 THROW_NEW_ERROR(isolate, |
382 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, | 385 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, |
383 name, receiver), | 386 name, receiver), |
384 Object); | 387 Object); |
385 } | 388 } |
386 Object* call_obj = info->setter(); | 389 |
387 v8::AccessorNameSetterCallback call_fun = | 390 v8::AccessorNameSetterCallback call_fun = |
388 v8::ToCData<v8::AccessorNameSetterCallback>(call_obj); | 391 v8::ToCData<v8::AccessorNameSetterCallback>(info->setter()); |
389 if (call_fun == NULL) return value; | 392 if (call_fun == nullptr) return value; |
| 393 |
390 LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name)); | 394 LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name)); |
391 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder); | 395 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder); |
392 args.Call(call_fun, | 396 args.Call(call_fun, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value)); |
393 v8::Utils::ToLocal(name), | |
394 v8::Utils::ToLocal(value)); | |
395 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | 397 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
396 return value; | 398 return value; |
397 } | 399 } |
398 | 400 |
399 if (structure->IsAccessorPair()) { | 401 // Regular accessor. |
400 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate); | 402 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate); |
401 if (setter->IsSpecFunction()) { | 403 if (setter->IsSpecFunction()) { |
402 // TODO(rossberg): nicer would be to cast to some JSCallable here... | 404 // TODO(rossberg): nicer would be to cast to some JSCallable here... |
403 return SetPropertyWithDefinedSetter( | 405 return SetPropertyWithDefinedSetter( |
404 receiver, Handle<JSReceiver>::cast(setter), value); | 406 receiver, Handle<JSReceiver>::cast(setter), value); |
405 } else { | |
406 if (is_sloppy(language_mode)) return value; | |
407 THROW_NEW_ERROR( | |
408 isolate, | |
409 NewTypeError(MessageTemplate::kNoSetterInCallback, name, holder), | |
410 Object); | |
411 } | |
412 } | 407 } |
413 | 408 |
414 UNREACHABLE(); | 409 if (is_sloppy(language_mode)) return value; |
415 return MaybeHandle<Object>(); | 410 |
| 411 THROW_NEW_ERROR(isolate, |
| 412 NewTypeError(MessageTemplate::kNoSetterInCallback, |
| 413 it->GetName(), it->GetHolder<JSObject>()), |
| 414 Object); |
416 } | 415 } |
417 | 416 |
418 | 417 |
419 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter( | 418 MaybeHandle<Object> Object::GetPropertyWithDefinedGetter( |
420 Handle<Object> receiver, | 419 Handle<Object> receiver, |
421 Handle<JSReceiver> getter) { | 420 Handle<JSReceiver> getter) { |
422 Isolate* isolate = getter->GetIsolate(); | 421 Isolate* isolate = getter->GetIsolate(); |
423 | 422 |
424 // Platforms with simulators like arm/arm64 expose a funny issue. If the | 423 // Platforms with simulators like arm/arm64 expose a funny issue. If the |
425 // simulator has a separate JS stack pointer from the C++ stack pointer, it | 424 // simulator has a separate JS stack pointer from the C++ stack pointer, it |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 } | 532 } |
534 } | 533 } |
535 return false; | 534 return false; |
536 } | 535 } |
537 | 536 |
538 | 537 |
539 MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck( | 538 MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck( |
540 LookupIterator* it, Handle<Object> value, LanguageMode language_mode) { | 539 LookupIterator* it, Handle<Object> value, LanguageMode language_mode) { |
541 Handle<JSObject> checked = it->GetHolder<JSObject>(); | 540 Handle<JSObject> checked = it->GetHolder<JSObject>(); |
542 if (FindAllCanWriteHolder(it)) { | 541 if (FindAllCanWriteHolder(it)) { |
543 return SetPropertyWithAccessor(it->GetReceiver(), it->GetName(), value, | 542 return SetPropertyWithAccessor(it, value, language_mode); |
544 it->GetHolder<JSObject>(), | |
545 it->GetAccessors(), language_mode); | |
546 } | 543 } |
547 | 544 |
548 it->isolate()->ReportFailedAccessCheck(checked); | 545 it->isolate()->ReportFailedAccessCheck(checked); |
549 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); | 546 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); |
550 return value; | 547 return value; |
551 } | 548 } |
552 | 549 |
553 | 550 |
554 void JSObject::SetNormalizedProperty(Handle<JSObject> object, | 551 void JSObject::SetNormalizedProperty(Handle<JSObject> object, |
555 Handle<Name> name, | 552 Handle<Name> name, |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
590 PropertyDetails original_details = property_dictionary->DetailsAt(entry); | 587 PropertyDetails original_details = property_dictionary->DetailsAt(entry); |
591 int enumeration_index = original_details.dictionary_index(); | 588 int enumeration_index = original_details.dictionary_index(); |
592 DCHECK(enumeration_index > 0); | 589 DCHECK(enumeration_index > 0); |
593 details = details.set_index(enumeration_index); | 590 details = details.set_index(enumeration_index); |
594 property_dictionary->SetEntry(entry, name, value, details); | 591 property_dictionary->SetEntry(entry, name, value, details); |
595 } | 592 } |
596 } | 593 } |
597 } | 594 } |
598 | 595 |
599 | 596 |
600 MaybeHandle<Object> Object::SetElementWithReceiver( | |
601 Isolate* isolate, Handle<Object> object, Handle<Object> receiver, | |
602 uint32_t index, Handle<Object> value, LanguageMode language_mode) { | |
603 // Iterate up the prototype chain until an element is found or the null | |
604 // prototype is encountered. | |
605 bool done = false; | |
606 for (PrototypeIterator iter(isolate, object, | |
607 object->IsJSProxy() || object->IsJSObject() | |
608 ? PrototypeIterator::START_AT_RECEIVER | |
609 : PrototypeIterator::START_AT_PROTOTYPE); | |
610 !iter.IsAtEnd() && !done; iter.Advance()) { | |
611 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | |
612 // TODO(dslomov): implement. | |
613 isolate->ThrowIllegalOperation(); | |
614 return MaybeHandle<Object>(); | |
615 } | |
616 | |
617 Handle<JSObject> js_object = | |
618 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
619 | |
620 // Check access rights if needed. | |
621 if (js_object->IsAccessCheckNeeded()) { | |
622 if (!isolate->MayAccess(js_object)) { | |
623 isolate->ReportFailedAccessCheck(js_object); | |
624 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
625 return isolate->factory()->undefined_value(); | |
626 } | |
627 } | |
628 | |
629 if (js_object->HasIndexedInterceptor()) { | |
630 LookupIterator it(isolate, receiver, index, js_object, | |
631 LookupIterator::OWN); | |
632 Maybe<PropertyAttributes> from_interceptor = | |
633 JSObject::GetPropertyAttributes(&it); | |
634 if (!from_interceptor.IsJust()) return MaybeHandle<Object>(); | |
635 if ((from_interceptor.FromJust() & READ_ONLY) != 0) { | |
636 return WriteToReadOnlyElement(isolate, receiver, index, value, | |
637 language_mode); | |
638 } | |
639 done = from_interceptor.FromJust() != ABSENT; | |
640 } | |
641 | |
642 if (!done && | |
643 js_object->elements() != isolate->heap()->empty_fixed_array()) { | |
644 ElementsAccessor* accessor = js_object->GetElementsAccessor(); | |
645 PropertyAttributes attrs = accessor->GetAttributes(js_object, index); | |
646 if ((attrs & READ_ONLY) != 0) { | |
647 return WriteToReadOnlyElement(isolate, receiver, index, value, | |
648 language_mode); | |
649 } | |
650 Handle<AccessorPair> pair; | |
651 if (accessor->GetAccessorPair(js_object, index).ToHandle(&pair)) { | |
652 return JSObject::SetElementWithCallback(receiver, pair, index, value, | |
653 js_object, language_mode); | |
654 } else { | |
655 done = attrs != ABSENT; | |
656 } | |
657 } | |
658 } | |
659 | |
660 if (!receiver->IsJSObject()) { | |
661 return WriteToReadOnlyElement(isolate, receiver, index, value, | |
662 language_mode); | |
663 } | |
664 Handle<JSObject> target = Handle<JSObject>::cast(receiver); | |
665 ElementsAccessor* accessor = target->GetElementsAccessor(); | |
666 PropertyAttributes attrs = accessor->GetAttributes(target, index); | |
667 if (attrs == ABSENT) { | |
668 return JSObject::SetElement(target, index, value, NONE, language_mode, | |
669 false); | |
670 } | |
671 return JSObject::SetElement(target, index, value, attrs, language_mode, false, | |
672 DEFINE_PROPERTY); | |
673 } | |
674 | |
675 | |
676 Map* Object::GetRootMap(Isolate* isolate) { | 597 Map* Object::GetRootMap(Isolate* isolate) { |
677 DisallowHeapAllocation no_alloc; | 598 DisallowHeapAllocation no_alloc; |
678 if (IsSmi()) { | 599 if (IsSmi()) { |
679 Context* context = isolate->context()->native_context(); | 600 Context* context = isolate->context()->native_context(); |
680 return context->number_function()->initial_map(); | 601 return context->number_function()->initial_map(); |
681 } | 602 } |
682 | 603 |
683 HeapObject* heap_object = HeapObject::cast(this); | 604 HeapObject* heap_object = HeapObject::cast(this); |
684 | 605 |
685 // The object is either a number, a string, a boolean, | 606 // The object is either a number, a string, a boolean, |
(...skipping 2344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3030 Handle<Map> Map::Update(Handle<Map> map) { | 2951 Handle<Map> Map::Update(Handle<Map> map) { |
3031 if (!map->is_deprecated()) return map; | 2952 if (!map->is_deprecated()) return map; |
3032 return ReconfigureProperty(map, -1, kData, NONE, Representation::None(), | 2953 return ReconfigureProperty(map, -1, kData, NONE, Representation::None(), |
3033 HeapType::None(map->GetIsolate()), | 2954 HeapType::None(map->GetIsolate()), |
3034 ALLOW_IN_DESCRIPTOR); | 2955 ALLOW_IN_DESCRIPTOR); |
3035 } | 2956 } |
3036 | 2957 |
3037 | 2958 |
3038 MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(LookupIterator* it, | 2959 MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(LookupIterator* it, |
3039 Handle<Object> value) { | 2960 Handle<Object> value) { |
3040 Handle<Name> name = it->name(); | 2961 Isolate* isolate = it->isolate(); |
| 2962 // Make sure that the top context does not change when doing callbacks or |
| 2963 // interceptor calls. |
| 2964 AssertNoContextChange ncc(isolate); |
| 2965 |
| 2966 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); |
| 2967 Handle<InterceptorInfo> interceptor(it->GetInterceptor()); |
| 2968 if (interceptor->setter()->IsUndefined()) return MaybeHandle<Object>(); |
| 2969 |
3041 Handle<JSObject> holder = it->GetHolder<JSObject>(); | 2970 Handle<JSObject> holder = it->GetHolder<JSObject>(); |
3042 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor()); | 2971 v8::Handle<v8::Value> result; |
3043 if (interceptor->setter()->IsUndefined() || | 2972 PropertyCallbackArguments args(isolate, interceptor->data(), |
3044 (name->IsSymbol() && !interceptor->can_intercept_symbols())) { | 2973 *it->GetReceiver(), *holder); |
3045 return MaybeHandle<Object>(); | 2974 |
| 2975 if (it->IsElement()) { |
| 2976 uint32_t index = it->index(); |
| 2977 v8::IndexedPropertySetterCallback setter = |
| 2978 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter()); |
| 2979 LOG(isolate, |
| 2980 ApiIndexedPropertyAccess("interceptor-indexed-set", *holder, index)); |
| 2981 result = args.Call(setter, index, v8::Utils::ToLocal(value)); |
| 2982 } else { |
| 2983 Handle<Name> name = it->name(); |
| 2984 |
| 2985 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) { |
| 2986 return MaybeHandle<Object>(); |
| 2987 } |
| 2988 |
| 2989 v8::GenericNamedPropertySetterCallback setter = |
| 2990 v8::ToCData<v8::GenericNamedPropertySetterCallback>( |
| 2991 interceptor->setter()); |
| 2992 LOG(it->isolate(), |
| 2993 ApiNamedPropertyAccess("interceptor-named-set", *holder, *name)); |
| 2994 result = |
| 2995 args.Call(setter, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value)); |
3046 } | 2996 } |
3047 | 2997 |
3048 LOG(it->isolate(), | |
3049 ApiNamedPropertyAccess("interceptor-named-set", *holder, *name)); | |
3050 PropertyCallbackArguments args(it->isolate(), interceptor->data(), *holder, | |
3051 *holder); | |
3052 v8::GenericNamedPropertySetterCallback setter = | |
3053 v8::ToCData<v8::GenericNamedPropertySetterCallback>( | |
3054 interceptor->setter()); | |
3055 v8::Handle<v8::Value> result = | |
3056 args.Call(setter, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value)); | |
3057 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); | 2998 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object); |
3058 if (!result.IsEmpty()) return value; | 2999 if (result.IsEmpty()) return MaybeHandle<Object>(); |
3059 | 3000 #ifdef DEBUG |
3060 return MaybeHandle<Object>(); | 3001 Handle<Object> result_internal = v8::Utils::OpenHandle(*result); |
| 3002 result_internal->VerifyApiCallResultType(); |
| 3003 #endif |
| 3004 return value; |
3061 } | 3005 } |
3062 | 3006 |
3063 | 3007 |
3064 MaybeHandle<Object> Object::SetProperty(Handle<Object> object, | 3008 MaybeHandle<Object> Object::SetProperty(Handle<Object> object, |
3065 Handle<Name> name, Handle<Object> value, | 3009 Handle<Name> name, Handle<Object> value, |
3066 LanguageMode language_mode, | 3010 LanguageMode language_mode, |
3067 StoreFromKeyed store_mode) { | 3011 StoreFromKeyed store_mode) { |
3068 LookupIterator it(object, name); | 3012 LookupIterator it(object, name); |
3069 return SetProperty(&it, value, language_mode, store_mode); | 3013 return SetProperty(&it, value, language_mode, store_mode); |
3070 } | 3014 } |
(...skipping 10 matching lines...) Expand all Loading... |
3081 | 3025 |
3082 *found = true; | 3026 *found = true; |
3083 | 3027 |
3084 bool done = false; | 3028 bool done = false; |
3085 for (; it->IsFound(); it->Next()) { | 3029 for (; it->IsFound(); it->Next()) { |
3086 switch (it->state()) { | 3030 switch (it->state()) { |
3087 case LookupIterator::NOT_FOUND: | 3031 case LookupIterator::NOT_FOUND: |
3088 UNREACHABLE(); | 3032 UNREACHABLE(); |
3089 | 3033 |
3090 case LookupIterator::ACCESS_CHECK: | 3034 case LookupIterator::ACCESS_CHECK: |
3091 // TODO(verwaest): Remove the distinction. This is mostly bogus since we | |
3092 // don't know whether we'll want to fetch attributes or call a setter | |
3093 // until we find the property. | |
3094 if (it->HasAccess()) break; | 3035 if (it->HasAccess()) break; |
| 3036 // Check whether it makes sense to reuse the lookup iterator. Here it |
| 3037 // might still call into setters up the prototype chain. |
3095 return JSObject::SetPropertyWithFailedAccessCheck(it, value, | 3038 return JSObject::SetPropertyWithFailedAccessCheck(it, value, |
3096 language_mode); | 3039 language_mode); |
3097 | 3040 |
3098 case LookupIterator::JSPROXY: | 3041 case LookupIterator::JSPROXY: |
3099 if (it->HolderIsReceiverOrHiddenPrototype()) { | 3042 if (it->HolderIsReceiverOrHiddenPrototype()) { |
3100 return JSProxy::SetPropertyWithHandler( | 3043 return JSProxy::SetPropertyWithHandler( |
3101 it->GetHolder<JSProxy>(), it->GetReceiver(), it->GetName(), value, | 3044 it->GetHolder<JSProxy>(), it->GetReceiver(), it->GetName(), value, |
3102 language_mode); | 3045 language_mode); |
3103 } else { | 3046 } else { |
3104 // TODO(verwaest): Use the MaybeHandle to indicate result. | 3047 // TODO(verwaest): Use the MaybeHandle to indicate result. |
(...skipping 18 matching lines...) Expand all Loading... |
3123 JSObject::GetPropertyAttributesWithInterceptor(it); | 3066 JSObject::GetPropertyAttributesWithInterceptor(it); |
3124 if (!maybe_attributes.IsJust()) return MaybeHandle<Object>(); | 3067 if (!maybe_attributes.IsJust()) return MaybeHandle<Object>(); |
3125 done = maybe_attributes.FromJust() != ABSENT; | 3068 done = maybe_attributes.FromJust() != ABSENT; |
3126 if (done && (maybe_attributes.FromJust() & READ_ONLY) != 0) { | 3069 if (done && (maybe_attributes.FromJust() & READ_ONLY) != 0) { |
3127 return WriteToReadOnlyProperty(it, value, language_mode); | 3070 return WriteToReadOnlyProperty(it, value, language_mode); |
3128 } | 3071 } |
3129 } | 3072 } |
3130 break; | 3073 break; |
3131 | 3074 |
3132 case LookupIterator::ACCESSOR: { | 3075 case LookupIterator::ACCESSOR: { |
3133 if (it->property_details().IsReadOnly()) { | 3076 if (it->IsReadOnly()) { |
3134 return WriteToReadOnlyProperty(it, value, language_mode); | 3077 return WriteToReadOnlyProperty(it, value, language_mode); |
3135 } | 3078 } |
3136 Handle<Object> accessors = it->GetAccessors(); | 3079 Handle<Object> accessors = it->GetAccessors(); |
3137 if (accessors->IsAccessorInfo() && | 3080 if (accessors->IsAccessorInfo() && |
3138 !it->HolderIsReceiverOrHiddenPrototype() && | 3081 !it->HolderIsReceiverOrHiddenPrototype() && |
3139 AccessorInfo::cast(*accessors)->is_special_data_property()) { | 3082 AccessorInfo::cast(*accessors)->is_special_data_property()) { |
3140 done = true; | 3083 done = true; |
3141 break; | 3084 break; |
3142 } | 3085 } |
3143 return SetPropertyWithAccessor(it->GetReceiver(), it->GetName(), value, | 3086 return SetPropertyWithAccessor(it, value, language_mode); |
3144 it->GetHolder<JSObject>(), accessors, | |
3145 language_mode); | |
3146 } | 3087 } |
3147 case LookupIterator::INTEGER_INDEXED_EXOTIC: | 3088 case LookupIterator::INTEGER_INDEXED_EXOTIC: |
3148 done = true; | 3089 done = true; |
3149 break; | 3090 break; |
3150 | 3091 |
3151 case LookupIterator::DATA: | 3092 case LookupIterator::DATA: |
3152 if (it->property_details().IsReadOnly()) { | 3093 if (it->IsReadOnly()) { |
3153 return WriteToReadOnlyProperty(it, value, language_mode); | 3094 return WriteToReadOnlyProperty(it, value, language_mode); |
3154 } | 3095 } |
3155 if (it->HolderIsReceiverOrHiddenPrototype()) { | 3096 if (it->HolderIsReceiverOrHiddenPrototype()) { |
3156 return SetDataProperty(it, value); | 3097 return SetDataProperty(it, value); |
3157 } | 3098 } |
3158 done = true; | 3099 done = true; |
3159 break; | 3100 break; |
3160 | 3101 |
3161 case LookupIterator::TRANSITION: | 3102 case LookupIterator::TRANSITION: |
3162 done = true; | 3103 done = true; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3195 MaybeHandle<Object> Object::SetSuperProperty(LookupIterator* it, | 3136 MaybeHandle<Object> Object::SetSuperProperty(LookupIterator* it, |
3196 Handle<Object> value, | 3137 Handle<Object> value, |
3197 LanguageMode language_mode, | 3138 LanguageMode language_mode, |
3198 StoreFromKeyed store_mode) { | 3139 StoreFromKeyed store_mode) { |
3199 bool found = false; | 3140 bool found = false; |
3200 MaybeHandle<Object> result = | 3141 MaybeHandle<Object> result = |
3201 SetPropertyInternal(it, value, language_mode, store_mode, &found); | 3142 SetPropertyInternal(it, value, language_mode, store_mode, &found); |
3202 if (found) return result; | 3143 if (found) return result; |
3203 | 3144 |
3204 if (!it->GetReceiver()->IsJSReceiver()) { | 3145 if (!it->GetReceiver()->IsJSReceiver()) { |
3205 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), it->name(), | 3146 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), |
3206 value, language_mode); | 3147 it->GetName(), value, language_mode); |
3207 } | 3148 } |
3208 | 3149 |
3209 LookupIterator own_lookup(it->GetReceiver(), it->name(), LookupIterator::OWN); | 3150 LookupIterator::Configuration c = LookupIterator::OWN; |
| 3151 LookupIterator own_lookup = |
| 3152 it->IsElement() |
| 3153 ? LookupIterator(it->isolate(), it->GetReceiver(), it->index(), c) |
| 3154 : LookupIterator(it->GetReceiver(), it->name(), c); |
3210 | 3155 |
3211 switch (own_lookup.state()) { | 3156 for (; own_lookup.IsFound(); own_lookup.Next()) { |
3212 case LookupIterator::NOT_FOUND: | 3157 switch (own_lookup.state()) { |
3213 return JSObject::AddDataProperty(&own_lookup, value, NONE, language_mode, | 3158 case LookupIterator::ACCESS_CHECK: |
3214 store_mode); | 3159 if (!it->isolate()->MayAccess(own_lookup.GetHolder<JSObject>())) { |
| 3160 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value, |
| 3161 language_mode); |
| 3162 } |
| 3163 break; |
3215 | 3164 |
3216 case LookupIterator::INTEGER_INDEXED_EXOTIC: | 3165 case LookupIterator::INTEGER_INDEXED_EXOTIC: |
3217 return result; | 3166 return result; |
3218 | 3167 |
3219 case LookupIterator::DATA: { | 3168 case LookupIterator::DATA: { |
3220 PropertyDetails details = own_lookup.property_details(); | 3169 PropertyDetails details = own_lookup.property_details(); |
3221 if (details.IsConfigurable() || !details.IsReadOnly()) { | 3170 if (details.IsConfigurable() || !details.IsReadOnly()) { |
3222 return JSObject::SetOwnPropertyIgnoreAttributes( | 3171 return JSObject::ReconfigureAsDataProperty(&own_lookup, value, |
3223 Handle<JSObject>::cast(it->GetReceiver()), it->name(), value, | 3172 details.attributes()); |
3224 details.attributes()); | 3173 } |
3225 } | 3174 return WriteToReadOnlyProperty(&own_lookup, value, language_mode); |
3226 return WriteToReadOnlyProperty(&own_lookup, value, language_mode); | |
3227 } | |
3228 | |
3229 case LookupIterator::ACCESSOR: { | |
3230 PropertyDetails details = own_lookup.property_details(); | |
3231 if (details.IsConfigurable()) { | |
3232 return JSObject::SetOwnPropertyIgnoreAttributes( | |
3233 Handle<JSObject>::cast(it->GetReceiver()), it->name(), value, | |
3234 details.attributes()); | |
3235 } | 3175 } |
3236 | 3176 |
3237 return RedefineNonconfigurableProperty(it->isolate(), it->name(), value, | 3177 case LookupIterator::ACCESSOR: { |
3238 language_mode); | 3178 PropertyDetails details = own_lookup.property_details(); |
3239 } | 3179 if (details.IsConfigurable()) { |
| 3180 return JSObject::ReconfigureAsDataProperty(&own_lookup, value, |
| 3181 details.attributes()); |
| 3182 } |
3240 | 3183 |
3241 case LookupIterator::TRANSITION: | 3184 return RedefineNonconfigurableProperty(it->isolate(), it->GetName(), |
3242 UNREACHABLE(); | 3185 value, language_mode); |
3243 break; | 3186 } |
3244 | 3187 |
3245 case LookupIterator::INTERCEPTOR: | 3188 case LookupIterator::INTERCEPTOR: |
3246 case LookupIterator::JSPROXY: | 3189 case LookupIterator::JSPROXY: { |
3247 case LookupIterator::ACCESS_CHECK: { | 3190 bool found = false; |
3248 bool found = false; | 3191 MaybeHandle<Object> result = SetPropertyInternal( |
3249 MaybeHandle<Object> result = SetPropertyInternal( | 3192 &own_lookup, value, language_mode, store_mode, &found); |
3250 &own_lookup, value, language_mode, store_mode, &found); | 3193 if (found) return result; |
3251 if (found) return result; | 3194 break; |
3252 return SetDataProperty(&own_lookup, value); | 3195 } |
| 3196 |
| 3197 case LookupIterator::NOT_FOUND: |
| 3198 case LookupIterator::TRANSITION: |
| 3199 UNREACHABLE(); |
3253 } | 3200 } |
3254 } | 3201 } |
3255 | 3202 |
3256 UNREACHABLE(); | 3203 return JSObject::AddDataProperty(&own_lookup, value, NONE, language_mode, |
3257 return MaybeHandle<Object>(); | 3204 store_mode); |
3258 } | 3205 } |
3259 | 3206 |
3260 | 3207 |
3261 MaybeHandle<Object> Object::WriteToReadOnlyProperty( | 3208 MaybeHandle<Object> Object::WriteToReadOnlyProperty( |
3262 LookupIterator* it, Handle<Object> value, LanguageMode language_mode) { | 3209 LookupIterator* it, Handle<Object> value, LanguageMode language_mode) { |
3263 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), it->name(), | 3210 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), |
3264 value, language_mode); | 3211 it->GetName(), value, language_mode); |
3265 } | 3212 } |
3266 | 3213 |
3267 | 3214 |
3268 MaybeHandle<Object> Object::WriteToReadOnlyProperty( | 3215 MaybeHandle<Object> Object::WriteToReadOnlyProperty( |
3269 Isolate* isolate, Handle<Object> receiver, Handle<Object> name, | 3216 Isolate* isolate, Handle<Object> receiver, Handle<Object> name, |
3270 Handle<Object> value, LanguageMode language_mode) { | 3217 Handle<Object> value, LanguageMode language_mode) { |
3271 if (is_sloppy(language_mode)) return value; | 3218 if (is_sloppy(language_mode)) return value; |
3272 THROW_NEW_ERROR( | 3219 THROW_NEW_ERROR( |
3273 isolate, | 3220 isolate, |
3274 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name, receiver), | 3221 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, name, receiver), |
(...skipping 28 matching lines...) Expand all Loading... |
3303 // have own properties. | 3250 // have own properties. |
3304 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); | 3251 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); |
3305 | 3252 |
3306 // Store on the holder which may be hidden behind the receiver. | 3253 // Store on the holder which may be hidden behind the receiver. |
3307 DCHECK(it->HolderIsReceiverOrHiddenPrototype()); | 3254 DCHECK(it->HolderIsReceiverOrHiddenPrototype()); |
3308 | 3255 |
3309 // Old value for the observation change record. | 3256 // Old value for the observation change record. |
3310 // Fetch before transforming the object since the encoding may become | 3257 // Fetch before transforming the object since the encoding may become |
3311 // incompatible with what's cached in |it|. | 3258 // incompatible with what's cached in |it|. |
3312 bool is_observed = receiver->map()->is_observed() && | 3259 bool is_observed = receiver->map()->is_observed() && |
3313 !it->isolate()->IsInternallyUsedPropertyName(it->name()); | 3260 (it->IsElement() || |
| 3261 !it->isolate()->IsInternallyUsedPropertyName(it->name())); |
3314 MaybeHandle<Object> maybe_old; | 3262 MaybeHandle<Object> maybe_old; |
3315 if (is_observed) maybe_old = it->GetDataValue(); | 3263 if (is_observed) maybe_old = it->GetDataValue(); |
3316 | 3264 |
| 3265 // Convert the incoming value to a number for storing into typed arrays. |
| 3266 if (it->IsElement() && (receiver->HasExternalArrayElements() || |
| 3267 receiver->HasFixedTypedArrayElements())) { |
| 3268 if (!value->IsNumber() && !value->IsUndefined()) { |
| 3269 ASSIGN_RETURN_ON_EXCEPTION(it->isolate(), value, |
| 3270 Execution::ToNumber(it->isolate(), value), |
| 3271 Object); |
| 3272 } |
| 3273 } |
| 3274 |
3317 // Possibly migrate to the most up-to-date map that will be able to store | 3275 // Possibly migrate to the most up-to-date map that will be able to store |
3318 // |value| under it->name(). | 3276 // |value| under it->name(). |
3319 it->PrepareForDataProperty(value); | 3277 it->PrepareForDataProperty(value); |
3320 | 3278 |
3321 // Write the property value. | 3279 // Write the property value. |
3322 it->WriteDataValue(value); | 3280 value = it->WriteDataValue(value); |
3323 | 3281 |
3324 // Send the change record if there are observers. | 3282 // Send the change record if there are observers. |
3325 if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) { | 3283 if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) { |
3326 RETURN_ON_EXCEPTION(it->isolate(), JSObject::EnqueueChangeRecord( | 3284 RETURN_ON_EXCEPTION(it->isolate(), JSObject::EnqueueChangeRecord( |
3327 receiver, "update", it->name(), | 3285 receiver, "update", it->GetName(), |
3328 maybe_old.ToHandleChecked()), | 3286 maybe_old.ToHandleChecked()), |
3329 Object); | 3287 Object); |
3330 } | 3288 } |
3331 | 3289 |
3332 return value; | 3290 return value; |
3333 } | 3291 } |
3334 | 3292 |
3335 | 3293 |
| 3294 MUST_USE_RESULT static MaybeHandle<Object> BeginPerformSplice( |
| 3295 Handle<JSArray> object) { |
| 3296 Isolate* isolate = object->GetIsolate(); |
| 3297 HandleScope scope(isolate); |
| 3298 Handle<Object> args[] = {object}; |
| 3299 |
| 3300 return Execution::Call( |
| 3301 isolate, Handle<JSFunction>(isolate->observers_begin_perform_splice()), |
| 3302 isolate->factory()->undefined_value(), arraysize(args), args); |
| 3303 } |
| 3304 |
| 3305 |
| 3306 MUST_USE_RESULT static MaybeHandle<Object> EndPerformSplice( |
| 3307 Handle<JSArray> object) { |
| 3308 Isolate* isolate = object->GetIsolate(); |
| 3309 HandleScope scope(isolate); |
| 3310 Handle<Object> args[] = {object}; |
| 3311 |
| 3312 return Execution::Call( |
| 3313 isolate, Handle<JSFunction>(isolate->observers_end_perform_splice()), |
| 3314 isolate->factory()->undefined_value(), arraysize(args), args); |
| 3315 } |
| 3316 |
| 3317 |
| 3318 MUST_USE_RESULT static MaybeHandle<Object> EnqueueSpliceRecord( |
| 3319 Handle<JSArray> object, uint32_t index, Handle<JSArray> deleted, |
| 3320 uint32_t add_count) { |
| 3321 Isolate* isolate = object->GetIsolate(); |
| 3322 HandleScope scope(isolate); |
| 3323 Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index); |
| 3324 Handle<Object> add_count_object = |
| 3325 isolate->factory()->NewNumberFromUint(add_count); |
| 3326 |
| 3327 Handle<Object> args[] = {object, index_object, deleted, add_count_object}; |
| 3328 |
| 3329 return Execution::Call( |
| 3330 isolate, Handle<JSFunction>(isolate->observers_enqueue_splice()), |
| 3331 isolate->factory()->undefined_value(), arraysize(args), args); |
| 3332 } |
| 3333 |
| 3334 |
3336 MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it, | 3335 MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it, |
3337 Handle<Object> value, | 3336 Handle<Object> value, |
3338 PropertyAttributes attributes, | 3337 PropertyAttributes attributes, |
3339 LanguageMode language_mode, | 3338 LanguageMode language_mode, |
3340 StoreFromKeyed store_mode) { | 3339 StoreFromKeyed store_mode) { |
3341 DCHECK(!it->GetReceiver()->IsJSProxy()); | 3340 DCHECK(!it->GetReceiver()->IsJSProxy()); |
3342 if (!it->GetReceiver()->IsJSObject()) { | 3341 if (!it->GetReceiver()->IsJSObject()) { |
3343 // TODO(verwaest): Throw a TypeError with a more specific message. | 3342 // TODO(verwaest): Throw a TypeError with a more specific message. |
3344 return WriteToReadOnlyProperty(it, value, language_mode); | 3343 return WriteToReadOnlyProperty(it, value, language_mode); |
3345 } | 3344 } |
3346 | 3345 |
3347 if (it->state() == LookupIterator::INTEGER_INDEXED_EXOTIC) return value; | 3346 if (it->state() == LookupIterator::INTEGER_INDEXED_EXOTIC) return value; |
3348 | 3347 |
3349 Handle<JSObject> receiver = it->GetStoreTarget(); | 3348 Handle<JSObject> receiver = it->GetStoreTarget(); |
3350 | 3349 |
3351 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) | 3350 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject) |
3352 // instead. If the prototype is Null, the proxy is detached. | 3351 // instead. If the prototype is Null, the proxy is detached. |
3353 if (receiver->IsJSGlobalProxy()) return value; | 3352 if (receiver->IsJSGlobalProxy()) return value; |
3354 | 3353 |
3355 // Possibly migrate to the most up-to-date map that will be able to store | 3354 Isolate* isolate = it->isolate(); |
3356 // |value| under it->name() with |attributes|. | 3355 |
3357 it->PrepareTransitionToDataProperty(value, attributes, store_mode); | 3356 if (!receiver->map()->is_extensible() && |
3358 if (it->state() != LookupIterator::TRANSITION) { | 3357 (it->IsElement() || !isolate->IsInternallyUsedPropertyName(it->name()))) { |
3359 if (is_sloppy(language_mode)) return value; | 3358 if (is_sloppy(language_mode)) return value; |
3360 THROW_NEW_ERROR( | 3359 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kObjectNotExtensible, |
3361 it->isolate(), | 3360 it->GetName()), |
3362 NewTypeError(MessageTemplate::kObjectNotExtensible, it->name()), | 3361 Object); |
3363 Object); | |
3364 } | |
3365 it->ApplyTransitionToDataProperty(); | |
3366 | |
3367 // TODO(verwaest): Encapsulate dictionary handling better. | |
3368 if (receiver->map()->is_dictionary_map()) { | |
3369 // TODO(verwaest): Probably should ensure this is done beforehand. | |
3370 it->InternalizeName(); | |
3371 // TODO(dcarney): just populate TransitionPropertyCell here? | |
3372 JSObject::AddSlowProperty(receiver, it->name(), value, attributes); | |
3373 } else { | |
3374 // Write the property value. | |
3375 it->WriteDataValue(value); | |
3376 } | 3362 } |
3377 | 3363 |
3378 // Send the change record if there are observers. | 3364 if (it->IsElement()) { |
3379 if (receiver->map()->is_observed() && | 3365 if (receiver->IsJSArray()) { |
3380 !it->isolate()->IsInternallyUsedPropertyName(it->name())) { | 3366 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
3381 RETURN_ON_EXCEPTION(it->isolate(), JSObject::EnqueueChangeRecord( | 3367 if (JSArray::WouldChangeReadOnlyLength(array, it->index())) { |
3382 receiver, "add", it->name(), | 3368 if (is_sloppy(language_mode)) return value; |
3383 it->factory()->the_hole_value()), | 3369 return JSArray::ReadOnlyLengthError(array); |
3384 Object); | 3370 } |
| 3371 |
| 3372 if (FLAG_trace_external_array_abuse && |
| 3373 (array->HasExternalArrayElements() || |
| 3374 array->HasFixedTypedArrayElements())) { |
| 3375 CheckArrayAbuse(array, "typed elements write", it->index(), true); |
| 3376 } |
| 3377 |
| 3378 if (FLAG_trace_js_array_abuse && !array->HasExternalArrayElements() && |
| 3379 !array->HasFixedTypedArrayElements()) { |
| 3380 CheckArrayAbuse(array, "elements write", it->index(), false); |
| 3381 } |
| 3382 } |
| 3383 |
| 3384 return JSObject::AddDataElement(receiver, it->index(), value, attributes); |
| 3385 } else { |
| 3386 // Migrate to the most up-to-date map that will be able to store |value| |
| 3387 // under it->name() with |attributes|. |
| 3388 it->PrepareTransitionToDataProperty(value, attributes, store_mode); |
| 3389 DCHECK_EQ(LookupIterator::TRANSITION, it->state()); |
| 3390 it->ApplyTransitionToDataProperty(); |
| 3391 |
| 3392 // TODO(verwaest): Encapsulate dictionary handling better. |
| 3393 if (receiver->map()->is_dictionary_map()) { |
| 3394 // TODO(verwaest): Probably should ensure this is done beforehand. |
| 3395 it->InternalizeName(); |
| 3396 // TODO(dcarney): just populate TransitionPropertyCell here? |
| 3397 JSObject::AddSlowProperty(receiver, it->name(), value, attributes); |
| 3398 } else { |
| 3399 // Write the property value. |
| 3400 it->WriteDataValue(value); |
| 3401 } |
| 3402 |
| 3403 // Send the change record if there are observers. |
| 3404 if (receiver->map()->is_observed() && |
| 3405 !isolate->IsInternallyUsedPropertyName(it->name())) { |
| 3406 RETURN_ON_EXCEPTION(isolate, JSObject::EnqueueChangeRecord( |
| 3407 receiver, "add", it->name(), |
| 3408 it->factory()->the_hole_value()), |
| 3409 Object); |
| 3410 } |
3385 } | 3411 } |
3386 | 3412 |
3387 return value; | 3413 return value; |
3388 } | 3414 } |
3389 | 3415 |
3390 | 3416 |
3391 MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes( | |
3392 Handle<JSObject> object, uint32_t index, Handle<Object> value, bool* found, | |
3393 LanguageMode language_mode) { | |
3394 Isolate* isolate = object->GetIsolate(); | |
3395 for (PrototypeIterator iter(isolate, object); !iter.IsAtEnd(); | |
3396 iter.Advance()) { | |
3397 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | |
3398 return JSProxy::SetPropertyViaPrototypesWithHandler( | |
3399 Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), object, | |
3400 isolate->factory()->Uint32ToString(index), // name | |
3401 value, language_mode, found); | |
3402 } | |
3403 Handle<JSObject> js_proto = | |
3404 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
3405 | |
3406 if (js_proto->IsAccessCheckNeeded()) { | |
3407 if (!isolate->MayAccess(js_proto)) { | |
3408 *found = true; | |
3409 isolate->ReportFailedAccessCheck(js_proto); | |
3410 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
3411 return MaybeHandle<Object>(); | |
3412 } | |
3413 } | |
3414 | |
3415 if (!js_proto->HasDictionaryElements()) { | |
3416 continue; | |
3417 } | |
3418 | |
3419 Handle<SeededNumberDictionary> dictionary(js_proto->element_dictionary()); | |
3420 int entry = dictionary->FindEntry(index); | |
3421 if (entry != SeededNumberDictionary::kNotFound) { | |
3422 PropertyDetails details = dictionary->DetailsAt(entry); | |
3423 if (details.type() == ACCESSOR_CONSTANT) { | |
3424 *found = true; | |
3425 Handle<Object> structure(dictionary->ValueAt(entry), isolate); | |
3426 return SetElementWithCallback(object, structure, index, value, js_proto, | |
3427 language_mode); | |
3428 } | |
3429 } | |
3430 } | |
3431 *found = false; | |
3432 return isolate->factory()->the_hole_value(); | |
3433 } | |
3434 | |
3435 | |
3436 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { | 3417 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { |
3437 // Only supports adding slack to owned descriptors. | 3418 // Only supports adding slack to owned descriptors. |
3438 DCHECK(map->owns_descriptors()); | 3419 DCHECK(map->owns_descriptors()); |
3439 | 3420 |
3440 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | 3421 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
3441 int old_size = map->NumberOfOwnDescriptors(); | 3422 int old_size = map->NumberOfOwnDescriptors(); |
3442 if (slack <= descriptors->NumberOfSlackDescriptors()) return; | 3423 if (slack <= descriptors->NumberOfSlackDescriptors()) return; |
3443 | 3424 |
3444 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( | 3425 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( |
3445 descriptors, old_size, slack); | 3426 descriptors, old_size, slack); |
(...skipping 691 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4137 DCHECK(maybe.IsJust()); | 4118 DCHECK(maybe.IsJust()); |
4138 DCHECK(!it.IsFound()); | 4119 DCHECK(!it.IsFound()); |
4139 DCHECK(object->map()->is_extensible() || | 4120 DCHECK(object->map()->is_extensible() || |
4140 it.isolate()->IsInternallyUsedPropertyName(name)); | 4121 it.isolate()->IsInternallyUsedPropertyName(name)); |
4141 #endif | 4122 #endif |
4142 AddDataProperty(&it, value, attributes, STRICT, | 4123 AddDataProperty(&it, value, attributes, STRICT, |
4143 CERTAINLY_NOT_STORE_FROM_KEYED).Check(); | 4124 CERTAINLY_NOT_STORE_FROM_KEYED).Check(); |
4144 } | 4125 } |
4145 | 4126 |
4146 | 4127 |
| 4128 // static |
| 4129 void ExecutableAccessorInfo::ClearSetter(Handle<ExecutableAccessorInfo> info) { |
| 4130 info->set_setter(*v8::FromCData(info->GetIsolate(), nullptr)); |
| 4131 } |
| 4132 |
| 4133 |
| 4134 MaybeHandle<Object> JSObject::ReconfigureAsDataProperty( |
| 4135 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes) { |
| 4136 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); |
| 4137 bool is_observed = object->map()->is_observed() && |
| 4138 (it->IsElement() || |
| 4139 !it->isolate()->IsInternallyUsedPropertyName(it->name())); |
| 4140 |
| 4141 switch (it->state()) { |
| 4142 case LookupIterator::INTERCEPTOR: |
| 4143 case LookupIterator::JSPROXY: |
| 4144 case LookupIterator::NOT_FOUND: |
| 4145 case LookupIterator::TRANSITION: |
| 4146 case LookupIterator::ACCESS_CHECK: |
| 4147 UNREACHABLE(); |
| 4148 |
| 4149 case LookupIterator::INTEGER_INDEXED_EXOTIC: |
| 4150 return value; |
| 4151 |
| 4152 case LookupIterator::ACCESSOR: { |
| 4153 PropertyDetails details = it->property_details(); |
| 4154 // Ensure the context isn't changed after calling into accessors. |
| 4155 AssertNoContextChange ncc(it->isolate()); |
| 4156 |
| 4157 Handle<Object> accessors = it->GetAccessors(); |
| 4158 |
| 4159 // Special handling for ExecutableAccessorInfo, which behaves like a |
| 4160 // data property. |
| 4161 if (accessors->IsExecutableAccessorInfo()) { |
| 4162 Handle<Object> result; |
| 4163 ASSIGN_RETURN_ON_EXCEPTION( |
| 4164 it->isolate(), result, |
| 4165 JSObject::SetPropertyWithAccessor(it, value, STRICT), Object); |
| 4166 DCHECK(result->SameValue(*value)); |
| 4167 |
| 4168 if (details.attributes() == attributes) return value; |
| 4169 |
| 4170 // Reconfigure the accessor if attributes mismatch. |
| 4171 Handle<ExecutableAccessorInfo> new_data = Accessors::CloneAccessor( |
| 4172 it->isolate(), Handle<ExecutableAccessorInfo>::cast(accessors)); |
| 4173 new_data->set_property_attributes(attributes); |
| 4174 // By clearing the setter we don't have to introduce a lookup to |
| 4175 // the setter, simply make it unavailable to reflect the |
| 4176 // attributes. |
| 4177 if (attributes & READ_ONLY) { |
| 4178 ExecutableAccessorInfo::ClearSetter(new_data); |
| 4179 } |
| 4180 |
| 4181 if (it->IsElement()) { |
| 4182 SetElementCallback(object, it->index(), new_data, attributes); |
| 4183 } else { |
| 4184 SetPropertyCallback(object, it->name(), new_data, attributes); |
| 4185 } |
| 4186 if (is_observed) { |
| 4187 RETURN_ON_EXCEPTION( |
| 4188 it->isolate(), |
| 4189 EnqueueChangeRecord(object, "reconfigure", it->GetName(), |
| 4190 it->factory()->the_hole_value()), |
| 4191 Object); |
| 4192 } |
| 4193 return value; |
| 4194 } |
| 4195 |
| 4196 it->ReconfigureDataProperty(value, attributes); |
| 4197 it->WriteDataValue(value); |
| 4198 |
| 4199 if (is_observed) { |
| 4200 RETURN_ON_EXCEPTION( |
| 4201 it->isolate(), |
| 4202 EnqueueChangeRecord(object, "reconfigure", it->GetName(), |
| 4203 it->factory()->the_hole_value()), |
| 4204 Object); |
| 4205 } |
| 4206 |
| 4207 return value; |
| 4208 } |
| 4209 |
| 4210 case LookupIterator::DATA: { |
| 4211 PropertyDetails details = it->property_details(); |
| 4212 Handle<Object> old_value = it->factory()->the_hole_value(); |
| 4213 // Regular property update if the attributes match. |
| 4214 if (details.attributes() == attributes) { |
| 4215 return SetDataProperty(it, value); |
| 4216 } |
| 4217 |
| 4218 // Special case: properties of typed arrays cannot be reconfigured to |
| 4219 // non-writable nor to non-enumerable. |
| 4220 if (it->IsElement() && (object->HasExternalArrayElements() || |
| 4221 object->HasFixedTypedArrayElements())) { |
| 4222 return RedefineNonconfigurableProperty(it->isolate(), it->GetName(), |
| 4223 value, STRICT); |
| 4224 } |
| 4225 |
| 4226 // Reconfigure the data property if the attributes mismatch. |
| 4227 if (is_observed) old_value = it->GetDataValue(); |
| 4228 |
| 4229 it->ReconfigureDataProperty(value, attributes); |
| 4230 it->WriteDataValue(value); |
| 4231 |
| 4232 if (is_observed) { |
| 4233 if (old_value->SameValue(*value)) { |
| 4234 old_value = it->factory()->the_hole_value(); |
| 4235 } |
| 4236 RETURN_ON_EXCEPTION(it->isolate(), |
| 4237 EnqueueChangeRecord(object, "reconfigure", |
| 4238 it->GetName(), old_value), |
| 4239 Object); |
| 4240 } |
| 4241 } |
| 4242 } |
| 4243 |
| 4244 return value; |
| 4245 } |
| 4246 |
| 4247 |
4147 // Reconfigures a property to a data property with attributes, even if it is not | 4248 // Reconfigures a property to a data property with attributes, even if it is not |
4148 // reconfigurable. | 4249 // reconfigurable. |
4149 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes( | 4250 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes( |
4150 Handle<JSObject> object, | 4251 Handle<JSObject> object, Handle<Name> name, Handle<Object> value, |
4151 Handle<Name> name, | 4252 PropertyAttributes attributes) { |
4152 Handle<Object> value, | |
4153 PropertyAttributes attributes, | |
4154 ExecutableAccessorInfoHandling handling) { | |
4155 DCHECK(!value->IsTheHole()); | 4253 DCHECK(!value->IsTheHole()); |
4156 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); | 4254 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); |
4157 bool is_observed = object->map()->is_observed() && | 4255 if (it.state() == LookupIterator::ACCESS_CHECK) { |
4158 !it.isolate()->IsInternallyUsedPropertyName(name); | 4256 if (!it.isolate()->MayAccess(object)) { |
4159 for (; it.IsFound(); it.Next()) { | 4257 return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY); |
4160 switch (it.state()) { | 4258 } |
4161 case LookupIterator::INTEGER_INDEXED_EXOTIC: | 4259 it.Next(); |
4162 return value; | 4260 } |
4163 | 4261 |
4164 case LookupIterator::INTERCEPTOR: | 4262 if (it.IsFound()) { |
4165 case LookupIterator::JSPROXY: | 4263 return ReconfigureAsDataProperty(&it, value, attributes); |
4166 case LookupIterator::NOT_FOUND: | |
4167 case LookupIterator::TRANSITION: | |
4168 UNREACHABLE(); | |
4169 | |
4170 case LookupIterator::ACCESS_CHECK: | |
4171 if (!it.isolate()->MayAccess(object)) { | |
4172 return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY); | |
4173 } | |
4174 break; | |
4175 | |
4176 case LookupIterator::ACCESSOR: { | |
4177 PropertyDetails details = it.property_details(); | |
4178 // Ensure the context isn't changed after calling into accessors. | |
4179 AssertNoContextChange ncc(it.isolate()); | |
4180 | |
4181 Handle<Object> accessors = it.GetAccessors(); | |
4182 | |
4183 // Special handling for ExecutableAccessorInfo, which behaves like a | |
4184 // data property. | |
4185 if (handling == DONT_FORCE_FIELD && | |
4186 accessors->IsExecutableAccessorInfo()) { | |
4187 Handle<Object> result; | |
4188 ASSIGN_RETURN_ON_EXCEPTION( | |
4189 it.isolate(), result, | |
4190 JSObject::SetPropertyWithAccessor(it.GetReceiver(), it.name(), | |
4191 value, it.GetHolder<JSObject>(), | |
4192 accessors, STRICT), | |
4193 Object); | |
4194 DCHECK(result->SameValue(*value)); | |
4195 | |
4196 if (details.attributes() == attributes) { | |
4197 return value; | |
4198 } | |
4199 | |
4200 // Reconfigure the accessor if attributes mismatch. | |
4201 Handle<ExecutableAccessorInfo> new_data = Accessors::CloneAccessor( | |
4202 it.isolate(), Handle<ExecutableAccessorInfo>::cast(accessors)); | |
4203 new_data->set_property_attributes(attributes); | |
4204 // By clearing the setter we don't have to introduce a lookup to | |
4205 // the setter, simply make it unavailable to reflect the | |
4206 // attributes. | |
4207 if (attributes & READ_ONLY) { | |
4208 ExecutableAccessorInfo::ClearSetter(new_data); | |
4209 } | |
4210 SetPropertyCallback(object, name, new_data, attributes); | |
4211 if (is_observed) { | |
4212 RETURN_ON_EXCEPTION( | |
4213 it.isolate(), | |
4214 EnqueueChangeRecord(object, "reconfigure", name, | |
4215 it.isolate()->factory()->the_hole_value()), | |
4216 Object); | |
4217 } | |
4218 return value; | |
4219 } | |
4220 | |
4221 it.ReconfigureDataProperty(value, attributes); | |
4222 it.WriteDataValue(value); | |
4223 | |
4224 if (is_observed) { | |
4225 RETURN_ON_EXCEPTION( | |
4226 it.isolate(), | |
4227 EnqueueChangeRecord(object, "reconfigure", name, | |
4228 it.isolate()->factory()->the_hole_value()), | |
4229 Object); | |
4230 } | |
4231 | |
4232 return value; | |
4233 } | |
4234 | |
4235 case LookupIterator::DATA: { | |
4236 PropertyDetails details = it.property_details(); | |
4237 Handle<Object> old_value = it.isolate()->factory()->the_hole_value(); | |
4238 // Regular property update if the attributes match. | |
4239 if (details.attributes() == attributes) { | |
4240 return SetDataProperty(&it, value); | |
4241 } | |
4242 // Reconfigure the data property if the attributes mismatch. | |
4243 if (is_observed) old_value = it.GetDataValue(); | |
4244 | |
4245 it.ReconfigureDataProperty(value, attributes); | |
4246 it.WriteDataValue(value); | |
4247 | |
4248 if (is_observed) { | |
4249 if (old_value->SameValue(*value)) { | |
4250 old_value = it.isolate()->factory()->the_hole_value(); | |
4251 } | |
4252 RETURN_ON_EXCEPTION( | |
4253 it.isolate(), | |
4254 EnqueueChangeRecord(object, "reconfigure", name, old_value), | |
4255 Object); | |
4256 } | |
4257 | |
4258 return value; | |
4259 } | |
4260 } | |
4261 } | 4264 } |
4262 | 4265 |
4263 return AddDataProperty(&it, value, attributes, STRICT, | 4266 return AddDataProperty(&it, value, attributes, STRICT, |
4264 CERTAINLY_NOT_STORE_FROM_KEYED); | 4267 CERTAINLY_NOT_STORE_FROM_KEYED); |
4265 } | 4268 } |
4266 | 4269 |
4267 | 4270 |
| 4271 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes( |
| 4272 Handle<JSObject> object, uint32_t index, Handle<Object> value, |
| 4273 PropertyAttributes attributes) { |
| 4274 DCHECK(!object->HasExternalArrayElements()); |
| 4275 Isolate* isolate = object->GetIsolate(); |
| 4276 LookupIterator it(isolate, object, index, |
| 4277 LookupIterator::OWN_SKIP_INTERCEPTOR); |
| 4278 if (it.state() == LookupIterator::ACCESS_CHECK) { |
| 4279 if (!isolate->MayAccess(object)) { |
| 4280 return SetPropertyWithFailedAccessCheck(&it, value, STRICT); |
| 4281 } |
| 4282 it.Next(); |
| 4283 } |
| 4284 |
| 4285 if (it.IsFound()) { |
| 4286 return ReconfigureAsDataProperty(&it, value, attributes); |
| 4287 } |
| 4288 |
| 4289 return AddDataProperty(&it, value, attributes, STRICT, |
| 4290 MAY_BE_STORE_FROM_KEYED); |
| 4291 } |
| 4292 |
| 4293 |
4268 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( | 4294 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( |
4269 LookupIterator* it) { | 4295 LookupIterator* it) { |
4270 Isolate* isolate = it->isolate(); | 4296 Isolate* isolate = it->isolate(); |
4271 // Make sure that the top context does not change when doing | 4297 // Make sure that the top context does not change when doing |
4272 // callbacks or interceptor calls. | 4298 // callbacks or interceptor calls. |
4273 AssertNoContextChange ncc(isolate); | 4299 AssertNoContextChange ncc(isolate); |
4274 HandleScope scope(isolate); | 4300 HandleScope scope(isolate); |
4275 | 4301 |
4276 Handle<JSObject> holder = it->GetHolder<JSObject>(); | 4302 Handle<JSObject> holder = it->GetHolder<JSObject>(); |
4277 Handle<InterceptorInfo> interceptor(it->GetInterceptor()); | 4303 Handle<InterceptorInfo> interceptor(it->GetInterceptor()); |
(...skipping 2869 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7147 case ACCESSOR: | 7173 case ACCESSOR: |
7148 case ACCESSOR_CONSTANT: | 7174 case ACCESSOR_CONSTANT: |
7149 return false; | 7175 return false; |
7150 } | 7176 } |
7151 | 7177 |
7152 UNREACHABLE(); | 7178 UNREACHABLE(); |
7153 return false; | 7179 return false; |
7154 } | 7180 } |
7155 | 7181 |
7156 | 7182 |
| 7183 // static |
| 7184 Handle<Map> Map::PrepareForDataElement(Handle<Map> map, Handle<Object> value) { |
| 7185 ElementsKind kind = map->elements_kind(); |
| 7186 bool holey = IsHoleyElementsKind(kind); |
| 7187 |
| 7188 switch (kind) { |
| 7189 case FAST_SMI_ELEMENTS: |
| 7190 case FAST_HOLEY_SMI_ELEMENTS: |
| 7191 if (value->IsSmi()) return map; |
| 7192 kind = value->IsNumber() ? FAST_DOUBLE_ELEMENTS : FAST_ELEMENTS; |
| 7193 break; |
| 7194 |
| 7195 case FAST_DOUBLE_ELEMENTS: |
| 7196 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 7197 if (value->IsNumber()) return map; |
| 7198 kind = FAST_ELEMENTS; |
| 7199 break; |
| 7200 |
| 7201 case FAST_ELEMENTS: |
| 7202 case FAST_HOLEY_ELEMENTS: |
| 7203 case DICTIONARY_ELEMENTS: |
| 7204 case SLOPPY_ARGUMENTS_ELEMENTS: |
| 7205 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
| 7206 case EXTERNAL_##TYPE##_ELEMENTS: \ |
| 7207 case TYPE##_ELEMENTS: |
| 7208 |
| 7209 TYPED_ARRAYS(TYPED_ARRAY_CASE) |
| 7210 #undef TYPED_ARRAY_CASE |
| 7211 return map; |
| 7212 } |
| 7213 |
| 7214 if (holey) kind = GetHoleyElementsKind(kind); |
| 7215 return Map::AsElementsKind(map, kind); |
| 7216 } |
| 7217 |
| 7218 |
| 7219 // static |
7157 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor, | 7220 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor, |
7158 Handle<Object> value) { | 7221 Handle<Object> value) { |
7159 // Dictionaries can store any property value. | 7222 // Dictionaries can store any property value. |
7160 if (map->is_dictionary_map()) return map; | 7223 if (map->is_dictionary_map()) return map; |
7161 | 7224 |
7162 // Migrate to the newest map before storing the property. | 7225 // Migrate to the newest map before storing the property. |
7163 map = Update(map); | 7226 map = Update(map); |
7164 | 7227 |
7165 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | 7228 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
7166 | 7229 |
(...skipping 4722 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11889 if (!JSObject::GetOwnElementAccessorPair(object, index).is_null()) { | 11952 if (!JSObject::GetOwnElementAccessorPair(object, index).is_null()) { |
11890 value = Handle<Object>::cast(isolate->factory()->the_hole_value()); | 11953 value = Handle<Object>::cast(isolate->factory()->the_hole_value()); |
11891 } else { | 11954 } else { |
11892 value = Object::GetElement(isolate, object, index).ToHandleChecked(); | 11955 value = Object::GetElement(isolate, object, index).ToHandleChecked(); |
11893 } | 11956 } |
11894 old_values->Add(value); | 11957 old_values->Add(value); |
11895 indices->Add(index); | 11958 indices->Add(index); |
11896 return true; | 11959 return true; |
11897 } | 11960 } |
11898 | 11961 |
11899 MUST_USE_RESULT static MaybeHandle<Object> EnqueueSpliceRecord( | |
11900 Handle<JSArray> object, uint32_t index, Handle<JSArray> deleted, | |
11901 uint32_t add_count) { | |
11902 Isolate* isolate = object->GetIsolate(); | |
11903 HandleScope scope(isolate); | |
11904 Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index); | |
11905 Handle<Object> add_count_object = | |
11906 isolate->factory()->NewNumberFromUint(add_count); | |
11907 | |
11908 Handle<Object> args[] = | |
11909 { object, index_object, deleted, add_count_object }; | |
11910 | |
11911 return Execution::Call( | |
11912 isolate, Handle<JSFunction>(isolate->observers_enqueue_splice()), | |
11913 isolate->factory()->undefined_value(), arraysize(args), args); | |
11914 } | |
11915 | |
11916 | |
11917 MUST_USE_RESULT static MaybeHandle<Object> BeginPerformSplice( | |
11918 Handle<JSArray> object) { | |
11919 Isolate* isolate = object->GetIsolate(); | |
11920 HandleScope scope(isolate); | |
11921 Handle<Object> args[] = { object }; | |
11922 | |
11923 return Execution::Call( | |
11924 isolate, Handle<JSFunction>(isolate->observers_begin_perform_splice()), | |
11925 isolate->factory()->undefined_value(), arraysize(args), args); | |
11926 } | |
11927 | |
11928 | |
11929 MUST_USE_RESULT static MaybeHandle<Object> EndPerformSplice( | |
11930 Handle<JSArray> object) { | |
11931 Isolate* isolate = object->GetIsolate(); | |
11932 HandleScope scope(isolate); | |
11933 Handle<Object> args[] = { object }; | |
11934 | |
11935 return Execution::Call( | |
11936 isolate, Handle<JSFunction>(isolate->observers_end_perform_splice()), | |
11937 isolate->factory()->undefined_value(), arraysize(args), args); | |
11938 } | |
11939 | |
11940 | |
11941 MaybeHandle<Object> JSArray::SetElementsLength( | 11962 MaybeHandle<Object> JSArray::SetElementsLength( |
11942 Handle<JSArray> array, | 11963 Handle<JSArray> array, |
11943 Handle<Object> new_length_handle) { | 11964 Handle<Object> new_length_handle) { |
11944 if (array->HasFastElements() && | 11965 if (array->HasFastElements() && |
11945 SetElementsLengthWouldNormalize(array->GetHeap(), new_length_handle)) { | 11966 SetElementsLengthWouldNormalize(array->GetHeap(), new_length_handle)) { |
11946 NormalizeElements(array); | 11967 NormalizeElements(array); |
11947 } | 11968 } |
11948 | 11969 |
11949 // We should never end in here with a pixel or external array. | 11970 // We should never end in here with a pixel or external array. |
11950 DCHECK(array->AllowsSetElementsLength()); | 11971 DCHECK(array->AllowsSetElementsLength()); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12015 | 12036 |
12016 uint32_t index = Min(old_length, new_length); | 12037 uint32_t index = Min(old_length, new_length); |
12017 uint32_t add_count = new_length > old_length ? new_length - old_length : 0; | 12038 uint32_t add_count = new_length > old_length ? new_length - old_length : 0; |
12018 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0; | 12039 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0; |
12019 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0); | 12040 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0); |
12020 if (delete_count > 0) { | 12041 if (delete_count > 0) { |
12021 for (int i = indices.length() - 1; i >= 0; i--) { | 12042 for (int i = indices.length() - 1; i >= 0; i--) { |
12022 // Skip deletions where the property was an accessor, leaving holes | 12043 // Skip deletions where the property was an accessor, leaving holes |
12023 // in the array of old values. | 12044 // in the array of old values. |
12024 if (old_values[i]->IsTheHole()) continue; | 12045 if (old_values[i]->IsTheHole()) continue; |
12025 JSObject::SetOwnElement(deleted, indices[i] - index, old_values[i], | 12046 JSObject::AddDataElement(deleted, indices[i] - index, old_values[i], NONE) |
12026 SLOPPY).Assert(); | 12047 .Assert(); |
12027 } | 12048 } |
12028 | 12049 |
12029 RETURN_ON_EXCEPTION( | 12050 SetProperty(deleted, isolate->factory()->length_string(), |
12030 isolate, | 12051 isolate->factory()->NewNumberFromUint(delete_count), |
12031 SetProperty(deleted, isolate->factory()->length_string(), | 12052 STRICT).Assert(); |
12032 isolate->factory()->NewNumberFromUint(delete_count), | |
12033 STRICT), | |
12034 Object); | |
12035 } | 12053 } |
12036 | 12054 |
12037 RETURN_ON_EXCEPTION( | 12055 RETURN_ON_EXCEPTION( |
12038 isolate, EnqueueSpliceRecord(array, index, deleted, add_count), Object); | 12056 isolate, EnqueueSpliceRecord(array, index, deleted, add_count), Object); |
12039 | 12057 |
12040 return hresult; | 12058 return hresult; |
12041 } | 12059 } |
12042 | 12060 |
12043 | 12061 |
12044 // static | 12062 // static |
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12449 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index); | 12467 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index); |
12450 } | 12468 } |
12451 | 12469 |
12452 // Check for lookup interceptor. | 12470 // Check for lookup interceptor. |
12453 if (object->HasIndexedInterceptor()) return MaybeHandle<AccessorPair>(); | 12471 if (object->HasIndexedInterceptor()) return MaybeHandle<AccessorPair>(); |
12454 | 12472 |
12455 return object->GetElementsAccessor()->GetAccessorPair(object, index); | 12473 return object->GetElementsAccessor()->GetAccessorPair(object, index); |
12456 } | 12474 } |
12457 | 12475 |
12458 | 12476 |
12459 MaybeHandle<Object> JSObject::SetElementWithInterceptor( | |
12460 Handle<JSObject> object, uint32_t index, Handle<Object> value, | |
12461 PropertyAttributes attributes, LanguageMode language_mode, | |
12462 bool check_prototype, SetPropertyMode set_mode) { | |
12463 Isolate* isolate = object->GetIsolate(); | |
12464 | |
12465 // Make sure that the top context does not change when doing | |
12466 // callbacks or interceptor calls. | |
12467 AssertNoContextChange ncc(isolate); | |
12468 | |
12469 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor()); | |
12470 if (!interceptor->setter()->IsUndefined()) { | |
12471 v8::IndexedPropertySetterCallback setter = | |
12472 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter()); | |
12473 LOG(isolate, | |
12474 ApiIndexedPropertyAccess("interceptor-indexed-set", *object, index)); | |
12475 PropertyCallbackArguments args(isolate, interceptor->data(), *object, | |
12476 *object); | |
12477 v8::Handle<v8::Value> result = | |
12478 args.Call(setter, index, v8::Utils::ToLocal(value)); | |
12479 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
12480 if (!result.IsEmpty()) return value; | |
12481 } | |
12482 | |
12483 return SetElementWithoutInterceptor(object, index, value, attributes, | |
12484 language_mode, check_prototype, set_mode); | |
12485 } | |
12486 | |
12487 | |
12488 MaybeHandle<Object> JSObject::SetElementWithCallback( | |
12489 Handle<Object> object, Handle<Object> structure, uint32_t index, | |
12490 Handle<Object> value, Handle<JSObject> holder, LanguageMode language_mode) { | |
12491 Isolate* isolate = holder->GetIsolate(); | |
12492 | |
12493 // We should never get here to initialize a const with the hole | |
12494 // value since a const declaration would conflict with the setter. | |
12495 DCHECK(!value->IsTheHole()); | |
12496 DCHECK(!structure->IsForeign()); | |
12497 if (structure->IsExecutableAccessorInfo()) { | |
12498 // api style callbacks | |
12499 Handle<ExecutableAccessorInfo> data = | |
12500 Handle<ExecutableAccessorInfo>::cast(structure); | |
12501 Object* call_obj = data->setter(); | |
12502 v8::AccessorNameSetterCallback call_fun = | |
12503 v8::ToCData<v8::AccessorNameSetterCallback>(call_obj); | |
12504 if (call_fun == NULL) return value; | |
12505 Handle<String> key(isolate->factory()->Uint32ToString(index)); | |
12506 LOG(isolate, ApiNamedPropertyAccess("store", *holder, *key)); | |
12507 PropertyCallbackArguments | |
12508 args(isolate, data->data(), *object, *holder); | |
12509 args.Call(call_fun, | |
12510 v8::Utils::ToLocal(key), | |
12511 v8::Utils::ToLocal(value)); | |
12512 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
12513 return value; | |
12514 } | |
12515 | |
12516 if (structure->IsAccessorPair()) { | |
12517 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate); | |
12518 if (setter->IsSpecFunction()) { | |
12519 // TODO(rossberg): nicer would be to cast to some JSCallable here... | |
12520 return SetPropertyWithDefinedSetter( | |
12521 object, Handle<JSReceiver>::cast(setter), value); | |
12522 } else { | |
12523 if (is_sloppy(language_mode)) return value; | |
12524 Handle<Object> key(isolate->factory()->NewNumberFromUint(index)); | |
12525 THROW_NEW_ERROR( | |
12526 isolate, | |
12527 NewTypeError(MessageTemplate::kNoSetterInCallback, key, holder), | |
12528 Object); | |
12529 } | |
12530 } | |
12531 | |
12532 UNREACHABLE(); | |
12533 return MaybeHandle<Object>(); | |
12534 } | |
12535 | |
12536 | |
12537 bool JSObject::HasFastArgumentsElements() { | 12477 bool JSObject::HasFastArgumentsElements() { |
12538 Heap* heap = GetHeap(); | 12478 Heap* heap = GetHeap(); |
12539 if (!elements()->IsFixedArray()) return false; | 12479 if (!elements()->IsFixedArray()) return false; |
12540 FixedArray* elements = FixedArray::cast(this->elements()); | 12480 FixedArray* elements = FixedArray::cast(this->elements()); |
12541 if (elements->map() != heap->sloppy_arguments_elements_map()) { | 12481 if (elements->map() != heap->sloppy_arguments_elements_map()) { |
12542 return false; | 12482 return false; |
12543 } | 12483 } |
12544 FixedArray* arguments = FixedArray::cast(elements->get(1)); | 12484 FixedArray* arguments = FixedArray::cast(elements->get(1)); |
12545 return !arguments->IsDictionary(); | 12485 return !arguments->IsDictionary(); |
12546 } | 12486 } |
12547 | 12487 |
12548 | 12488 |
12549 bool JSObject::HasDictionaryArgumentsElements() { | 12489 bool JSObject::HasDictionaryArgumentsElements() { |
12550 Heap* heap = GetHeap(); | 12490 Heap* heap = GetHeap(); |
12551 if (!elements()->IsFixedArray()) return false; | 12491 if (!elements()->IsFixedArray()) return false; |
12552 FixedArray* elements = FixedArray::cast(this->elements()); | 12492 FixedArray* elements = FixedArray::cast(this->elements()); |
12553 if (elements->map() != heap->sloppy_arguments_elements_map()) { | 12493 if (elements->map() != heap->sloppy_arguments_elements_map()) { |
12554 return false; | 12494 return false; |
12555 } | 12495 } |
12556 FixedArray* arguments = FixedArray::cast(elements->get(1)); | 12496 FixedArray* arguments = FixedArray::cast(elements->get(1)); |
12557 return arguments->IsDictionary(); | 12497 return arguments->IsDictionary(); |
12558 } | 12498 } |
12559 | 12499 |
12560 | 12500 |
12561 // Adding n elements in fast case is O(n*n). | 12501 void JSObject::SetFastElement(Handle<JSObject> object, uint32_t index, |
12562 // Note: revisit design to have dual undefined values to capture absent | 12502 Handle<Object> value) { |
12563 // elements. | |
12564 MaybeHandle<Object> JSObject::SetFastElement(Handle<JSObject> object, | |
12565 uint32_t index, | |
12566 Handle<Object> value, | |
12567 LanguageMode language_mode, | |
12568 bool check_prototype) { | |
12569 DCHECK(object->HasFastSmiOrObjectElements() || | 12503 DCHECK(object->HasFastSmiOrObjectElements() || |
12570 object->HasFastArgumentsElements()); | 12504 object->HasFastArgumentsElements()); |
12571 | 12505 |
12572 Isolate* isolate = object->GetIsolate(); | 12506 Isolate* isolate = object->GetIsolate(); |
12573 | 12507 |
12574 // Array optimizations rely on the prototype lookups of Array objects always | 12508 // Array optimizations rely on the prototype lookups of Array objects always |
12575 // returning undefined. If there is a store to the initial prototype object, | 12509 // returning undefined. If there is a store to the initial prototype object, |
12576 // make sure all of these optimizations are invalidated. | 12510 // make sure all of these optimizations are invalidated. |
12577 isolate->UpdateArrayProtectorOnSetElement(object); | 12511 isolate->UpdateArrayProtectorOnSetElement(object); |
12578 | 12512 |
12579 Handle<FixedArray> backing_store(FixedArray::cast(object->elements())); | 12513 Handle<FixedArray> backing_store(FixedArray::cast(object->elements())); |
12580 if (backing_store->map() == | 12514 if (object->HasSloppyArgumentsElements()) { |
12581 isolate->heap()->sloppy_arguments_elements_map()) { | |
12582 backing_store = handle(FixedArray::cast(backing_store->get(1))); | 12515 backing_store = handle(FixedArray::cast(backing_store->get(1))); |
12583 } else { | 12516 } else { |
12584 backing_store = EnsureWritableFastElements(object); | 12517 backing_store = EnsureWritableFastElements(object); |
12585 } | 12518 } |
12586 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); | 12519 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); |
12587 | 12520 |
12588 if (check_prototype && | |
12589 (index >= capacity || backing_store->get(index)->IsTheHole())) { | |
12590 bool found; | |
12591 MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes( | |
12592 object, index, value, &found, language_mode); | |
12593 if (found) return result; | |
12594 } | |
12595 | |
12596 uint32_t new_capacity = capacity; | 12521 uint32_t new_capacity = capacity; |
12597 // Check if the length property of this object needs to be updated. | 12522 // Check if the length property of this object needs to be updated. |
12598 uint32_t array_length = 0; | 12523 uint32_t array_length = 0; |
12599 bool must_update_array_length = false; | 12524 bool must_update_array_length = false; |
12600 bool introduces_holes = true; | 12525 bool introduces_holes = true; |
12601 if (object->IsJSArray()) { | 12526 if (object->IsJSArray()) { |
12602 CHECK( | 12527 CHECK( |
12603 Handle<JSArray>::cast(object)->length()->ToArrayLength(&array_length)); | 12528 Handle<JSArray>::cast(object)->length()->ToArrayLength(&array_length)); |
12604 introduces_holes = index > array_length; | 12529 introduces_holes = index > array_length; |
12605 if (index >= array_length) { | 12530 if (index >= array_length) { |
(...skipping 20 matching lines...) Expand all Loading... |
12626 bool convert_to_slow = true; | 12551 bool convert_to_slow = true; |
12627 if ((index - capacity) < kMaxGap) { | 12552 if ((index - capacity) < kMaxGap) { |
12628 new_capacity = NewElementsCapacity(index + 1); | 12553 new_capacity = NewElementsCapacity(index + 1); |
12629 DCHECK(new_capacity > index); | 12554 DCHECK(new_capacity > index); |
12630 if (!object->ShouldConvertToSlowElements(new_capacity)) { | 12555 if (!object->ShouldConvertToSlowElements(new_capacity)) { |
12631 convert_to_slow = false; | 12556 convert_to_slow = false; |
12632 } | 12557 } |
12633 } | 12558 } |
12634 if (convert_to_slow) { | 12559 if (convert_to_slow) { |
12635 NormalizeElements(object); | 12560 NormalizeElements(object); |
12636 return SetDictionaryElement(object, index, value, NONE, language_mode, | 12561 SetDictionaryElement(object, index, value, NONE); |
12637 check_prototype); | 12562 return; |
12638 } | 12563 } |
12639 } | 12564 } |
12640 // Convert to fast double elements if appropriate. | 12565 // Convert to fast double elements if appropriate. |
12641 if (object->HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) { | 12566 if (object->HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) { |
12642 // Consider fixing the boilerplate as well if we have one. | 12567 // Consider fixing the boilerplate as well if we have one. |
12643 ElementsKind to_kind = IsHoleyElementsKind(elements_kind) | 12568 ElementsKind to_kind = IsHoleyElementsKind(elements_kind) |
12644 ? FAST_HOLEY_DOUBLE_ELEMENTS | 12569 ? FAST_HOLEY_DOUBLE_ELEMENTS |
12645 : FAST_DOUBLE_ELEMENTS; | 12570 : FAST_DOUBLE_ELEMENTS; |
12646 | 12571 |
12647 UpdateAllocationSite(object, to_kind); | 12572 UpdateAllocationSite(object, to_kind); |
12648 | 12573 |
12649 SetFastDoubleElementsCapacityAndLength(object, new_capacity, array_length); | 12574 SetFastDoubleElementsCapacityAndLength(object, new_capacity, array_length); |
12650 FixedDoubleArray::cast(object->elements())->set(index, value->Number()); | 12575 FixedDoubleArray::cast(object->elements())->set(index, value->Number()); |
12651 JSObject::ValidateElements(object); | 12576 JSObject::ValidateElements(object); |
12652 return value; | 12577 return; |
12653 } | 12578 } |
12654 // Change elements kind from Smi-only to generic FAST if necessary. | 12579 // Change elements kind from Smi-only to generic FAST if necessary. |
12655 if (object->HasFastSmiElements() && !value->IsSmi()) { | 12580 if (object->HasFastSmiElements() && !value->IsSmi()) { |
12656 ElementsKind kind = object->HasFastHoleyElements() | 12581 ElementsKind kind = object->HasFastHoleyElements() |
12657 ? FAST_HOLEY_ELEMENTS | 12582 ? FAST_HOLEY_ELEMENTS |
12658 : FAST_ELEMENTS; | 12583 : FAST_ELEMENTS; |
12659 | 12584 |
12660 UpdateAllocationSite(object, kind); | 12585 UpdateAllocationSite(object, kind); |
12661 Handle<Map> new_map = GetElementsTransitionMap(object, kind); | 12586 Handle<Map> new_map = GetElementsTransitionMap(object, kind); |
12662 JSObject::MigrateToMap(object, new_map); | 12587 JSObject::MigrateToMap(object, new_map); |
12663 DCHECK(IsFastObjectElementsKind(object->GetElementsKind())); | 12588 DCHECK(IsFastObjectElementsKind(object->GetElementsKind())); |
12664 } | 12589 } |
12665 // Increase backing store capacity if that's been decided previously. | 12590 // Increase backing store capacity if that's been decided previously. |
12666 if (new_capacity != capacity) { | 12591 if (new_capacity != capacity) { |
12667 SetFastElementsCapacitySmiMode smi_mode = | 12592 SetFastElementsCapacitySmiMode smi_mode = |
12668 value->IsSmi() && object->HasFastSmiElements() | 12593 value->IsSmi() && object->HasFastSmiElements() |
12669 ? kAllowSmiElements | 12594 ? kAllowSmiElements |
12670 : kDontAllowSmiElements; | 12595 : kDontAllowSmiElements; |
12671 Handle<FixedArray> new_elements = | 12596 Handle<FixedArray> new_elements = |
12672 SetFastElementsCapacityAndLength(object, new_capacity, array_length, | 12597 SetFastElementsCapacityAndLength(object, new_capacity, array_length, |
12673 smi_mode); | 12598 smi_mode); |
12674 new_elements->set(index, *value); | 12599 new_elements->set(index, *value); |
12675 JSObject::ValidateElements(object); | 12600 JSObject::ValidateElements(object); |
12676 return value; | 12601 return; |
12677 } | 12602 } |
12678 | 12603 |
12679 // Finally, set the new element and length. | 12604 // Finally, set the new element and length. |
12680 DCHECK(object->elements()->IsFixedArray()); | 12605 DCHECK(object->elements()->IsFixedArray()); |
12681 backing_store->set(index, *value); | 12606 backing_store->set(index, *value); |
12682 if (must_update_array_length) { | 12607 if (must_update_array_length) { |
12683 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length)); | 12608 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length)); |
12684 } | 12609 } |
12685 return value; | |
12686 } | 12610 } |
12687 | 12611 |
12688 | 12612 |
12689 MaybeHandle<Object> JSObject::SetDictionaryElement( | 12613 void JSObject::SetSloppyArgumentsElement(Handle<JSObject> object, |
12690 Handle<JSObject> object, uint32_t index, Handle<Object> value, | 12614 uint32_t index, Handle<Object> value, |
12691 PropertyAttributes attributes, LanguageMode language_mode, | 12615 PropertyAttributes attributes) { |
12692 bool check_prototype, SetPropertyMode set_mode) { | 12616 // TODO(verwaest): Handle with the elements accessor. |
12693 DCHECK(object->HasDictionaryElements() || | 12617 Isolate* isolate = object->GetIsolate(); |
12694 object->HasDictionaryArgumentsElements()); | 12618 |
| 12619 DCHECK(object->HasSloppyArgumentsElements()); |
| 12620 |
| 12621 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements())); |
| 12622 uint32_t length = parameter_map->length(); |
| 12623 Handle<Object> probe = |
| 12624 index < length - 2 |
| 12625 ? Handle<Object>(parameter_map->get(index + 2), isolate) |
| 12626 : Handle<Object>(); |
| 12627 if (!probe.is_null() && !probe->IsTheHole()) { |
| 12628 Handle<Context> context(Context::cast(parameter_map->get(0))); |
| 12629 int context_index = Handle<Smi>::cast(probe)->value(); |
| 12630 DCHECK(!context->get(context_index)->IsTheHole()); |
| 12631 context->set(context_index, *value); |
| 12632 |
| 12633 if (attributes == NONE) return; |
| 12634 |
| 12635 // Redefining attributes of an aliased element destroys fast aliasing. |
| 12636 parameter_map->set_the_hole(index + 2); |
| 12637 // For elements that are still writable we re-establish slow aliasing. |
| 12638 if ((attributes & READ_ONLY) == 0) { |
| 12639 value = Handle<Object>::cast( |
| 12640 isolate->factory()->NewAliasedArgumentsEntry(context_index)); |
| 12641 } |
| 12642 } |
| 12643 |
| 12644 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1))); |
| 12645 if (arguments->IsDictionary()) { |
| 12646 SetDictionaryElement(object, index, value, attributes); |
| 12647 } else { |
| 12648 SetFastElement(object, index, value); |
| 12649 } |
| 12650 } |
| 12651 |
| 12652 |
| 12653 void JSObject::SetDictionaryElement(Handle<JSObject> object, uint32_t index, |
| 12654 Handle<Object> value, |
| 12655 PropertyAttributes attributes) { |
| 12656 // TODO(verwaest): Handle with the elements accessor. |
12695 Isolate* isolate = object->GetIsolate(); | 12657 Isolate* isolate = object->GetIsolate(); |
12696 | 12658 |
12697 // Insert element in the dictionary. | 12659 // Insert element in the dictionary. |
12698 Handle<FixedArray> elements(FixedArray::cast(object->elements())); | 12660 Handle<FixedArray> elements(FixedArray::cast(object->elements())); |
12699 bool is_arguments = | 12661 bool is_arguments = |
12700 (elements->map() == isolate->heap()->sloppy_arguments_elements_map()); | 12662 (elements->map() == isolate->heap()->sloppy_arguments_elements_map()); |
| 12663 |
| 12664 DCHECK(object->HasDictionaryElements() || |
| 12665 object->HasDictionaryArgumentsElements()); |
| 12666 |
12701 Handle<SeededNumberDictionary> dictionary(is_arguments | 12667 Handle<SeededNumberDictionary> dictionary(is_arguments |
12702 ? SeededNumberDictionary::cast(elements->get(1)) | 12668 ? SeededNumberDictionary::cast(elements->get(1)) |
12703 : SeededNumberDictionary::cast(*elements)); | 12669 : SeededNumberDictionary::cast(*elements)); |
12704 | 12670 |
12705 int entry = dictionary->FindEntry(index); | 12671 int entry = dictionary->FindEntry(index); |
12706 if (entry != SeededNumberDictionary::kNotFound) { | 12672 if (entry != SeededNumberDictionary::kNotFound) { |
12707 Handle<Object> element(dictionary->ValueAt(entry), isolate); | 12673 Handle<Object> element(dictionary->ValueAt(entry), isolate); |
12708 PropertyDetails details = dictionary->DetailsAt(entry); | 12674 PropertyDetails details = dictionary->DetailsAt(entry); |
12709 if (details.type() == ACCESSOR_CONSTANT && set_mode == SET_PROPERTY) { | 12675 DCHECK(details.IsConfigurable() || !details.IsReadOnly() || |
12710 return SetElementWithCallback(object, element, index, value, object, | 12676 element->IsTheHole()); |
12711 language_mode); | 12677 dictionary->UpdateMaxNumberKey(index); |
12712 } else if (set_mode == DEFINE_PROPERTY && !details.IsConfigurable() && | |
12713 details.kind() == kAccessor) { | |
12714 return RedefineNonconfigurableProperty( | |
12715 isolate, isolate->factory()->NewNumberFromUint(index), | |
12716 isolate->factory()->undefined_value(), language_mode); | |
12717 | 12678 |
12718 } else if ((set_mode == DEFINE_PROPERTY && !details.IsConfigurable() && | 12679 details = PropertyDetails(attributes, DATA, details.dictionary_index(), |
12719 details.IsReadOnly()) || | 12680 PropertyCellType::kNoCell); |
12720 (set_mode == SET_PROPERTY && details.IsReadOnly() && | 12681 dictionary->DetailsAtPut(entry, details); |
12721 !element->IsTheHole())) { | |
12722 // If a value has not been initialized we allow writing to it even if it | |
12723 // is read-only (a declared const that has not been initialized). | |
12724 return WriteToReadOnlyProperty( | |
12725 isolate, object, isolate->factory()->NewNumberFromUint(index), | |
12726 isolate->factory()->undefined_value(), language_mode); | |
12727 } else { | |
12728 DCHECK(details.IsConfigurable() || !details.IsReadOnly() || | |
12729 element->IsTheHole()); | |
12730 dictionary->UpdateMaxNumberKey(index); | |
12731 if (set_mode == DEFINE_PROPERTY) { | |
12732 details = PropertyDetails(attributes, DATA, details.dictionary_index(), | |
12733 PropertyCellType::kNoCell); | |
12734 dictionary->DetailsAtPut(entry, details); | |
12735 } | |
12736 | 12682 |
12737 // Elements of the arguments object in slow mode might be slow aliases. | 12683 // Elements of the arguments object in slow mode might be slow aliases. |
12738 if (is_arguments && element->IsAliasedArgumentsEntry()) { | 12684 if (is_arguments && element->IsAliasedArgumentsEntry()) { |
12739 Handle<AliasedArgumentsEntry> entry = | 12685 Handle<AliasedArgumentsEntry> entry = |
12740 Handle<AliasedArgumentsEntry>::cast(element); | 12686 Handle<AliasedArgumentsEntry>::cast(element); |
12741 Handle<Context> context(Context::cast(elements->get(0))); | 12687 Handle<Context> context(Context::cast(elements->get(0))); |
12742 int context_index = entry->aliased_context_slot(); | 12688 int context_index = entry->aliased_context_slot(); |
12743 DCHECK(!context->get(context_index)->IsTheHole()); | 12689 DCHECK(!context->get(context_index)->IsTheHole()); |
12744 context->set(context_index, *value); | 12690 context->set(context_index, *value); |
12745 // For elements that are still writable we keep slow aliasing. | 12691 // For elements that are still writable we keep slow aliasing. |
12746 if (!details.IsReadOnly()) value = element; | 12692 if (!details.IsReadOnly()) value = element; |
12747 } | |
12748 dictionary->ValueAtPut(entry, *value); | |
12749 } | 12693 } |
| 12694 dictionary->ValueAtPut(entry, *value); |
12750 } else { | 12695 } else { |
12751 // Index not already used. Look for an accessor in the prototype chain. | 12696 DCHECK(object->map()->is_extensible()); |
12752 // Can cause GC! | |
12753 if (check_prototype) { | |
12754 bool found; | |
12755 MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes( | |
12756 object, index, value, &found, language_mode); | |
12757 if (found) return result; | |
12758 } | |
12759 | |
12760 // When we set the is_extensible flag to false we always force the | |
12761 // element into dictionary mode (and force them to stay there). | |
12762 if (!object->map()->is_extensible()) { | |
12763 if (is_sloppy(language_mode)) { | |
12764 return isolate->factory()->undefined_value(); | |
12765 } else { | |
12766 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); | |
12767 Handle<String> name = isolate->factory()->NumberToString(number); | |
12768 THROW_NEW_ERROR( | |
12769 isolate, NewTypeError(MessageTemplate::kObjectNotExtensible, name), | |
12770 Object); | |
12771 } | |
12772 } | |
12773 | |
12774 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); | 12697 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); |
12775 Handle<SeededNumberDictionary> new_dictionary = | 12698 Handle<SeededNumberDictionary> new_dictionary = |
12776 SeededNumberDictionary::AddNumberEntry(dictionary, index, value, | 12699 SeededNumberDictionary::AddNumberEntry(dictionary, index, value, |
12777 details); | 12700 details); |
12778 if (*dictionary != *new_dictionary) { | 12701 if (*dictionary != *new_dictionary) { |
12779 if (is_arguments) { | 12702 if (is_arguments) { |
12780 elements->set(1, *new_dictionary); | 12703 elements->set(1, *new_dictionary); |
12781 } else { | 12704 } else { |
12782 object->set_elements(*new_dictionary); | 12705 object->set_elements(*new_dictionary); |
12783 } | 12706 } |
(...skipping 30 matching lines...) Expand all Loading... |
12814 } | 12737 } |
12815 JSObject::ValidateElements(object); | 12738 JSObject::ValidateElements(object); |
12816 #ifdef DEBUG | 12739 #ifdef DEBUG |
12817 if (FLAG_trace_normalization) { | 12740 if (FLAG_trace_normalization) { |
12818 OFStream os(stdout); | 12741 OFStream os(stdout); |
12819 os << "Object elements are fast case again:\n"; | 12742 os << "Object elements are fast case again:\n"; |
12820 object->Print(os); | 12743 object->Print(os); |
12821 } | 12744 } |
12822 #endif | 12745 #endif |
12823 } | 12746 } |
12824 return value; | |
12825 } | 12747 } |
12826 | 12748 |
12827 MaybeHandle<Object> JSObject::SetFastDoubleElement(Handle<JSObject> object, | 12749 void JSObject::SetFastDoubleElement(Handle<JSObject> object, uint32_t index, |
12828 uint32_t index, | 12750 Handle<Object> value) { |
12829 Handle<Object> value, | |
12830 LanguageMode language_mode, | |
12831 bool check_prototype) { | |
12832 DCHECK(object->HasFastDoubleElements()); | 12751 DCHECK(object->HasFastDoubleElements()); |
12833 | 12752 |
12834 Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements())); | 12753 Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements())); |
12835 uint32_t elms_length = static_cast<uint32_t>(base_elms->length()); | 12754 uint32_t elms_length = static_cast<uint32_t>(base_elms->length()); |
| 12755 uint32_t length = elms_length; |
12836 | 12756 |
12837 // If storing to an element that isn't in the array, pass the store request | |
12838 // up the prototype chain before storing in the receiver's elements. | |
12839 if (check_prototype && | |
12840 (index >= elms_length || | |
12841 Handle<FixedDoubleArray>::cast(base_elms)->is_the_hole(index))) { | |
12842 bool found; | |
12843 MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes( | |
12844 object, index, value, &found, language_mode); | |
12845 if (found) return result; | |
12846 } | |
12847 | |
12848 // If the value object is not a heap number, switch to fast elements and try | |
12849 // again. | |
12850 bool value_is_smi = value->IsSmi(); | |
12851 bool introduces_holes = true; | 12757 bool introduces_holes = true; |
12852 uint32_t length = elms_length; | |
12853 if (object->IsJSArray()) { | 12758 if (object->IsJSArray()) { |
| 12759 // In case of JSArray, the length does not equal the capacity. |
12854 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength(&length)); | 12760 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength(&length)); |
12855 introduces_holes = index > length; | 12761 introduces_holes = index > length; |
12856 } else { | 12762 } else { |
12857 introduces_holes = index >= elms_length; | 12763 introduces_holes = index >= elms_length; |
12858 } | 12764 } |
12859 | 12765 |
| 12766 // If the value object is not a heap number, switch to fast elements and try |
| 12767 // again. |
12860 if (!value->IsNumber()) { | 12768 if (!value->IsNumber()) { |
12861 SetFastElementsCapacityAndLength(object, elms_length, length, | 12769 SetFastElementsCapacityAndLength(object, elms_length, length, |
12862 kDontAllowSmiElements); | 12770 kDontAllowSmiElements); |
12863 Handle<Object> result; | 12771 SetFastElement(object, index, value); |
12864 ASSIGN_RETURN_ON_EXCEPTION( | 12772 return; |
12865 object->GetIsolate(), result, | |
12866 SetFastElement(object, index, value, language_mode, check_prototype), | |
12867 Object); | |
12868 JSObject::ValidateElements(object); | |
12869 return result; | |
12870 } | 12773 } |
12871 | 12774 |
12872 double double_value = value_is_smi | |
12873 ? static_cast<double>(Handle<Smi>::cast(value)->value()) | |
12874 : Handle<HeapNumber>::cast(value)->value(); | |
12875 | |
12876 // If the array is growing, and it's not growth by a single element at the | 12775 // If the array is growing, and it's not growth by a single element at the |
12877 // end, make sure that the ElementsKind is HOLEY. | 12776 // end, make sure that the ElementsKind is HOLEY. |
12878 ElementsKind elements_kind = object->GetElementsKind(); | 12777 ElementsKind elements_kind = object->GetElementsKind(); |
12879 if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) { | 12778 if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) { |
12880 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind); | 12779 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind); |
12881 TransitionElementsKind(object, transitioned_kind); | 12780 TransitionElementsKind(object, transitioned_kind); |
12882 } | 12781 } |
12883 | 12782 |
12884 // Check whether there is extra space in the fixed array. | 12783 // Check whether there is extra space in the fixed array. |
12885 if (index < elms_length) { | 12784 if (index < elms_length) { |
12886 Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements())); | 12785 Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements())); |
12887 elms->set(index, double_value); | 12786 elms->set(index, value->Number()); |
12888 if (object->IsJSArray()) { | 12787 if (object->IsJSArray()) { |
12889 // Update the length of the array if needed. | 12788 // Update the length of the array if needed. |
12890 uint32_t array_length = 0; | 12789 uint32_t array_length = 0; |
12891 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength( | 12790 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength( |
12892 &array_length)); | 12791 &array_length)); |
12893 if (index >= array_length) { | 12792 if (index >= array_length) { |
12894 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1)); | 12793 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1)); |
12895 } | 12794 } |
12896 } | 12795 } |
12897 return value; | 12796 return; |
12898 } | 12797 } |
12899 | 12798 |
12900 // Allow gap in fast case. | 12799 // Allow gap in fast case. |
12901 if ((index - elms_length) < kMaxGap) { | 12800 if ((index - elms_length) < kMaxGap) { |
12902 // Try allocating extra space. | 12801 // Try allocating extra space. |
12903 int new_capacity = NewElementsCapacity(index+1); | 12802 int new_capacity = NewElementsCapacity(index+1); |
12904 if (!object->ShouldConvertToSlowElements(new_capacity)) { | 12803 if (!object->ShouldConvertToSlowElements(new_capacity)) { |
12905 DCHECK(static_cast<uint32_t>(new_capacity) > index); | 12804 DCHECK(static_cast<uint32_t>(new_capacity) > index); |
12906 SetFastDoubleElementsCapacityAndLength(object, new_capacity, index + 1); | 12805 SetFastDoubleElementsCapacityAndLength(object, new_capacity, index + 1); |
12907 FixedDoubleArray::cast(object->elements())->set(index, double_value); | 12806 FixedDoubleArray::cast(object->elements())->set(index, value->Number()); |
12908 JSObject::ValidateElements(object); | 12807 JSObject::ValidateElements(object); |
12909 return value; | 12808 return; |
12910 } | 12809 } |
12911 } | 12810 } |
12912 | 12811 |
12913 // Otherwise default to slow case. | 12812 // Otherwise default to slow case. |
12914 DCHECK(object->HasFastDoubleElements()); | 12813 DCHECK(object->HasFastDoubleElements()); |
12915 DCHECK(object->map()->has_fast_double_elements()); | 12814 DCHECK(object->map()->has_fast_double_elements()); |
12916 DCHECK(object->elements()->IsFixedDoubleArray() || | 12815 DCHECK(object->elements()->IsFixedDoubleArray() || |
12917 object->elements()->length() == 0); | 12816 object->elements()->length() == 0); |
12918 | 12817 |
12919 NormalizeElements(object); | 12818 NormalizeElements(object); |
12920 DCHECK(object->HasDictionaryElements()); | 12819 DCHECK(object->HasDictionaryElements()); |
12921 return SetElement(object, index, value, NONE, language_mode, check_prototype); | 12820 SetDictionaryElement(object, index, value, NONE); |
12922 } | 12821 } |
12923 | 12822 |
12924 | 12823 |
| 12824 // static |
12925 MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object, | 12825 MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object, |
12926 uint32_t index, Handle<Object> value, | 12826 uint32_t index, Handle<Object> value, |
12927 PropertyAttributes attributes, | |
12928 LanguageMode language_mode) { | 12827 LanguageMode language_mode) { |
12929 if (object->IsJSProxy()) { | 12828 Isolate* isolate = object->GetIsolate(); |
12930 return JSProxy::SetElementWithHandler(Handle<JSProxy>::cast(object), object, | 12829 LookupIterator it(isolate, object, index); |
12931 index, value, language_mode); | 12830 return SetProperty(&it, value, language_mode, MAY_BE_STORE_FROM_KEYED); |
12932 } | |
12933 return JSObject::SetElement(Handle<JSObject>::cast(object), index, value, | |
12934 attributes, language_mode); | |
12935 } | 12831 } |
12936 | 12832 |
12937 | 12833 |
12938 MaybeHandle<Object> JSObject::SetOwnElement(Handle<JSObject> object, | 12834 // static |
12939 uint32_t index, | 12835 MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> receiver, |
12940 Handle<Object> value, | 12836 uint32_t index, |
12941 PropertyAttributes attributes, | 12837 Handle<Object> value, |
12942 LanguageMode language_mode) { | 12838 PropertyAttributes attributes) { |
12943 DCHECK(!object->HasExternalArrayElements()); | 12839 DCHECK(receiver->map()->is_extensible()); |
12944 return JSObject::SetElement(object, index, value, attributes, language_mode, | |
12945 false); | |
12946 } | |
12947 | 12840 |
| 12841 Isolate* isolate = receiver->GetIsolate(); |
12948 | 12842 |
12949 MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object, | 12843 // TODO(verwaest): Use ElementAccessor. |
12950 uint32_t index, Handle<Object> value, | 12844 Handle<Object> old_length_handle; |
12951 PropertyAttributes attributes, | 12845 if (receiver->IsJSArray() && receiver->map()->is_observed()) { |
12952 LanguageMode language_mode, | 12846 old_length_handle = handle(JSArray::cast(*receiver)->length(), isolate); |
12953 bool check_prototype, | |
12954 SetPropertyMode set_mode) { | |
12955 Isolate* isolate = object->GetIsolate(); | |
12956 | |
12957 if (object->HasExternalArrayElements() || | |
12958 object->HasFixedTypedArrayElements()) { | |
12959 if (!value->IsNumber() && !value->IsUndefined()) { | |
12960 ASSIGN_RETURN_ON_EXCEPTION( | |
12961 isolate, value, | |
12962 Execution::ToNumber(isolate, value), Object); | |
12963 } | |
12964 } | 12847 } |
12965 | 12848 |
12966 // Check access rights if needed. | 12849 if (attributes != NONE) { |
12967 if (object->IsAccessCheckNeeded()) { | 12850 Handle<SeededNumberDictionary> d = JSObject::NormalizeElements(receiver); |
12968 if (!isolate->MayAccess(object)) { | 12851 // TODO(verwaest): Move this into NormalizeElements. |
12969 isolate->ReportFailedAccessCheck(object); | 12852 d->set_requires_slow_elements(); |
12970 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
12971 return value; | |
12972 } | |
12973 } | 12853 } |
12974 | 12854 |
12975 if (object->IsJSGlobalProxy()) { | 12855 Handle<Object> result = value; |
12976 PrototypeIterator iter(isolate, object); | 12856 |
12977 if (iter.IsAtEnd()) return value; | 12857 switch (receiver->GetElementsKind()) { |
12978 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); | 12858 case FAST_SMI_ELEMENTS: |
12979 return SetElement( | 12859 case FAST_ELEMENTS: |
12980 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index, | 12860 case FAST_HOLEY_SMI_ELEMENTS: |
12981 value, attributes, language_mode, check_prototype, set_mode); | 12861 case FAST_HOLEY_ELEMENTS: |
| 12862 SetFastElement(receiver, index, value); |
| 12863 break; |
| 12864 case FAST_DOUBLE_ELEMENTS: |
| 12865 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 12866 SetFastDoubleElement(receiver, index, value); |
| 12867 break; |
| 12868 |
| 12869 case DICTIONARY_ELEMENTS: |
| 12870 SetDictionaryElement(receiver, index, value, attributes); |
| 12871 break; |
| 12872 case SLOPPY_ARGUMENTS_ELEMENTS: |
| 12873 SetSloppyArgumentsElement(receiver, index, value, attributes); |
| 12874 break; |
| 12875 |
| 12876 // Elements cannot be added to typed arrays. |
| 12877 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
| 12878 case EXTERNAL_##TYPE##_ELEMENTS: \ |
| 12879 case TYPE##_ELEMENTS: |
| 12880 |
| 12881 TYPED_ARRAYS(TYPED_ARRAY_CASE) |
| 12882 |
| 12883 #undef TYPED_ARRAY_CASE |
| 12884 UNREACHABLE(); |
| 12885 break; |
12982 } | 12886 } |
12983 | 12887 |
12984 // Don't allow element properties to be redefined for external arrays. | 12888 if (!old_length_handle.is_null() && |
12985 if ((object->HasExternalArrayElements() || | 12889 !old_length_handle->SameValue( |
12986 object->HasFixedTypedArrayElements()) && | 12890 Handle<JSArray>::cast(receiver)->length())) { |
12987 set_mode == DEFINE_PROPERTY) { | 12891 // |old_length_handle| is kept null above unless the receiver is observed. |
12988 THROW_NEW_ERROR( | 12892 DCHECK(receiver->map()->is_observed()); |
12989 isolate, NewTypeError(MessageTemplate::kRedefineExternalArray), Object); | 12893 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
12990 } | 12894 Handle<String> name = isolate->factory()->Uint32ToString(index); |
| 12895 Handle<Object> new_length_handle(array->length(), isolate); |
| 12896 uint32_t old_length = 0; |
| 12897 uint32_t new_length = 0; |
| 12898 CHECK(old_length_handle->ToArrayLength(&old_length)); |
| 12899 CHECK(new_length_handle->ToArrayLength(&new_length)); |
12991 | 12900 |
12992 // Normalize the elements to enable attributes on the property. | 12901 RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object); |
12993 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) { | |
12994 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); | |
12995 // Make sure that we never go back to fast case. | |
12996 dictionary->set_requires_slow_elements(); | |
12997 } | |
12998 | |
12999 if (!object->map()->is_observed()) { | |
13000 return object->HasIndexedInterceptor() | |
13001 ? SetElementWithInterceptor(object, index, value, attributes, | |
13002 language_mode, check_prototype, | |
13003 set_mode) | |
13004 : SetElementWithoutInterceptor(object, index, value, attributes, | |
13005 language_mode, check_prototype, | |
13006 set_mode); | |
13007 } | |
13008 | |
13009 Maybe<PropertyAttributes> maybe = | |
13010 JSReceiver::GetOwnElementAttributes(object, index); | |
13011 if (!maybe.IsJust()) return MaybeHandle<Object>(); | |
13012 PropertyAttributes old_attributes = maybe.FromJust(); | |
13013 | |
13014 Handle<Object> old_value = isolate->factory()->the_hole_value(); | |
13015 Handle<Object> old_length_handle; | |
13016 Handle<Object> new_length_handle; | |
13017 | |
13018 if (old_attributes != ABSENT) { | |
13019 if (GetOwnElementAccessorPair(object, index).is_null()) { | |
13020 old_value = Object::GetElement(isolate, object, index).ToHandleChecked(); | |
13021 } | |
13022 } else if (object->IsJSArray()) { | |
13023 // Store old array length in case adding an element grows the array. | |
13024 old_length_handle = handle(Handle<JSArray>::cast(object)->length(), | |
13025 isolate); | |
13026 } | |
13027 | |
13028 // Check for lookup interceptor | |
13029 Handle<Object> result; | |
13030 ASSIGN_RETURN_ON_EXCEPTION( | |
13031 isolate, result, | |
13032 object->HasIndexedInterceptor() | |
13033 ? SetElementWithInterceptor(object, index, value, attributes, | |
13034 language_mode, check_prototype, set_mode) | |
13035 : SetElementWithoutInterceptor(object, index, value, attributes, | |
13036 language_mode, check_prototype, | |
13037 set_mode), | |
13038 Object); | |
13039 | |
13040 Handle<String> name = isolate->factory()->Uint32ToString(index); | |
13041 maybe = GetOwnElementAttributes(object, index); | |
13042 if (!maybe.IsJust()) return MaybeHandle<Object>(); | |
13043 PropertyAttributes new_attributes = maybe.FromJust(); | |
13044 | |
13045 if (old_attributes == ABSENT) { | |
13046 if (object->IsJSArray() && | |
13047 !old_length_handle->SameValue( | |
13048 Handle<JSArray>::cast(object)->length())) { | |
13049 new_length_handle = handle(Handle<JSArray>::cast(object)->length(), | |
13050 isolate); | |
13051 uint32_t old_length = 0; | |
13052 uint32_t new_length = 0; | |
13053 CHECK(old_length_handle->ToArrayLength(&old_length)); | |
13054 CHECK(new_length_handle->ToArrayLength(&new_length)); | |
13055 | |
13056 RETURN_ON_EXCEPTION( | |
13057 isolate, BeginPerformSplice(Handle<JSArray>::cast(object)), Object); | |
13058 RETURN_ON_EXCEPTION( | |
13059 isolate, EnqueueChangeRecord(object, "add", name, old_value), Object); | |
13060 RETURN_ON_EXCEPTION( | |
13061 isolate, EnqueueChangeRecord(object, "update", | |
13062 isolate->factory()->length_string(), | |
13063 old_length_handle), | |
13064 Object); | |
13065 RETURN_ON_EXCEPTION( | |
13066 isolate, EndPerformSplice(Handle<JSArray>::cast(object)), Object); | |
13067 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0); | |
13068 RETURN_ON_EXCEPTION( | |
13069 isolate, | |
13070 EnqueueSpliceRecord(Handle<JSArray>::cast(object), old_length, | |
13071 deleted, new_length - old_length), | |
13072 Object); | |
13073 } else { | |
13074 RETURN_ON_EXCEPTION( | |
13075 isolate, EnqueueChangeRecord(object, "add", name, old_value), Object); | |
13076 } | |
13077 } else if (old_value->IsTheHole()) { | |
13078 RETURN_ON_EXCEPTION( | 12902 RETURN_ON_EXCEPTION( |
13079 isolate, EnqueueChangeRecord(object, "reconfigure", name, old_value), | 12903 isolate, JSObject::EnqueueChangeRecord( |
| 12904 array, "add", name, isolate->factory()->the_hole_value()), |
13080 Object); | 12905 Object); |
13081 } else { | 12906 RETURN_ON_EXCEPTION( |
13082 Handle<Object> new_value = | 12907 isolate, JSObject::EnqueueChangeRecord( |
13083 Object::GetElement(isolate, object, index).ToHandleChecked(); | 12908 array, "update", isolate->factory()->length_string(), |
13084 bool value_changed = !old_value->SameValue(*new_value); | 12909 old_length_handle), |
13085 if (old_attributes != new_attributes) { | 12910 Object); |
13086 if (!value_changed) old_value = isolate->factory()->the_hole_value(); | 12911 RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object); |
13087 RETURN_ON_EXCEPTION( | 12912 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0); |
13088 isolate, EnqueueChangeRecord(object, "reconfigure", name, old_value), | 12913 RETURN_ON_EXCEPTION(isolate, EnqueueSpliceRecord(array, old_length, deleted, |
13089 Object); | 12914 new_length - old_length), |
13090 } else if (value_changed) { | 12915 Object); |
13091 RETURN_ON_EXCEPTION( | 12916 } else if (receiver->map()->is_observed()) { |
13092 isolate, EnqueueChangeRecord(object, "update", name, old_value), | 12917 Handle<String> name = isolate->factory()->Uint32ToString(index); |
13093 Object); | 12918 RETURN_ON_EXCEPTION(isolate, JSObject::EnqueueChangeRecord( |
13094 } | 12919 receiver, "add", name, |
| 12920 isolate->factory()->the_hole_value()), |
| 12921 Object); |
13095 } | 12922 } |
13096 | 12923 |
13097 return result; | 12924 return result; |
13098 } | 12925 } |
13099 | 12926 |
13100 | 12927 |
13101 MaybeHandle<Object> JSObject::SetElementWithoutInterceptor( | |
13102 Handle<JSObject> object, uint32_t index, Handle<Object> value, | |
13103 PropertyAttributes attributes, LanguageMode language_mode, | |
13104 bool check_prototype, SetPropertyMode set_mode) { | |
13105 DCHECK(object->HasDictionaryElements() || | |
13106 object->HasDictionaryArgumentsElements() || | |
13107 (attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0); | |
13108 Isolate* isolate = object->GetIsolate(); | |
13109 if (FLAG_trace_external_array_abuse && | |
13110 IsExternalArrayElementsKind(object->GetElementsKind())) { | |
13111 CheckArrayAbuse(object, "external elements write", index); | |
13112 } | |
13113 if (FLAG_trace_js_array_abuse && | |
13114 !IsExternalArrayElementsKind(object->GetElementsKind())) { | |
13115 if (object->IsJSArray()) { | |
13116 CheckArrayAbuse(object, "elements write", index, true); | |
13117 } | |
13118 } | |
13119 if (object->IsJSArray() && JSArray::WouldChangeReadOnlyLength( | |
13120 Handle<JSArray>::cast(object), index)) { | |
13121 if (is_sloppy(language_mode)) { | |
13122 return value; | |
13123 } else { | |
13124 return JSArray::ReadOnlyLengthError(Handle<JSArray>::cast(object)); | |
13125 } | |
13126 } | |
13127 switch (object->GetElementsKind()) { | |
13128 case FAST_SMI_ELEMENTS: | |
13129 case FAST_ELEMENTS: | |
13130 case FAST_HOLEY_SMI_ELEMENTS: | |
13131 case FAST_HOLEY_ELEMENTS: | |
13132 return SetFastElement(object, index, value, language_mode, | |
13133 check_prototype); | |
13134 case FAST_DOUBLE_ELEMENTS: | |
13135 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
13136 return SetFastDoubleElement(object, index, value, language_mode, | |
13137 check_prototype); | |
13138 | |
13139 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | |
13140 case EXTERNAL_##TYPE##_ELEMENTS: { \ | |
13141 Handle<External##Type##Array> array( \ | |
13142 External##Type##Array::cast(object->elements())); \ | |
13143 return External##Type##Array::SetValue(object, array, index, value); \ | |
13144 } \ | |
13145 case TYPE##_ELEMENTS: { \ | |
13146 Handle<Fixed##Type##Array> array( \ | |
13147 Fixed##Type##Array::cast(object->elements())); \ | |
13148 return Fixed##Type##Array::SetValue(object, array, index, value); \ | |
13149 } | |
13150 | |
13151 TYPED_ARRAYS(TYPED_ARRAY_CASE) | |
13152 | |
13153 #undef TYPED_ARRAY_CASE | |
13154 | |
13155 case DICTIONARY_ELEMENTS: | |
13156 return SetDictionaryElement(object, index, value, attributes, | |
13157 language_mode, check_prototype, set_mode); | |
13158 case SLOPPY_ARGUMENTS_ELEMENTS: { | |
13159 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements())); | |
13160 uint32_t length = parameter_map->length(); | |
13161 Handle<Object> probe = index < length - 2 ? | |
13162 Handle<Object>(parameter_map->get(index + 2), isolate) : | |
13163 Handle<Object>(); | |
13164 if (!probe.is_null() && !probe->IsTheHole()) { | |
13165 Handle<Context> context(Context::cast(parameter_map->get(0))); | |
13166 int context_index = Handle<Smi>::cast(probe)->value(); | |
13167 DCHECK(!context->get(context_index)->IsTheHole()); | |
13168 context->set(context_index, *value); | |
13169 // Redefining attributes of an aliased element destroys fast aliasing. | |
13170 if (set_mode == SET_PROPERTY || attributes == NONE) return value; | |
13171 parameter_map->set_the_hole(index + 2); | |
13172 // For elements that are still writable we re-establish slow aliasing. | |
13173 if ((attributes & READ_ONLY) == 0) { | |
13174 value = Handle<Object>::cast( | |
13175 isolate->factory()->NewAliasedArgumentsEntry(context_index)); | |
13176 } | |
13177 } | |
13178 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1))); | |
13179 if (arguments->IsDictionary()) { | |
13180 return SetDictionaryElement(object, index, value, attributes, | |
13181 language_mode, check_prototype, set_mode); | |
13182 } else { | |
13183 return SetFastElement(object, index, value, language_mode, | |
13184 check_prototype); | |
13185 } | |
13186 } | |
13187 } | |
13188 // All possible cases have been handled above. Add a return to avoid the | |
13189 // complaints from the compiler. | |
13190 UNREACHABLE(); | |
13191 return isolate->factory()->null_value(); | |
13192 } | |
13193 | |
13194 | |
13195 const double AllocationSite::kPretenureRatio = 0.85; | 12928 const double AllocationSite::kPretenureRatio = 0.85; |
13196 | 12929 |
13197 | 12930 |
13198 void AllocationSite::ResetPretenureDecision() { | 12931 void AllocationSite::ResetPretenureDecision() { |
13199 set_pretenure_decision(kUndecided); | 12932 set_pretenure_decision(kUndecided); |
13200 set_memento_found_count(0); | 12933 set_memento_found_count(0); |
13201 set_memento_create_count(0); | 12934 set_memento_create_count(0); |
13202 } | 12935 } |
13203 | 12936 |
13204 | 12937 |
(...skipping 1767 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
14972 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE) | 14705 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE) |
14973 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE | 14706 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE |
14974 | 14707 |
14975 default: | 14708 default: |
14976 UNREACHABLE(); | 14709 UNREACHABLE(); |
14977 return 0; | 14710 return 0; |
14978 } | 14711 } |
14979 } | 14712 } |
14980 | 14713 |
14981 | 14714 |
| 14715 Handle<Object> FixedArray::SetValue(Handle<JSObject> holder, |
| 14716 Handle<FixedArray> array, uint32_t index, |
| 14717 Handle<Object> value) { |
| 14718 array->set(index, *value); |
| 14719 return value; |
| 14720 } |
| 14721 |
| 14722 |
| 14723 Handle<Object> FixedDoubleArray::SetValue(Handle<JSObject> holder, |
| 14724 Handle<FixedDoubleArray> array, |
| 14725 uint32_t index, |
| 14726 Handle<Object> value) { |
| 14727 array->set(index, value->Number()); |
| 14728 return value; |
| 14729 } |
| 14730 |
| 14731 |
14982 Handle<Object> ExternalUint8ClampedArray::SetValue( | 14732 Handle<Object> ExternalUint8ClampedArray::SetValue( |
14983 Handle<JSObject> holder, Handle<ExternalUint8ClampedArray> array, | 14733 Handle<JSObject> holder, Handle<ExternalUint8ClampedArray> array, |
14984 uint32_t index, Handle<Object> value) { | 14734 uint32_t index, Handle<Object> value) { |
14985 uint8_t clamped_value = 0; | 14735 uint8_t clamped_value = 0; |
14986 Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(holder); | 14736 Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(holder); |
14987 if (!view->WasNeutered()) { | 14737 if (!view->WasNeutered()) { |
14988 if (index < static_cast<uint32_t>(array->length())) { | 14738 if (index < static_cast<uint32_t>(array->length())) { |
14989 if (value->IsSmi()) { | 14739 if (value->IsSmi()) { |
14990 int int_value = Handle<Smi>::cast(value)->value(); | 14740 int int_value = Handle<Smi>::cast(value)->value(); |
14991 if (int_value < 0) { | 14741 if (int_value < 0) { |
(...skipping 1983 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
16975 Handle<Object> new_value) { | 16725 Handle<Object> new_value) { |
16976 if (cell->value() != *new_value) { | 16726 if (cell->value() != *new_value) { |
16977 cell->set_value(*new_value); | 16727 cell->set_value(*new_value); |
16978 Isolate* isolate = cell->GetIsolate(); | 16728 Isolate* isolate = cell->GetIsolate(); |
16979 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 16729 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
16980 isolate, DependentCode::kPropertyCellChangedGroup); | 16730 isolate, DependentCode::kPropertyCellChangedGroup); |
16981 } | 16731 } |
16982 } | 16732 } |
16983 } // namespace internal | 16733 } // namespace internal |
16984 } // namespace v8 | 16734 } // namespace v8 |
OLD | NEW |