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()) { |
Igor Sheludko
2015/06/11 13:44:25
IsExecutableAccessorInfo()?
Toon Verwaest
2015/06/11 14:26:50
It's in a weird state since it's the only subclass
| |
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 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3123 JSObject::GetPropertyAttributesWithInterceptor(it); | 3067 JSObject::GetPropertyAttributesWithInterceptor(it); |
3124 if (!maybe_attributes.IsJust()) return MaybeHandle<Object>(); | 3068 if (!maybe_attributes.IsJust()) return MaybeHandle<Object>(); |
3125 done = maybe_attributes.FromJust() != ABSENT; | 3069 done = maybe_attributes.FromJust() != ABSENT; |
3126 if (done && (maybe_attributes.FromJust() & READ_ONLY) != 0) { | 3070 if (done && (maybe_attributes.FromJust() & READ_ONLY) != 0) { |
3127 return WriteToReadOnlyProperty(it, value, language_mode); | 3071 return WriteToReadOnlyProperty(it, value, language_mode); |
3128 } | 3072 } |
3129 } | 3073 } |
3130 break; | 3074 break; |
3131 | 3075 |
3132 case LookupIterator::ACCESSOR: { | 3076 case LookupIterator::ACCESSOR: { |
3133 if (it->property_details().IsReadOnly()) { | 3077 if (it->IsReadOnly()) { |
3134 return WriteToReadOnlyProperty(it, value, language_mode); | 3078 return WriteToReadOnlyProperty(it, value, language_mode); |
3135 } | 3079 } |
3136 Handle<Object> accessors = it->GetAccessors(); | 3080 Handle<Object> accessors = it->GetAccessors(); |
3137 if (accessors->IsAccessorInfo() && | 3081 if (accessors->IsAccessorInfo() && |
3138 !it->HolderIsReceiverOrHiddenPrototype() && | 3082 !it->HolderIsReceiverOrHiddenPrototype() && |
3139 AccessorInfo::cast(*accessors)->is_special_data_property()) { | 3083 AccessorInfo::cast(*accessors)->is_special_data_property()) { |
3140 done = true; | 3084 done = true; |
3141 break; | 3085 break; |
3142 } | 3086 } |
3143 return SetPropertyWithAccessor(it->GetReceiver(), it->GetName(), value, | 3087 return SetPropertyWithAccessor(it, value, language_mode); |
3144 it->GetHolder<JSObject>(), accessors, | |
3145 language_mode); | |
3146 } | 3088 } |
3147 case LookupIterator::INTEGER_INDEXED_EXOTIC: | 3089 case LookupIterator::INTEGER_INDEXED_EXOTIC: |
3148 done = true; | 3090 done = true; |
3149 break; | 3091 break; |
3150 | 3092 |
3151 case LookupIterator::DATA: | 3093 case LookupIterator::DATA: |
3152 if (it->property_details().IsReadOnly()) { | 3094 if (it->IsReadOnly()) { |
3153 return WriteToReadOnlyProperty(it, value, language_mode); | 3095 return WriteToReadOnlyProperty(it, value, language_mode); |
3154 } | 3096 } |
3155 if (it->HolderIsReceiverOrHiddenPrototype()) { | 3097 if (it->HolderIsReceiverOrHiddenPrototype()) { |
3156 return SetDataProperty(it, value); | 3098 return SetDataProperty(it, value); |
3157 } | 3099 } |
3158 done = true; | 3100 done = true; |
3159 break; | 3101 break; |
3160 | 3102 |
3161 case LookupIterator::TRANSITION: | 3103 case LookupIterator::TRANSITION: |
3162 done = true; | 3104 done = true; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3195 MaybeHandle<Object> Object::SetSuperProperty(LookupIterator* it, | 3137 MaybeHandle<Object> Object::SetSuperProperty(LookupIterator* it, |
3196 Handle<Object> value, | 3138 Handle<Object> value, |
3197 LanguageMode language_mode, | 3139 LanguageMode language_mode, |
3198 StoreFromKeyed store_mode) { | 3140 StoreFromKeyed store_mode) { |
3199 bool found = false; | 3141 bool found = false; |
3200 MaybeHandle<Object> result = | 3142 MaybeHandle<Object> result = |
3201 SetPropertyInternal(it, value, language_mode, store_mode, &found); | 3143 SetPropertyInternal(it, value, language_mode, store_mode, &found); |
3202 if (found) return result; | 3144 if (found) return result; |
3203 | 3145 |
3204 if (!it->GetReceiver()->IsJSReceiver()) { | 3146 if (!it->GetReceiver()->IsJSReceiver()) { |
3205 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), it->name(), | 3147 return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), |
3206 value, language_mode); | 3148 it->GetName(), value, language_mode); |
3207 } | 3149 } |
3208 | 3150 |
3209 LookupIterator own_lookup(it->GetReceiver(), it->name(), LookupIterator::OWN); | 3151 LookupIterator::Configuration c = LookupIterator::OWN; |
3152 LookupIterator own_lookup = | |
3153 it->IsElement() | |
3154 ? LookupIterator(it->isolate(), it->GetReceiver(), it->index(), c) | |
3155 : LookupIterator(it->GetReceiver(), it->name(), c); | |
3210 | 3156 |
3211 switch (own_lookup.state()) { | 3157 for (; own_lookup.IsFound(); own_lookup.Next()) { |
3212 case LookupIterator::NOT_FOUND: | 3158 switch (own_lookup.state()) { |
3213 return JSObject::AddDataProperty(&own_lookup, value, NONE, language_mode, | 3159 case LookupIterator::ACCESS_CHECK: |
3214 store_mode); | 3160 if (!it->isolate()->MayAccess(own_lookup.GetHolder<JSObject>())) { |
3161 return JSObject::SetPropertyWithFailedAccessCheck(&own_lookup, value, | |
3162 language_mode); | |
3163 } | |
3164 break; | |
3215 | 3165 |
3216 case LookupIterator::INTEGER_INDEXED_EXOTIC: | 3166 case LookupIterator::INTEGER_INDEXED_EXOTIC: |
3217 return result; | 3167 return result; |
3218 | 3168 |
3219 case LookupIterator::DATA: { | 3169 case LookupIterator::DATA: { |
3220 PropertyDetails details = own_lookup.property_details(); | 3170 PropertyDetails details = own_lookup.property_details(); |
3221 if (details.IsConfigurable() || !details.IsReadOnly()) { | 3171 if (details.IsConfigurable() || !details.IsReadOnly()) { |
3222 return JSObject::SetOwnPropertyIgnoreAttributes( | 3172 return JSObject::ReconfigureAsDataProperty(&own_lookup, value, |
3223 Handle<JSObject>::cast(it->GetReceiver()), it->name(), value, | 3173 details.attributes()); |
3224 details.attributes()); | 3174 } |
3225 } | 3175 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 } | 3176 } |
3236 | 3177 |
3237 return RedefineNonconfigurableProperty(it->isolate(), it->name(), value, | 3178 case LookupIterator::ACCESSOR: { |
3238 language_mode); | 3179 PropertyDetails details = own_lookup.property_details(); |
3239 } | 3180 if (details.IsConfigurable()) { |
3181 return JSObject::ReconfigureAsDataProperty(&own_lookup, value, | |
3182 details.attributes()); | |
3183 } | |
3240 | 3184 |
3241 case LookupIterator::TRANSITION: | 3185 return RedefineNonconfigurableProperty(it->isolate(), it->GetName(), |
3242 UNREACHABLE(); | 3186 value, language_mode); |
3243 break; | 3187 } |
3244 | 3188 |
3245 case LookupIterator::INTERCEPTOR: | 3189 case LookupIterator::INTERCEPTOR: |
3246 case LookupIterator::JSPROXY: | 3190 case LookupIterator::JSPROXY: { |
3247 case LookupIterator::ACCESS_CHECK: { | 3191 bool found = false; |
3248 bool found = false; | 3192 MaybeHandle<Object> result = SetPropertyInternal( |
3249 MaybeHandle<Object> result = SetPropertyInternal( | 3193 &own_lookup, value, language_mode, store_mode, &found); |
3250 &own_lookup, value, language_mode, store_mode, &found); | 3194 if (found) return result; |
Igor Sheludko
2015/06/11 13:44:25
Missing break; ?
Toon Verwaest
2015/06/11 14:26:50
Done.
| |
3251 if (found) return result; | 3195 } |
3252 return SetDataProperty(&own_lookup, value); | 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()) { |
Igor Sheludko
2015/06/11 13:44:25
You dropped CheckArrayAbuse() calls. Was it done i
Toon Verwaest
2015/06/11 14:26:50
Done.
| |
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 | |
3373 return JSObject::AddDataElement(receiver, it->index(), value, attributes); | |
3374 } else { | |
3375 // Migrate to the most up-to-date map that will be able to store |value| | |
3376 // under it->name() with |attributes|. | |
3377 it->PrepareTransitionToDataProperty(value, attributes, store_mode); | |
3378 DCHECK_EQ(LookupIterator::TRANSITION, it->state()); | |
3379 it->ApplyTransitionToDataProperty(); | |
3380 | |
3381 // TODO(verwaest): Encapsulate dictionary handling better. | |
3382 if (receiver->map()->is_dictionary_map()) { | |
3383 // TODO(verwaest): Probably should ensure this is done beforehand. | |
3384 it->InternalizeName(); | |
3385 // TODO(dcarney): just populate TransitionPropertyCell here? | |
3386 JSObject::AddSlowProperty(receiver, it->name(), value, attributes); | |
3387 } else { | |
3388 // Write the property value. | |
3389 it->WriteDataValue(value); | |
3390 } | |
3391 | |
3392 // Send the change record if there are observers. | |
3393 if (receiver->map()->is_observed() && | |
3394 !isolate->IsInternallyUsedPropertyName(it->name())) { | |
3395 RETURN_ON_EXCEPTION(isolate, JSObject::EnqueueChangeRecord( | |
3396 receiver, "add", it->name(), | |
3397 it->factory()->the_hole_value()), | |
3398 Object); | |
3399 } | |
3385 } | 3400 } |
3386 | 3401 |
3387 return value; | 3402 return value; |
3388 } | 3403 } |
3389 | 3404 |
3390 | 3405 |
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) { | 3406 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { |
3437 // Only supports adding slack to owned descriptors. | 3407 // Only supports adding slack to owned descriptors. |
3438 DCHECK(map->owns_descriptors()); | 3408 DCHECK(map->owns_descriptors()); |
3439 | 3409 |
3440 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | 3410 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
3441 int old_size = map->NumberOfOwnDescriptors(); | 3411 int old_size = map->NumberOfOwnDescriptors(); |
3442 if (slack <= descriptors->NumberOfSlackDescriptors()) return; | 3412 if (slack <= descriptors->NumberOfSlackDescriptors()) return; |
3443 | 3413 |
3444 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( | 3414 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo( |
3445 descriptors, old_size, slack); | 3415 descriptors, old_size, slack); |
(...skipping 691 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4137 DCHECK(maybe.IsJust()); | 4107 DCHECK(maybe.IsJust()); |
4138 DCHECK(!it.IsFound()); | 4108 DCHECK(!it.IsFound()); |
4139 DCHECK(object->map()->is_extensible() || | 4109 DCHECK(object->map()->is_extensible() || |
4140 it.isolate()->IsInternallyUsedPropertyName(name)); | 4110 it.isolate()->IsInternallyUsedPropertyName(name)); |
4141 #endif | 4111 #endif |
4142 AddDataProperty(&it, value, attributes, STRICT, | 4112 AddDataProperty(&it, value, attributes, STRICT, |
4143 CERTAINLY_NOT_STORE_FROM_KEYED).Check(); | 4113 CERTAINLY_NOT_STORE_FROM_KEYED).Check(); |
4144 } | 4114 } |
4145 | 4115 |
4146 | 4116 |
4117 // static | |
4118 void ExecutableAccessorInfo::ClearSetter(Handle<ExecutableAccessorInfo> info) { | |
4119 info->set_setter(*v8::FromCData(info->GetIsolate(), nullptr)); | |
4120 } | |
4121 | |
4122 | |
4123 MaybeHandle<Object> JSObject::ReconfigureAsDataProperty( | |
4124 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes) { | |
4125 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); | |
4126 bool is_observed = object->map()->is_observed() && | |
4127 (it->IsElement() || | |
4128 !it->isolate()->IsInternallyUsedPropertyName(it->name())); | |
4129 | |
4130 switch (it->state()) { | |
4131 case LookupIterator::INTERCEPTOR: | |
4132 case LookupIterator::JSPROXY: | |
4133 case LookupIterator::NOT_FOUND: | |
4134 case LookupIterator::TRANSITION: | |
4135 case LookupIterator::ACCESS_CHECK: | |
4136 UNREACHABLE(); | |
4137 | |
4138 case LookupIterator::INTEGER_INDEXED_EXOTIC: | |
4139 return value; | |
4140 | |
4141 case LookupIterator::ACCESSOR: { | |
4142 PropertyDetails details = it->property_details(); | |
4143 // Ensure the context isn't changed after calling into accessors. | |
4144 AssertNoContextChange ncc(it->isolate()); | |
4145 | |
4146 Handle<Object> accessors = it->GetAccessors(); | |
4147 | |
4148 // Special handling for ExecutableAccessorInfo, which behaves like a | |
4149 // data property. | |
4150 if (accessors->IsExecutableAccessorInfo()) { | |
4151 Handle<Object> result; | |
4152 ASSIGN_RETURN_ON_EXCEPTION( | |
4153 it->isolate(), result, | |
4154 JSObject::SetPropertyWithAccessor(it, value, STRICT), Object); | |
4155 DCHECK(result->SameValue(*value)); | |
4156 | |
4157 if (details.attributes() == attributes) return value; | |
4158 | |
4159 // Reconfigure the accessor if attributes mismatch. | |
4160 Handle<ExecutableAccessorInfo> new_data = Accessors::CloneAccessor( | |
4161 it->isolate(), Handle<ExecutableAccessorInfo>::cast(accessors)); | |
4162 new_data->set_property_attributes(attributes); | |
4163 // By clearing the setter we don't have to introduce a lookup to | |
4164 // the setter, simply make it unavailable to reflect the | |
4165 // attributes. | |
4166 if (attributes & READ_ONLY) { | |
4167 ExecutableAccessorInfo::ClearSetter(new_data); | |
4168 } | |
4169 | |
4170 if (it->IsElement()) { | |
4171 SetElementCallback(object, it->index(), new_data, attributes); | |
4172 } else { | |
4173 SetPropertyCallback(object, it->name(), new_data, attributes); | |
4174 } | |
4175 if (is_observed) { | |
4176 RETURN_ON_EXCEPTION( | |
4177 it->isolate(), | |
4178 EnqueueChangeRecord(object, "reconfigure", it->GetName(), | |
4179 it->factory()->the_hole_value()), | |
4180 Object); | |
4181 } | |
4182 return value; | |
4183 } | |
4184 | |
4185 it->ReconfigureDataProperty(value, attributes); | |
4186 it->WriteDataValue(value); | |
4187 | |
4188 if (is_observed) { | |
4189 RETURN_ON_EXCEPTION( | |
4190 it->isolate(), | |
4191 EnqueueChangeRecord(object, "reconfigure", it->GetName(), | |
4192 it->factory()->the_hole_value()), | |
4193 Object); | |
4194 } | |
4195 | |
4196 return value; | |
4197 } | |
4198 | |
4199 case LookupIterator::DATA: { | |
4200 PropertyDetails details = it->property_details(); | |
4201 Handle<Object> old_value = it->factory()->the_hole_value(); | |
4202 // Regular property update if the attributes match. | |
4203 if (details.attributes() == attributes) { | |
4204 return SetDataProperty(it, value); | |
4205 } | |
4206 | |
4207 // Special case: properties of typed arrays cannot be reconfigured to | |
4208 // non-writable nor to non-enumerable. | |
4209 if (it->IsElement() && (object->HasExternalArrayElements() || | |
4210 object->HasFixedTypedArrayElements())) { | |
4211 return RedefineNonconfigurableProperty(it->isolate(), it->GetName(), | |
4212 value, STRICT); | |
4213 } | |
4214 | |
4215 // Reconfigure the data property if the attributes mismatch. | |
4216 if (is_observed) old_value = it->GetDataValue(); | |
4217 | |
4218 it->ReconfigureDataProperty(value, attributes); | |
4219 it->WriteDataValue(value); | |
4220 | |
4221 if (is_observed) { | |
4222 if (old_value->SameValue(*value)) { | |
4223 old_value = it->factory()->the_hole_value(); | |
4224 } | |
4225 RETURN_ON_EXCEPTION(it->isolate(), | |
4226 EnqueueChangeRecord(object, "reconfigure", | |
4227 it->GetName(), old_value), | |
4228 Object); | |
4229 } | |
4230 } | |
4231 } | |
4232 | |
4233 return value; | |
4234 } | |
4235 | |
4236 | |
4147 // Reconfigures a property to a data property with attributes, even if it is not | 4237 // Reconfigures a property to a data property with attributes, even if it is not |
4148 // reconfigurable. | 4238 // reconfigurable. |
4149 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes( | 4239 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes( |
4150 Handle<JSObject> object, | 4240 Handle<JSObject> object, Handle<Name> name, Handle<Object> value, |
4151 Handle<Name> name, | 4241 PropertyAttributes attributes) { |
4152 Handle<Object> value, | |
4153 PropertyAttributes attributes, | |
4154 ExecutableAccessorInfoHandling handling) { | |
4155 DCHECK(!value->IsTheHole()); | 4242 DCHECK(!value->IsTheHole()); |
4156 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); | 4243 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); |
4157 bool is_observed = object->map()->is_observed() && | 4244 if (it.state() == LookupIterator::ACCESS_CHECK) { |
4158 !it.isolate()->IsInternallyUsedPropertyName(name); | 4245 if (!it.isolate()->MayAccess(object)) { |
4159 for (; it.IsFound(); it.Next()) { | 4246 // TODO(verwaest): Check whether this makes sense. |
4160 switch (it.state()) { | 4247 return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY); |
4161 case LookupIterator::INTEGER_INDEXED_EXOTIC: | 4248 } |
4162 return value; | 4249 it.Next(); |
4250 } | |
4163 | 4251 |
4164 case LookupIterator::INTERCEPTOR: | 4252 if (it.IsFound()) { |
4165 case LookupIterator::JSPROXY: | 4253 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 } | 4254 } |
4262 | 4255 |
4263 return AddDataProperty(&it, value, attributes, STRICT, | 4256 return AddDataProperty(&it, value, attributes, STRICT, |
4264 CERTAINLY_NOT_STORE_FROM_KEYED); | 4257 CERTAINLY_NOT_STORE_FROM_KEYED); |
4265 } | 4258 } |
4266 | 4259 |
4267 | 4260 |
4261 MaybeHandle<Object> JSObject::SetOwnElementIgnoreAttributes( | |
4262 Handle<JSObject> object, uint32_t index, Handle<Object> value, | |
4263 PropertyAttributes attributes) { | |
4264 DCHECK(!object->HasExternalArrayElements()); | |
4265 Isolate* isolate = object->GetIsolate(); | |
4266 LookupIterator it(isolate, object, index, | |
4267 LookupIterator::OWN_SKIP_INTERCEPTOR); | |
4268 if (it.state() == LookupIterator::ACCESS_CHECK) { | |
4269 if (!isolate->MayAccess(object)) { | |
4270 // TODO(verwaest): Check whether this makes sense. | |
4271 return SetPropertyWithFailedAccessCheck(&it, value, STRICT); | |
4272 } | |
4273 it.Next(); | |
4274 } | |
4275 | |
4276 if (it.IsFound()) { | |
4277 return ReconfigureAsDataProperty(&it, value, attributes); | |
4278 } | |
4279 | |
4280 return AddDataProperty(&it, value, attributes, STRICT, | |
4281 MAY_BE_STORE_FROM_KEYED); | |
4282 } | |
4283 | |
4284 | |
4268 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( | 4285 Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( |
4269 LookupIterator* it) { | 4286 LookupIterator* it) { |
4270 Isolate* isolate = it->isolate(); | 4287 Isolate* isolate = it->isolate(); |
4271 // Make sure that the top context does not change when doing | 4288 // Make sure that the top context does not change when doing |
4272 // callbacks or interceptor calls. | 4289 // callbacks or interceptor calls. |
4273 AssertNoContextChange ncc(isolate); | 4290 AssertNoContextChange ncc(isolate); |
4274 HandleScope scope(isolate); | 4291 HandleScope scope(isolate); |
4275 | 4292 |
4276 Handle<JSObject> holder = it->GetHolder<JSObject>(); | 4293 Handle<JSObject> holder = it->GetHolder<JSObject>(); |
4277 Handle<InterceptorInfo> interceptor(it->GetInterceptor()); | 4294 Handle<InterceptorInfo> interceptor(it->GetInterceptor()); |
(...skipping 2869 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7147 case ACCESSOR: | 7164 case ACCESSOR: |
7148 case ACCESSOR_CONSTANT: | 7165 case ACCESSOR_CONSTANT: |
7149 return false; | 7166 return false; |
7150 } | 7167 } |
7151 | 7168 |
7152 UNREACHABLE(); | 7169 UNREACHABLE(); |
7153 return false; | 7170 return false; |
7154 } | 7171 } |
7155 | 7172 |
7156 | 7173 |
7174 // static | |
7175 Handle<Map> Map::PrepareForDataElement(Handle<Map> map, Handle<Object> value) { | |
7176 ElementsKind kind = map->elements_kind(); | |
7177 bool holey = IsHoleyElementsKind(kind); | |
7178 | |
7179 switch (kind) { | |
7180 case FAST_SMI_ELEMENTS: | |
7181 case FAST_HOLEY_SMI_ELEMENTS: | |
7182 if (value->IsSmi()) return map; | |
7183 kind = value->IsNumber() ? FAST_DOUBLE_ELEMENTS : FAST_ELEMENTS; | |
7184 break; | |
7185 | |
7186 case FAST_DOUBLE_ELEMENTS: | |
7187 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
7188 if (value->IsNumber()) return map; | |
7189 kind = FAST_ELEMENTS; | |
7190 break; | |
7191 | |
7192 case FAST_ELEMENTS: | |
7193 case FAST_HOLEY_ELEMENTS: | |
7194 case DICTIONARY_ELEMENTS: | |
7195 case SLOPPY_ARGUMENTS_ELEMENTS: | |
7196 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | |
7197 case EXTERNAL_##TYPE##_ELEMENTS: \ | |
7198 case TYPE##_ELEMENTS: | |
7199 | |
7200 TYPED_ARRAYS(TYPED_ARRAY_CASE) | |
7201 #undef TYPED_ARRAY_CASE | |
7202 return map; | |
7203 } | |
7204 | |
7205 if (holey) kind = GetHoleyElementsKind(kind); | |
7206 return Map::AsElementsKind(map, kind); | |
7207 } | |
7208 | |
7209 | |
7210 // static | |
7157 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor, | 7211 Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor, |
7158 Handle<Object> value) { | 7212 Handle<Object> value) { |
7159 // Dictionaries can store any property value. | 7213 // Dictionaries can store any property value. |
7160 if (map->is_dictionary_map()) return map; | 7214 if (map->is_dictionary_map()) return map; |
7161 | 7215 |
7162 // Migrate to the newest map before storing the property. | 7216 // Migrate to the newest map before storing the property. |
7163 map = Update(map); | 7217 map = Update(map); |
7164 | 7218 |
7165 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | 7219 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
7166 | 7220 |
(...skipping 4721 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
11888 if (!JSObject::GetOwnElementAccessorPair(object, index).is_null()) { | 11942 if (!JSObject::GetOwnElementAccessorPair(object, index).is_null()) { |
11889 value = Handle<Object>::cast(isolate->factory()->the_hole_value()); | 11943 value = Handle<Object>::cast(isolate->factory()->the_hole_value()); |
11890 } else { | 11944 } else { |
11891 value = Object::GetElement(isolate, object, index).ToHandleChecked(); | 11945 value = Object::GetElement(isolate, object, index).ToHandleChecked(); |
11892 } | 11946 } |
11893 old_values->Add(value); | 11947 old_values->Add(value); |
11894 indices->Add(index); | 11948 indices->Add(index); |
11895 return true; | 11949 return true; |
11896 } | 11950 } |
11897 | 11951 |
11898 MUST_USE_RESULT static MaybeHandle<Object> EnqueueSpliceRecord( | |
11899 Handle<JSArray> object, uint32_t index, Handle<JSArray> deleted, | |
11900 uint32_t add_count) { | |
11901 Isolate* isolate = object->GetIsolate(); | |
11902 HandleScope scope(isolate); | |
11903 Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index); | |
11904 Handle<Object> add_count_object = | |
11905 isolate->factory()->NewNumberFromUint(add_count); | |
11906 | |
11907 Handle<Object> args[] = | |
11908 { object, index_object, deleted, add_count_object }; | |
11909 | |
11910 return Execution::Call( | |
11911 isolate, Handle<JSFunction>(isolate->observers_enqueue_splice()), | |
11912 isolate->factory()->undefined_value(), arraysize(args), args); | |
11913 } | |
11914 | |
11915 | |
11916 MUST_USE_RESULT static MaybeHandle<Object> BeginPerformSplice( | |
11917 Handle<JSArray> object) { | |
11918 Isolate* isolate = object->GetIsolate(); | |
11919 HandleScope scope(isolate); | |
11920 Handle<Object> args[] = { object }; | |
11921 | |
11922 return Execution::Call( | |
11923 isolate, Handle<JSFunction>(isolate->observers_begin_perform_splice()), | |
11924 isolate->factory()->undefined_value(), arraysize(args), args); | |
11925 } | |
11926 | |
11927 | |
11928 MUST_USE_RESULT static MaybeHandle<Object> EndPerformSplice( | |
11929 Handle<JSArray> object) { | |
11930 Isolate* isolate = object->GetIsolate(); | |
11931 HandleScope scope(isolate); | |
11932 Handle<Object> args[] = { object }; | |
11933 | |
11934 return Execution::Call( | |
11935 isolate, Handle<JSFunction>(isolate->observers_end_perform_splice()), | |
11936 isolate->factory()->undefined_value(), arraysize(args), args); | |
11937 } | |
11938 | |
11939 | |
11940 MaybeHandle<Object> JSArray::SetElementsLength( | 11952 MaybeHandle<Object> JSArray::SetElementsLength( |
11941 Handle<JSArray> array, | 11953 Handle<JSArray> array, |
11942 Handle<Object> new_length_handle) { | 11954 Handle<Object> new_length_handle) { |
11943 if (array->HasFastElements() && | 11955 if (array->HasFastElements() && |
11944 SetElementsLengthWouldNormalize(array->GetHeap(), new_length_handle)) { | 11956 SetElementsLengthWouldNormalize(array->GetHeap(), new_length_handle)) { |
11945 NormalizeElements(array); | 11957 NormalizeElements(array); |
11946 } | 11958 } |
11947 | 11959 |
11948 // We should never end in here with a pixel or external array. | 11960 // We should never end in here with a pixel or external array. |
11949 DCHECK(array->AllowsSetElementsLength()); | 11961 DCHECK(array->AllowsSetElementsLength()); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12014 | 12026 |
12015 uint32_t index = Min(old_length, new_length); | 12027 uint32_t index = Min(old_length, new_length); |
12016 uint32_t add_count = new_length > old_length ? new_length - old_length : 0; | 12028 uint32_t add_count = new_length > old_length ? new_length - old_length : 0; |
12017 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0; | 12029 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0; |
12018 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0); | 12030 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0); |
12019 if (delete_count > 0) { | 12031 if (delete_count > 0) { |
12020 for (int i = indices.length() - 1; i >= 0; i--) { | 12032 for (int i = indices.length() - 1; i >= 0; i--) { |
12021 // Skip deletions where the property was an accessor, leaving holes | 12033 // Skip deletions where the property was an accessor, leaving holes |
12022 // in the array of old values. | 12034 // in the array of old values. |
12023 if (old_values[i]->IsTheHole()) continue; | 12035 if (old_values[i]->IsTheHole()) continue; |
12024 JSObject::SetOwnElement(deleted, indices[i] - index, old_values[i], | 12036 JSObject::AddDataElement(deleted, indices[i] - index, old_values[i], NONE) |
12025 SLOPPY).Assert(); | 12037 .Assert(); |
12026 } | 12038 } |
12027 | 12039 |
12028 RETURN_ON_EXCEPTION( | 12040 SetProperty(deleted, isolate->factory()->length_string(), |
12029 isolate, | 12041 isolate->factory()->NewNumberFromUint(delete_count), |
12030 SetProperty(deleted, isolate->factory()->length_string(), | 12042 STRICT).Assert(); |
12031 isolate->factory()->NewNumberFromUint(delete_count), | |
12032 STRICT), | |
12033 Object); | |
12034 } | 12043 } |
12035 | 12044 |
12036 RETURN_ON_EXCEPTION( | 12045 RETURN_ON_EXCEPTION( |
12037 isolate, EnqueueSpliceRecord(array, index, deleted, add_count), Object); | 12046 isolate, EnqueueSpliceRecord(array, index, deleted, add_count), Object); |
12038 | 12047 |
12039 return hresult; | 12048 return hresult; |
12040 } | 12049 } |
12041 | 12050 |
12042 | 12051 |
12043 // static | 12052 // static |
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12448 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index); | 12457 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index); |
12449 } | 12458 } |
12450 | 12459 |
12451 // Check for lookup interceptor. | 12460 // Check for lookup interceptor. |
12452 if (object->HasIndexedInterceptor()) return MaybeHandle<AccessorPair>(); | 12461 if (object->HasIndexedInterceptor()) return MaybeHandle<AccessorPair>(); |
12453 | 12462 |
12454 return object->GetElementsAccessor()->GetAccessorPair(object, index); | 12463 return object->GetElementsAccessor()->GetAccessorPair(object, index); |
12455 } | 12464 } |
12456 | 12465 |
12457 | 12466 |
12458 MaybeHandle<Object> JSObject::SetElementWithInterceptor( | |
12459 Handle<JSObject> object, uint32_t index, Handle<Object> value, | |
12460 PropertyAttributes attributes, LanguageMode language_mode, | |
12461 bool check_prototype, SetPropertyMode set_mode) { | |
12462 Isolate* isolate = object->GetIsolate(); | |
12463 | |
12464 // Make sure that the top context does not change when doing | |
12465 // callbacks or interceptor calls. | |
12466 AssertNoContextChange ncc(isolate); | |
12467 | |
12468 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor()); | |
12469 if (!interceptor->setter()->IsUndefined()) { | |
12470 v8::IndexedPropertySetterCallback setter = | |
12471 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter()); | |
12472 LOG(isolate, | |
12473 ApiIndexedPropertyAccess("interceptor-indexed-set", *object, index)); | |
12474 PropertyCallbackArguments args(isolate, interceptor->data(), *object, | |
12475 *object); | |
12476 v8::Handle<v8::Value> result = | |
12477 args.Call(setter, index, v8::Utils::ToLocal(value)); | |
12478 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
12479 if (!result.IsEmpty()) return value; | |
12480 } | |
12481 | |
12482 return SetElementWithoutInterceptor(object, index, value, attributes, | |
12483 language_mode, check_prototype, set_mode); | |
12484 } | |
12485 | |
12486 | |
12487 MaybeHandle<Object> JSObject::SetElementWithCallback( | |
12488 Handle<Object> object, Handle<Object> structure, uint32_t index, | |
12489 Handle<Object> value, Handle<JSObject> holder, LanguageMode language_mode) { | |
12490 Isolate* isolate = holder->GetIsolate(); | |
12491 | |
12492 // We should never get here to initialize a const with the hole | |
12493 // value since a const declaration would conflict with the setter. | |
12494 DCHECK(!value->IsTheHole()); | |
12495 DCHECK(!structure->IsForeign()); | |
12496 if (structure->IsExecutableAccessorInfo()) { | |
12497 // api style callbacks | |
12498 Handle<ExecutableAccessorInfo> data = | |
12499 Handle<ExecutableAccessorInfo>::cast(structure); | |
12500 Object* call_obj = data->setter(); | |
12501 v8::AccessorNameSetterCallback call_fun = | |
12502 v8::ToCData<v8::AccessorNameSetterCallback>(call_obj); | |
12503 if (call_fun == NULL) return value; | |
12504 Handle<String> key(isolate->factory()->Uint32ToString(index)); | |
12505 LOG(isolate, ApiNamedPropertyAccess("store", *holder, *key)); | |
12506 PropertyCallbackArguments | |
12507 args(isolate, data->data(), *object, *holder); | |
12508 args.Call(call_fun, | |
12509 v8::Utils::ToLocal(key), | |
12510 v8::Utils::ToLocal(value)); | |
12511 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
12512 return value; | |
12513 } | |
12514 | |
12515 if (structure->IsAccessorPair()) { | |
12516 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate); | |
12517 if (setter->IsSpecFunction()) { | |
12518 // TODO(rossberg): nicer would be to cast to some JSCallable here... | |
12519 return SetPropertyWithDefinedSetter( | |
12520 object, Handle<JSReceiver>::cast(setter), value); | |
12521 } else { | |
12522 if (is_sloppy(language_mode)) return value; | |
12523 Handle<Object> key(isolate->factory()->NewNumberFromUint(index)); | |
12524 THROW_NEW_ERROR( | |
12525 isolate, | |
12526 NewTypeError(MessageTemplate::kNoSetterInCallback, key, holder), | |
12527 Object); | |
12528 } | |
12529 } | |
12530 | |
12531 UNREACHABLE(); | |
12532 return MaybeHandle<Object>(); | |
12533 } | |
12534 | |
12535 | |
12536 bool JSObject::HasFastArgumentsElements() { | 12467 bool JSObject::HasFastArgumentsElements() { |
12537 Heap* heap = GetHeap(); | 12468 Heap* heap = GetHeap(); |
12538 if (!elements()->IsFixedArray()) return false; | 12469 if (!elements()->IsFixedArray()) return false; |
12539 FixedArray* elements = FixedArray::cast(this->elements()); | 12470 FixedArray* elements = FixedArray::cast(this->elements()); |
12540 if (elements->map() != heap->sloppy_arguments_elements_map()) { | 12471 if (elements->map() != heap->sloppy_arguments_elements_map()) { |
12541 return false; | 12472 return false; |
12542 } | 12473 } |
12543 FixedArray* arguments = FixedArray::cast(elements->get(1)); | 12474 FixedArray* arguments = FixedArray::cast(elements->get(1)); |
12544 return !arguments->IsDictionary(); | 12475 return !arguments->IsDictionary(); |
12545 } | 12476 } |
12546 | 12477 |
12547 | 12478 |
12548 bool JSObject::HasDictionaryArgumentsElements() { | 12479 bool JSObject::HasDictionaryArgumentsElements() { |
12549 Heap* heap = GetHeap(); | 12480 Heap* heap = GetHeap(); |
12550 if (!elements()->IsFixedArray()) return false; | 12481 if (!elements()->IsFixedArray()) return false; |
12551 FixedArray* elements = FixedArray::cast(this->elements()); | 12482 FixedArray* elements = FixedArray::cast(this->elements()); |
12552 if (elements->map() != heap->sloppy_arguments_elements_map()) { | 12483 if (elements->map() != heap->sloppy_arguments_elements_map()) { |
12553 return false; | 12484 return false; |
12554 } | 12485 } |
12555 FixedArray* arguments = FixedArray::cast(elements->get(1)); | 12486 FixedArray* arguments = FixedArray::cast(elements->get(1)); |
12556 return arguments->IsDictionary(); | 12487 return arguments->IsDictionary(); |
12557 } | 12488 } |
12558 | 12489 |
12559 | 12490 |
12560 // Adding n elements in fast case is O(n*n). | 12491 void JSObject::SetFastElement(Handle<JSObject> object, uint32_t index, |
12561 // Note: revisit design to have dual undefined values to capture absent | 12492 Handle<Object> value) { |
12562 // elements. | |
12563 MaybeHandle<Object> JSObject::SetFastElement(Handle<JSObject> object, | |
12564 uint32_t index, | |
12565 Handle<Object> value, | |
12566 LanguageMode language_mode, | |
12567 bool check_prototype) { | |
12568 DCHECK(object->HasFastSmiOrObjectElements() || | 12493 DCHECK(object->HasFastSmiOrObjectElements() || |
12569 object->HasFastArgumentsElements()); | 12494 object->HasFastArgumentsElements()); |
12570 | 12495 |
12571 Isolate* isolate = object->GetIsolate(); | 12496 Isolate* isolate = object->GetIsolate(); |
12572 | 12497 |
12573 // Array optimizations rely on the prototype lookups of Array objects always | 12498 // Array optimizations rely on the prototype lookups of Array objects always |
12574 // returning undefined. If there is a store to the initial prototype object, | 12499 // returning undefined. If there is a store to the initial prototype object, |
12575 // make sure all of these optimizations are invalidated. | 12500 // make sure all of these optimizations are invalidated. |
12576 isolate->UpdateArrayProtectorOnSetElement(object); | 12501 isolate->UpdateArrayProtectorOnSetElement(object); |
12577 | 12502 |
12578 Handle<FixedArray> backing_store(FixedArray::cast(object->elements())); | 12503 Handle<FixedArray> backing_store(FixedArray::cast(object->elements())); |
12579 if (backing_store->map() == | 12504 if (object->HasSloppyArgumentsElements()) { |
12580 isolate->heap()->sloppy_arguments_elements_map()) { | |
12581 backing_store = handle(FixedArray::cast(backing_store->get(1))); | 12505 backing_store = handle(FixedArray::cast(backing_store->get(1))); |
12582 } else { | 12506 } else { |
12583 backing_store = EnsureWritableFastElements(object); | 12507 backing_store = EnsureWritableFastElements(object); |
12584 } | 12508 } |
12585 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); | 12509 uint32_t capacity = static_cast<uint32_t>(backing_store->length()); |
12586 | 12510 |
12587 if (check_prototype && | |
12588 (index >= capacity || backing_store->get(index)->IsTheHole())) { | |
12589 bool found; | |
12590 MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes( | |
12591 object, index, value, &found, language_mode); | |
12592 if (found) return result; | |
12593 } | |
12594 | |
12595 uint32_t new_capacity = capacity; | 12511 uint32_t new_capacity = capacity; |
12596 // Check if the length property of this object needs to be updated. | 12512 // Check if the length property of this object needs to be updated. |
12597 uint32_t array_length = 0; | 12513 uint32_t array_length = 0; |
12598 bool must_update_array_length = false; | 12514 bool must_update_array_length = false; |
12599 bool introduces_holes = true; | 12515 bool introduces_holes = true; |
12600 if (object->IsJSArray()) { | 12516 if (object->IsJSArray()) { |
12601 CHECK( | 12517 CHECK( |
12602 Handle<JSArray>::cast(object)->length()->ToArrayLength(&array_length)); | 12518 Handle<JSArray>::cast(object)->length()->ToArrayLength(&array_length)); |
12603 introduces_holes = index > array_length; | 12519 introduces_holes = index > array_length; |
12604 if (index >= array_length) { | 12520 if (index >= array_length) { |
(...skipping 20 matching lines...) Expand all Loading... | |
12625 bool convert_to_slow = true; | 12541 bool convert_to_slow = true; |
12626 if ((index - capacity) < kMaxGap) { | 12542 if ((index - capacity) < kMaxGap) { |
12627 new_capacity = NewElementsCapacity(index + 1); | 12543 new_capacity = NewElementsCapacity(index + 1); |
12628 DCHECK(new_capacity > index); | 12544 DCHECK(new_capacity > index); |
12629 if (!object->ShouldConvertToSlowElements(new_capacity)) { | 12545 if (!object->ShouldConvertToSlowElements(new_capacity)) { |
12630 convert_to_slow = false; | 12546 convert_to_slow = false; |
12631 } | 12547 } |
12632 } | 12548 } |
12633 if (convert_to_slow) { | 12549 if (convert_to_slow) { |
12634 NormalizeElements(object); | 12550 NormalizeElements(object); |
12635 return SetDictionaryElement(object, index, value, NONE, language_mode, | 12551 SetDictionaryElement(object, index, value, NONE); |
12636 check_prototype); | 12552 return; |
12637 } | 12553 } |
12638 } | 12554 } |
12639 // Convert to fast double elements if appropriate. | 12555 // Convert to fast double elements if appropriate. |
12640 if (object->HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) { | 12556 if (object->HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) { |
12641 // Consider fixing the boilerplate as well if we have one. | 12557 // Consider fixing the boilerplate as well if we have one. |
12642 ElementsKind to_kind = IsHoleyElementsKind(elements_kind) | 12558 ElementsKind to_kind = IsHoleyElementsKind(elements_kind) |
12643 ? FAST_HOLEY_DOUBLE_ELEMENTS | 12559 ? FAST_HOLEY_DOUBLE_ELEMENTS |
12644 : FAST_DOUBLE_ELEMENTS; | 12560 : FAST_DOUBLE_ELEMENTS; |
12645 | 12561 |
12646 UpdateAllocationSite(object, to_kind); | 12562 UpdateAllocationSite(object, to_kind); |
12647 | 12563 |
12648 SetFastDoubleElementsCapacityAndLength(object, new_capacity, array_length); | 12564 SetFastDoubleElementsCapacityAndLength(object, new_capacity, array_length); |
12649 FixedDoubleArray::cast(object->elements())->set(index, value->Number()); | 12565 FixedDoubleArray::cast(object->elements())->set(index, value->Number()); |
12650 JSObject::ValidateElements(object); | 12566 JSObject::ValidateElements(object); |
12651 return value; | 12567 return; |
12652 } | 12568 } |
12653 // Change elements kind from Smi-only to generic FAST if necessary. | 12569 // Change elements kind from Smi-only to generic FAST if necessary. |
12654 if (object->HasFastSmiElements() && !value->IsSmi()) { | 12570 if (object->HasFastSmiElements() && !value->IsSmi()) { |
12655 ElementsKind kind = object->HasFastHoleyElements() | 12571 ElementsKind kind = object->HasFastHoleyElements() |
12656 ? FAST_HOLEY_ELEMENTS | 12572 ? FAST_HOLEY_ELEMENTS |
12657 : FAST_ELEMENTS; | 12573 : FAST_ELEMENTS; |
12658 | 12574 |
12659 UpdateAllocationSite(object, kind); | 12575 UpdateAllocationSite(object, kind); |
12660 Handle<Map> new_map = GetElementsTransitionMap(object, kind); | 12576 Handle<Map> new_map = GetElementsTransitionMap(object, kind); |
12661 JSObject::MigrateToMap(object, new_map); | 12577 JSObject::MigrateToMap(object, new_map); |
12662 DCHECK(IsFastObjectElementsKind(object->GetElementsKind())); | 12578 DCHECK(IsFastObjectElementsKind(object->GetElementsKind())); |
12663 } | 12579 } |
12664 // Increase backing store capacity if that's been decided previously. | 12580 // Increase backing store capacity if that's been decided previously. |
12665 if (new_capacity != capacity) { | 12581 if (new_capacity != capacity) { |
12666 SetFastElementsCapacitySmiMode smi_mode = | 12582 SetFastElementsCapacitySmiMode smi_mode = |
12667 value->IsSmi() && object->HasFastSmiElements() | 12583 value->IsSmi() && object->HasFastSmiElements() |
12668 ? kAllowSmiElements | 12584 ? kAllowSmiElements |
12669 : kDontAllowSmiElements; | 12585 : kDontAllowSmiElements; |
12670 Handle<FixedArray> new_elements = | 12586 Handle<FixedArray> new_elements = |
12671 SetFastElementsCapacityAndLength(object, new_capacity, array_length, | 12587 SetFastElementsCapacityAndLength(object, new_capacity, array_length, |
12672 smi_mode); | 12588 smi_mode); |
12673 new_elements->set(index, *value); | 12589 new_elements->set(index, *value); |
12674 JSObject::ValidateElements(object); | 12590 JSObject::ValidateElements(object); |
12675 return value; | 12591 return; |
12676 } | 12592 } |
12677 | 12593 |
12678 // Finally, set the new element and length. | 12594 // Finally, set the new element and length. |
12679 DCHECK(object->elements()->IsFixedArray()); | 12595 DCHECK(object->elements()->IsFixedArray()); |
12680 backing_store->set(index, *value); | 12596 backing_store->set(index, *value); |
12681 if (must_update_array_length) { | 12597 if (must_update_array_length) { |
12682 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length)); | 12598 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length)); |
12683 } | 12599 } |
12684 return value; | |
12685 } | 12600 } |
12686 | 12601 |
12687 | 12602 |
12688 MaybeHandle<Object> JSObject::SetDictionaryElement( | 12603 void JSObject::SetSloppyArgumentsElements(Handle<JSObject> object, |
12689 Handle<JSObject> object, uint32_t index, Handle<Object> value, | 12604 uint32_t index, Handle<Object> value, |
12690 PropertyAttributes attributes, LanguageMode language_mode, | 12605 PropertyAttributes attributes) { |
12691 bool check_prototype, SetPropertyMode set_mode) { | 12606 // TODO(verwaest): Handle with the elements accessor. |
12692 DCHECK(object->HasDictionaryElements() || | 12607 Isolate* isolate = object->GetIsolate(); |
12693 object->HasDictionaryArgumentsElements()); | 12608 |
12609 DCHECK(object->HasSloppyArgumentsElements()); | |
12610 | |
12611 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements())); | |
12612 uint32_t length = parameter_map->length(); | |
12613 Handle<Object> probe = | |
12614 index < length - 2 | |
12615 ? Handle<Object>(parameter_map->get(index + 2), isolate) | |
12616 : Handle<Object>(); | |
12617 if (!probe.is_null() && !probe->IsTheHole()) { | |
12618 Handle<Context> context(Context::cast(parameter_map->get(0))); | |
12619 int context_index = Handle<Smi>::cast(probe)->value(); | |
12620 DCHECK(!context->get(context_index)->IsTheHole()); | |
12621 context->set(context_index, *value); | |
12622 | |
12623 if (attributes == NONE) return; | |
12624 | |
12625 // Redefining attributes of an aliased element destroys fast aliasing. | |
12626 parameter_map->set_the_hole(index + 2); | |
12627 // For elements that are still writable we re-establish slow aliasing. | |
12628 if ((attributes & READ_ONLY) == 0) { | |
12629 value = Handle<Object>::cast( | |
12630 isolate->factory()->NewAliasedArgumentsEntry(context_index)); | |
12631 } | |
12632 } | |
12633 | |
12634 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1))); | |
12635 if (arguments->IsDictionary()) { | |
12636 SetDictionaryElement(object, index, value, attributes); | |
12637 } else { | |
12638 SetFastElement(object, index, value); | |
12639 } | |
12640 } | |
12641 | |
12642 | |
12643 void JSObject::SetDictionaryElement(Handle<JSObject> object, uint32_t index, | |
12644 Handle<Object> value, | |
12645 PropertyAttributes attributes) { | |
12646 // TODO(verwaest): Handle with the elements accessor. | |
12694 Isolate* isolate = object->GetIsolate(); | 12647 Isolate* isolate = object->GetIsolate(); |
12695 | 12648 |
12696 // Insert element in the dictionary. | 12649 // Insert element in the dictionary. |
12697 Handle<FixedArray> elements(FixedArray::cast(object->elements())); | 12650 Handle<FixedArray> elements(FixedArray::cast(object->elements())); |
12698 bool is_arguments = | 12651 bool is_arguments = |
12699 (elements->map() == isolate->heap()->sloppy_arguments_elements_map()); | 12652 (elements->map() == isolate->heap()->sloppy_arguments_elements_map()); |
12653 | |
12654 DCHECK(object->HasDictionaryElements() || | |
12655 object->HasDictionaryArgumentsElements()); | |
12656 | |
12700 Handle<SeededNumberDictionary> dictionary(is_arguments | 12657 Handle<SeededNumberDictionary> dictionary(is_arguments |
12701 ? SeededNumberDictionary::cast(elements->get(1)) | 12658 ? SeededNumberDictionary::cast(elements->get(1)) |
12702 : SeededNumberDictionary::cast(*elements)); | 12659 : SeededNumberDictionary::cast(*elements)); |
12703 | 12660 |
12704 int entry = dictionary->FindEntry(index); | 12661 int entry = dictionary->FindEntry(index); |
12705 if (entry != SeededNumberDictionary::kNotFound) { | 12662 if (entry != SeededNumberDictionary::kNotFound) { |
12706 Handle<Object> element(dictionary->ValueAt(entry), isolate); | 12663 Handle<Object> element(dictionary->ValueAt(entry), isolate); |
12707 PropertyDetails details = dictionary->DetailsAt(entry); | 12664 PropertyDetails details = dictionary->DetailsAt(entry); |
12708 if (details.type() == ACCESSOR_CONSTANT && set_mode == SET_PROPERTY) { | 12665 DCHECK(details.IsConfigurable() || !details.IsReadOnly() || |
12709 return SetElementWithCallback(object, element, index, value, object, | 12666 element->IsTheHole()); |
12710 language_mode); | 12667 dictionary->UpdateMaxNumberKey(index); |
12711 } else if (set_mode == DEFINE_PROPERTY && !details.IsConfigurable() && | |
12712 details.kind() == kAccessor) { | |
12713 return RedefineNonconfigurableProperty( | |
12714 isolate, isolate->factory()->NewNumberFromUint(index), | |
12715 isolate->factory()->undefined_value(), language_mode); | |
12716 | 12668 |
12717 } else if ((set_mode == DEFINE_PROPERTY && !details.IsConfigurable() && | 12669 details = PropertyDetails(attributes, DATA, details.dictionary_index(), |
12718 details.IsReadOnly()) || | 12670 PropertyCellType::kNoCell); |
12719 (set_mode == SET_PROPERTY && details.IsReadOnly() && | 12671 dictionary->DetailsAtPut(entry, details); |
12720 !element->IsTheHole())) { | |
12721 // If a value has not been initialized we allow writing to it even if it | |
12722 // is read-only (a declared const that has not been initialized). | |
12723 return WriteToReadOnlyProperty( | |
12724 isolate, object, isolate->factory()->NewNumberFromUint(index), | |
12725 isolate->factory()->undefined_value(), language_mode); | |
12726 } else { | |
12727 DCHECK(details.IsConfigurable() || !details.IsReadOnly() || | |
12728 element->IsTheHole()); | |
12729 dictionary->UpdateMaxNumberKey(index); | |
12730 if (set_mode == DEFINE_PROPERTY) { | |
12731 details = PropertyDetails(attributes, DATA, details.dictionary_index(), | |
12732 PropertyCellType::kNoCell); | |
12733 dictionary->DetailsAtPut(entry, details); | |
12734 } | |
12735 | 12672 |
12736 // Elements of the arguments object in slow mode might be slow aliases. | 12673 // Elements of the arguments object in slow mode might be slow aliases. |
12737 if (is_arguments && element->IsAliasedArgumentsEntry()) { | 12674 if (is_arguments && element->IsAliasedArgumentsEntry()) { |
12738 Handle<AliasedArgumentsEntry> entry = | 12675 Handle<AliasedArgumentsEntry> entry = |
12739 Handle<AliasedArgumentsEntry>::cast(element); | 12676 Handle<AliasedArgumentsEntry>::cast(element); |
12740 Handle<Context> context(Context::cast(elements->get(0))); | 12677 Handle<Context> context(Context::cast(elements->get(0))); |
12741 int context_index = entry->aliased_context_slot(); | 12678 int context_index = entry->aliased_context_slot(); |
12742 DCHECK(!context->get(context_index)->IsTheHole()); | 12679 DCHECK(!context->get(context_index)->IsTheHole()); |
12743 context->set(context_index, *value); | 12680 context->set(context_index, *value); |
12744 // For elements that are still writable we keep slow aliasing. | 12681 // For elements that are still writable we keep slow aliasing. |
12745 if (!details.IsReadOnly()) value = element; | 12682 if (!details.IsReadOnly()) value = element; |
12746 } | |
12747 dictionary->ValueAtPut(entry, *value); | |
12748 } | 12683 } |
12684 dictionary->ValueAtPut(entry, *value); | |
12749 } else { | 12685 } else { |
12750 // Index not already used. Look for an accessor in the prototype chain. | 12686 DCHECK(object->map()->is_extensible()); |
12751 // Can cause GC! | |
12752 if (check_prototype) { | |
12753 bool found; | |
12754 MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes( | |
12755 object, index, value, &found, language_mode); | |
12756 if (found) return result; | |
12757 } | |
12758 | |
12759 // When we set the is_extensible flag to false we always force the | |
12760 // element into dictionary mode (and force them to stay there). | |
12761 if (!object->map()->is_extensible()) { | |
12762 if (is_sloppy(language_mode)) { | |
12763 return isolate->factory()->undefined_value(); | |
12764 } else { | |
12765 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); | |
12766 Handle<String> name = isolate->factory()->NumberToString(number); | |
12767 THROW_NEW_ERROR( | |
12768 isolate, NewTypeError(MessageTemplate::kObjectNotExtensible, name), | |
12769 Object); | |
12770 } | |
12771 } | |
12772 | |
12773 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); | 12687 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); |
12774 Handle<SeededNumberDictionary> new_dictionary = | 12688 Handle<SeededNumberDictionary> new_dictionary = |
12775 SeededNumberDictionary::AddNumberEntry(dictionary, index, value, | 12689 SeededNumberDictionary::AddNumberEntry(dictionary, index, value, |
12776 details); | 12690 details); |
12777 if (*dictionary != *new_dictionary) { | 12691 if (*dictionary != *new_dictionary) { |
12778 if (is_arguments) { | 12692 if (is_arguments) { |
12779 elements->set(1, *new_dictionary); | 12693 elements->set(1, *new_dictionary); |
12780 } else { | 12694 } else { |
12781 object->set_elements(*new_dictionary); | 12695 object->set_elements(*new_dictionary); |
12782 } | 12696 } |
(...skipping 30 matching lines...) Expand all Loading... | |
12813 } | 12727 } |
12814 JSObject::ValidateElements(object); | 12728 JSObject::ValidateElements(object); |
12815 #ifdef DEBUG | 12729 #ifdef DEBUG |
12816 if (FLAG_trace_normalization) { | 12730 if (FLAG_trace_normalization) { |
12817 OFStream os(stdout); | 12731 OFStream os(stdout); |
12818 os << "Object elements are fast case again:\n"; | 12732 os << "Object elements are fast case again:\n"; |
12819 object->Print(os); | 12733 object->Print(os); |
12820 } | 12734 } |
12821 #endif | 12735 #endif |
12822 } | 12736 } |
12823 return value; | |
12824 } | 12737 } |
12825 | 12738 |
12826 MaybeHandle<Object> JSObject::SetFastDoubleElement(Handle<JSObject> object, | 12739 void JSObject::SetFastDoubleElement(Handle<JSObject> object, uint32_t index, |
12827 uint32_t index, | 12740 Handle<Object> value) { |
12828 Handle<Object> value, | |
12829 LanguageMode language_mode, | |
12830 bool check_prototype) { | |
12831 DCHECK(object->HasFastDoubleElements()); | 12741 DCHECK(object->HasFastDoubleElements()); |
12832 | 12742 |
12833 Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements())); | 12743 Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements())); |
12834 uint32_t elms_length = static_cast<uint32_t>(base_elms->length()); | 12744 uint32_t elms_length = static_cast<uint32_t>(base_elms->length()); |
12745 uint32_t length = elms_length; | |
12835 | 12746 |
12836 // If storing to an element that isn't in the array, pass the store request | |
12837 // up the prototype chain before storing in the receiver's elements. | |
12838 if (check_prototype && | |
12839 (index >= elms_length || | |
12840 Handle<FixedDoubleArray>::cast(base_elms)->is_the_hole(index))) { | |
12841 bool found; | |
12842 MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes( | |
12843 object, index, value, &found, language_mode); | |
12844 if (found) return result; | |
12845 } | |
12846 | |
12847 // If the value object is not a heap number, switch to fast elements and try | |
12848 // again. | |
12849 bool value_is_smi = value->IsSmi(); | |
12850 bool introduces_holes = true; | 12747 bool introduces_holes = true; |
12851 uint32_t length = elms_length; | |
12852 if (object->IsJSArray()) { | 12748 if (object->IsJSArray()) { |
12749 // In case of JSArray, the length does not equal the capacity. | |
12853 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength(&length)); | 12750 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength(&length)); |
12854 introduces_holes = index > length; | 12751 introduces_holes = index > length; |
12855 } else { | 12752 } else { |
12856 introduces_holes = index >= elms_length; | 12753 introduces_holes = index >= elms_length; |
12857 } | 12754 } |
12858 | 12755 |
12756 // If the value object is not a heap number, switch to fast elements and try | |
12757 // again. | |
12859 if (!value->IsNumber()) { | 12758 if (!value->IsNumber()) { |
12860 SetFastElementsCapacityAndLength(object, elms_length, length, | 12759 SetFastElementsCapacityAndLength(object, elms_length, length, |
12861 kDontAllowSmiElements); | 12760 kDontAllowSmiElements); |
12862 Handle<Object> result; | 12761 SetFastElement(object, index, value); |
12863 ASSIGN_RETURN_ON_EXCEPTION( | 12762 return; |
12864 object->GetIsolate(), result, | |
12865 SetFastElement(object, index, value, language_mode, check_prototype), | |
12866 Object); | |
12867 JSObject::ValidateElements(object); | |
12868 return result; | |
12869 } | 12763 } |
12870 | 12764 |
12871 double double_value = value_is_smi | |
12872 ? static_cast<double>(Handle<Smi>::cast(value)->value()) | |
12873 : Handle<HeapNumber>::cast(value)->value(); | |
12874 | |
12875 // If the array is growing, and it's not growth by a single element at the | 12765 // If the array is growing, and it's not growth by a single element at the |
12876 // end, make sure that the ElementsKind is HOLEY. | 12766 // end, make sure that the ElementsKind is HOLEY. |
12877 ElementsKind elements_kind = object->GetElementsKind(); | 12767 ElementsKind elements_kind = object->GetElementsKind(); |
12878 if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) { | 12768 if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) { |
12879 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind); | 12769 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind); |
12880 TransitionElementsKind(object, transitioned_kind); | 12770 TransitionElementsKind(object, transitioned_kind); |
12881 } | 12771 } |
12882 | 12772 |
12883 // Check whether there is extra space in the fixed array. | 12773 // Check whether there is extra space in the fixed array. |
12884 if (index < elms_length) { | 12774 if (index < elms_length) { |
12885 Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements())); | 12775 Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements())); |
12886 elms->set(index, double_value); | 12776 elms->set(index, value->Number()); |
12887 if (object->IsJSArray()) { | 12777 if (object->IsJSArray()) { |
12888 // Update the length of the array if needed. | 12778 // Update the length of the array if needed. |
12889 uint32_t array_length = 0; | 12779 uint32_t array_length = 0; |
12890 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength( | 12780 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength( |
12891 &array_length)); | 12781 &array_length)); |
12892 if (index >= array_length) { | 12782 if (index >= array_length) { |
12893 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1)); | 12783 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1)); |
12894 } | 12784 } |
12895 } | 12785 } |
12896 return value; | 12786 return; |
12897 } | 12787 } |
12898 | 12788 |
12899 // Allow gap in fast case. | 12789 // Allow gap in fast case. |
12900 if ((index - elms_length) < kMaxGap) { | 12790 if ((index - elms_length) < kMaxGap) { |
12901 // Try allocating extra space. | 12791 // Try allocating extra space. |
12902 int new_capacity = NewElementsCapacity(index+1); | 12792 int new_capacity = NewElementsCapacity(index+1); |
12903 if (!object->ShouldConvertToSlowElements(new_capacity)) { | 12793 if (!object->ShouldConvertToSlowElements(new_capacity)) { |
12904 DCHECK(static_cast<uint32_t>(new_capacity) > index); | 12794 DCHECK(static_cast<uint32_t>(new_capacity) > index); |
12905 SetFastDoubleElementsCapacityAndLength(object, new_capacity, index + 1); | 12795 SetFastDoubleElementsCapacityAndLength(object, new_capacity, index + 1); |
12906 FixedDoubleArray::cast(object->elements())->set(index, double_value); | 12796 FixedDoubleArray::cast(object->elements())->set(index, value->Number()); |
12907 JSObject::ValidateElements(object); | 12797 JSObject::ValidateElements(object); |
12908 return value; | 12798 return; |
12909 } | 12799 } |
12910 } | 12800 } |
12911 | 12801 |
12912 // Otherwise default to slow case. | 12802 // Otherwise default to slow case. |
12913 DCHECK(object->HasFastDoubleElements()); | 12803 DCHECK(object->HasFastDoubleElements()); |
12914 DCHECK(object->map()->has_fast_double_elements()); | 12804 DCHECK(object->map()->has_fast_double_elements()); |
12915 DCHECK(object->elements()->IsFixedDoubleArray() || | 12805 DCHECK(object->elements()->IsFixedDoubleArray() || |
12916 object->elements()->length() == 0); | 12806 object->elements()->length() == 0); |
12917 | 12807 |
12918 NormalizeElements(object); | 12808 NormalizeElements(object); |
12919 DCHECK(object->HasDictionaryElements()); | 12809 DCHECK(object->HasDictionaryElements()); |
12920 return SetElement(object, index, value, NONE, language_mode, check_prototype); | 12810 SetDictionaryElement(object, index, value, NONE); |
12811 return; | |
Igor Sheludko
2015/06/11 13:44:25
nit: Do we need return; here?
Toon Verwaest
2015/06/11 14:26:50
Done.
| |
12921 } | 12812 } |
12922 | 12813 |
12923 | 12814 |
12815 // static | |
12924 MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object, | 12816 MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object, |
12925 uint32_t index, Handle<Object> value, | 12817 uint32_t index, Handle<Object> value, |
12926 PropertyAttributes attributes, | |
12927 LanguageMode language_mode) { | 12818 LanguageMode language_mode) { |
12928 if (object->IsJSProxy()) { | 12819 Isolate* isolate = object->GetIsolate(); |
12929 return JSProxy::SetElementWithHandler(Handle<JSProxy>::cast(object), object, | 12820 LookupIterator it(isolate, object, index); |
12930 index, value, language_mode); | 12821 return SetProperty(&it, value, language_mode, MAY_BE_STORE_FROM_KEYED); |
12931 } | |
12932 return JSObject::SetElement(Handle<JSObject>::cast(object), index, value, | |
12933 attributes, language_mode); | |
12934 } | 12822 } |
12935 | 12823 |
12936 | 12824 |
12937 MaybeHandle<Object> JSObject::SetOwnElement(Handle<JSObject> object, | 12825 // static |
12938 uint32_t index, | 12826 MaybeHandle<Object> JSObject::AddDataElement(Handle<JSObject> receiver, |
12939 Handle<Object> value, | 12827 uint32_t index, |
12940 PropertyAttributes attributes, | 12828 Handle<Object> value, |
12941 LanguageMode language_mode) { | 12829 PropertyAttributes attributes) { |
12942 DCHECK(!object->HasExternalArrayElements()); | 12830 DCHECK(receiver->map()->is_extensible()); |
12943 return JSObject::SetElement(object, index, value, attributes, language_mode, | |
12944 false); | |
12945 } | |
12946 | 12831 |
12832 Isolate* isolate = receiver->GetIsolate(); | |
12947 | 12833 |
12948 MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object, | 12834 // TODO(verwaest): Use ElementAccessor. |
12949 uint32_t index, Handle<Object> value, | 12835 Handle<Object> old_length_handle; |
12950 PropertyAttributes attributes, | 12836 if (receiver->IsJSArray() && receiver->map()->is_observed()) { |
12951 LanguageMode language_mode, | 12837 old_length_handle = handle(JSArray::cast(*receiver)->length(), isolate); |
12952 bool check_prototype, | |
12953 SetPropertyMode set_mode) { | |
12954 Isolate* isolate = object->GetIsolate(); | |
12955 | |
12956 if (object->HasExternalArrayElements() || | |
12957 object->HasFixedTypedArrayElements()) { | |
12958 if (!value->IsNumber() && !value->IsUndefined()) { | |
12959 ASSIGN_RETURN_ON_EXCEPTION( | |
12960 isolate, value, | |
12961 Execution::ToNumber(isolate, value), Object); | |
12962 } | |
12963 } | 12838 } |
12964 | 12839 |
12965 // Check access rights if needed. | 12840 if (attributes != NONE) { |
12966 if (object->IsAccessCheckNeeded()) { | 12841 Handle<SeededNumberDictionary> d = JSObject::NormalizeElements(receiver); |
12967 if (!isolate->MayAccess(object)) { | 12842 // TODO(verwaest): Move this into NormalizeElements. |
12968 isolate->ReportFailedAccessCheck(object); | 12843 d->set_requires_slow_elements(); |
12969 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
12970 return value; | |
12971 } | |
12972 } | 12844 } |
12973 | 12845 |
12974 if (object->IsJSGlobalProxy()) { | 12846 Handle<Object> result = value; |
12975 PrototypeIterator iter(isolate, object); | 12847 |
12976 if (iter.IsAtEnd()) return value; | 12848 switch (receiver->GetElementsKind()) { |
12977 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); | 12849 case FAST_SMI_ELEMENTS: |
12978 return SetElement( | 12850 case FAST_ELEMENTS: |
12979 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index, | 12851 case FAST_HOLEY_SMI_ELEMENTS: |
12980 value, attributes, language_mode, check_prototype, set_mode); | 12852 case FAST_HOLEY_ELEMENTS: |
12853 SetFastElement(receiver, index, value); | |
12854 break; | |
12855 case FAST_DOUBLE_ELEMENTS: | |
12856 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
12857 SetFastDoubleElement(receiver, index, value); | |
12858 break; | |
12859 | |
12860 case DICTIONARY_ELEMENTS: | |
12861 SetDictionaryElement(receiver, index, value, attributes); | |
12862 break; | |
12863 case SLOPPY_ARGUMENTS_ELEMENTS: | |
12864 SetSloppyArgumentsElements(receiver, index, value, attributes); | |
12865 break; | |
12866 | |
12867 // Elements cannot be added to typed arrays. | |
12868 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | |
12869 case EXTERNAL_##TYPE##_ELEMENTS: \ | |
12870 case TYPE##_ELEMENTS: | |
12871 | |
12872 TYPED_ARRAYS(TYPED_ARRAY_CASE) | |
12873 | |
12874 #undef TYPED_ARRAY_CASE | |
12875 UNREACHABLE(); | |
12876 break; | |
12981 } | 12877 } |
12982 | 12878 |
12983 // Don't allow element properties to be redefined for external arrays. | 12879 if (!old_length_handle.is_null() && |
12984 if ((object->HasExternalArrayElements() || | 12880 !old_length_handle->SameValue( |
12985 object->HasFixedTypedArrayElements()) && | 12881 Handle<JSArray>::cast(receiver)->length())) { |
Igor Sheludko
2015/06/11 13:44:25
What about adding DCHECK(receiver->map()->is_obser
Toon Verwaest
2015/06/11 14:26:50
Done.
| |
12986 set_mode == DEFINE_PROPERTY) { | 12882 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
12987 THROW_NEW_ERROR( | 12883 Handle<String> name = isolate->factory()->Uint32ToString(index); |
12988 isolate, NewTypeError(MessageTemplate::kRedefineExternalArray), Object); | 12884 Handle<Object> new_length_handle(array->length(), isolate); |
12989 } | 12885 uint32_t old_length = 0; |
12886 uint32_t new_length = 0; | |
12887 CHECK(old_length_handle->ToArrayLength(&old_length)); | |
12888 CHECK(new_length_handle->ToArrayLength(&new_length)); | |
12990 | 12889 |
12991 // Normalize the elements to enable attributes on the property. | 12890 RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object); |
12992 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) { | |
12993 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object); | |
12994 // Make sure that we never go back to fast case. | |
12995 dictionary->set_requires_slow_elements(); | |
12996 } | |
12997 | |
12998 if (!object->map()->is_observed()) { | |
12999 return object->HasIndexedInterceptor() | |
13000 ? SetElementWithInterceptor(object, index, value, attributes, | |
13001 language_mode, check_prototype, | |
13002 set_mode) | |
13003 : SetElementWithoutInterceptor(object, index, value, attributes, | |
13004 language_mode, check_prototype, | |
13005 set_mode); | |
13006 } | |
13007 | |
13008 Maybe<PropertyAttributes> maybe = | |
13009 JSReceiver::GetOwnElementAttributes(object, index); | |
13010 if (!maybe.IsJust()) return MaybeHandle<Object>(); | |
13011 PropertyAttributes old_attributes = maybe.FromJust(); | |
13012 | |
13013 Handle<Object> old_value = isolate->factory()->the_hole_value(); | |
13014 Handle<Object> old_length_handle; | |
13015 Handle<Object> new_length_handle; | |
13016 | |
13017 if (old_attributes != ABSENT) { | |
13018 if (GetOwnElementAccessorPair(object, index).is_null()) { | |
13019 old_value = Object::GetElement(isolate, object, index).ToHandleChecked(); | |
13020 } | |
13021 } else if (object->IsJSArray()) { | |
13022 // Store old array length in case adding an element grows the array. | |
13023 old_length_handle = handle(Handle<JSArray>::cast(object)->length(), | |
13024 isolate); | |
13025 } | |
13026 | |
13027 // Check for lookup interceptor | |
13028 Handle<Object> result; | |
13029 ASSIGN_RETURN_ON_EXCEPTION( | |
13030 isolate, result, | |
13031 object->HasIndexedInterceptor() | |
13032 ? SetElementWithInterceptor(object, index, value, attributes, | |
13033 language_mode, check_prototype, set_mode) | |
13034 : SetElementWithoutInterceptor(object, index, value, attributes, | |
13035 language_mode, check_prototype, | |
13036 set_mode), | |
13037 Object); | |
13038 | |
13039 Handle<String> name = isolate->factory()->Uint32ToString(index); | |
13040 maybe = GetOwnElementAttributes(object, index); | |
13041 if (!maybe.IsJust()) return MaybeHandle<Object>(); | |
13042 PropertyAttributes new_attributes = maybe.FromJust(); | |
13043 | |
13044 if (old_attributes == ABSENT) { | |
13045 if (object->IsJSArray() && | |
13046 !old_length_handle->SameValue( | |
13047 Handle<JSArray>::cast(object)->length())) { | |
13048 new_length_handle = handle(Handle<JSArray>::cast(object)->length(), | |
13049 isolate); | |
13050 uint32_t old_length = 0; | |
13051 uint32_t new_length = 0; | |
13052 CHECK(old_length_handle->ToArrayLength(&old_length)); | |
13053 CHECK(new_length_handle->ToArrayLength(&new_length)); | |
13054 | |
13055 RETURN_ON_EXCEPTION( | |
13056 isolate, BeginPerformSplice(Handle<JSArray>::cast(object)), Object); | |
13057 RETURN_ON_EXCEPTION( | |
13058 isolate, EnqueueChangeRecord(object, "add", name, old_value), Object); | |
13059 RETURN_ON_EXCEPTION( | |
13060 isolate, EnqueueChangeRecord(object, "update", | |
13061 isolate->factory()->length_string(), | |
13062 old_length_handle), | |
13063 Object); | |
13064 RETURN_ON_EXCEPTION( | |
13065 isolate, EndPerformSplice(Handle<JSArray>::cast(object)), Object); | |
13066 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0); | |
13067 RETURN_ON_EXCEPTION( | |
13068 isolate, | |
13069 EnqueueSpliceRecord(Handle<JSArray>::cast(object), old_length, | |
13070 deleted, new_length - old_length), | |
13071 Object); | |
13072 } else { | |
13073 RETURN_ON_EXCEPTION( | |
13074 isolate, EnqueueChangeRecord(object, "add", name, old_value), Object); | |
13075 } | |
13076 } else if (old_value->IsTheHole()) { | |
13077 RETURN_ON_EXCEPTION( | 12891 RETURN_ON_EXCEPTION( |
13078 isolate, EnqueueChangeRecord(object, "reconfigure", name, old_value), | 12892 isolate, JSObject::EnqueueChangeRecord( |
12893 array, "add", name, isolate->factory()->the_hole_value()), | |
13079 Object); | 12894 Object); |
13080 } else { | 12895 RETURN_ON_EXCEPTION( |
13081 Handle<Object> new_value = | 12896 isolate, JSObject::EnqueueChangeRecord( |
13082 Object::GetElement(isolate, object, index).ToHandleChecked(); | 12897 array, "update", isolate->factory()->length_string(), |
13083 bool value_changed = !old_value->SameValue(*new_value); | 12898 old_length_handle), |
13084 if (old_attributes != new_attributes) { | 12899 Object); |
13085 if (!value_changed) old_value = isolate->factory()->the_hole_value(); | 12900 RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object); |
13086 RETURN_ON_EXCEPTION( | 12901 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0); |
13087 isolate, EnqueueChangeRecord(object, "reconfigure", name, old_value), | 12902 RETURN_ON_EXCEPTION(isolate, EnqueueSpliceRecord(array, old_length, deleted, |
13088 Object); | 12903 new_length - old_length), |
13089 } else if (value_changed) { | 12904 Object); |
13090 RETURN_ON_EXCEPTION( | 12905 } else if (receiver->map()->is_observed()) { |
13091 isolate, EnqueueChangeRecord(object, "update", name, old_value), | 12906 Handle<String> name = isolate->factory()->Uint32ToString(index); |
13092 Object); | 12907 RETURN_ON_EXCEPTION(isolate, JSObject::EnqueueChangeRecord( |
13093 } | 12908 receiver, "add", name, |
12909 isolate->factory()->the_hole_value()), | |
12910 Object); | |
13094 } | 12911 } |
13095 | 12912 |
13096 return result; | 12913 return result; |
13097 } | 12914 } |
13098 | 12915 |
13099 | 12916 |
13100 MaybeHandle<Object> JSObject::SetElementWithoutInterceptor( | |
13101 Handle<JSObject> object, uint32_t index, Handle<Object> value, | |
13102 PropertyAttributes attributes, LanguageMode language_mode, | |
13103 bool check_prototype, SetPropertyMode set_mode) { | |
13104 DCHECK(object->HasDictionaryElements() || | |
13105 object->HasDictionaryArgumentsElements() || | |
13106 (attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0); | |
13107 Isolate* isolate = object->GetIsolate(); | |
13108 if (FLAG_trace_external_array_abuse && | |
13109 IsExternalArrayElementsKind(object->GetElementsKind())) { | |
13110 CheckArrayAbuse(object, "external elements write", index); | |
13111 } | |
13112 if (FLAG_trace_js_array_abuse && | |
13113 !IsExternalArrayElementsKind(object->GetElementsKind())) { | |
13114 if (object->IsJSArray()) { | |
13115 CheckArrayAbuse(object, "elements write", index, true); | |
13116 } | |
13117 } | |
13118 if (object->IsJSArray() && JSArray::WouldChangeReadOnlyLength( | |
13119 Handle<JSArray>::cast(object), index)) { | |
13120 if (is_sloppy(language_mode)) { | |
13121 return value; | |
13122 } else { | |
13123 return JSArray::ReadOnlyLengthError(Handle<JSArray>::cast(object)); | |
13124 } | |
13125 } | |
13126 switch (object->GetElementsKind()) { | |
13127 case FAST_SMI_ELEMENTS: | |
13128 case FAST_ELEMENTS: | |
13129 case FAST_HOLEY_SMI_ELEMENTS: | |
13130 case FAST_HOLEY_ELEMENTS: | |
13131 return SetFastElement(object, index, value, language_mode, | |
13132 check_prototype); | |
13133 case FAST_DOUBLE_ELEMENTS: | |
13134 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
13135 return SetFastDoubleElement(object, index, value, language_mode, | |
13136 check_prototype); | |
13137 | |
13138 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | |
13139 case EXTERNAL_##TYPE##_ELEMENTS: { \ | |
13140 Handle<External##Type##Array> array( \ | |
13141 External##Type##Array::cast(object->elements())); \ | |
13142 return External##Type##Array::SetValue(object, array, index, value); \ | |
13143 } \ | |
13144 case TYPE##_ELEMENTS: { \ | |
13145 Handle<Fixed##Type##Array> array( \ | |
13146 Fixed##Type##Array::cast(object->elements())); \ | |
13147 return Fixed##Type##Array::SetValue(object, array, index, value); \ | |
13148 } | |
13149 | |
13150 TYPED_ARRAYS(TYPED_ARRAY_CASE) | |
13151 | |
13152 #undef TYPED_ARRAY_CASE | |
13153 | |
13154 case DICTIONARY_ELEMENTS: | |
13155 return SetDictionaryElement(object, index, value, attributes, | |
13156 language_mode, check_prototype, set_mode); | |
13157 case SLOPPY_ARGUMENTS_ELEMENTS: { | |
13158 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements())); | |
13159 uint32_t length = parameter_map->length(); | |
13160 Handle<Object> probe = index < length - 2 ? | |
13161 Handle<Object>(parameter_map->get(index + 2), isolate) : | |
13162 Handle<Object>(); | |
13163 if (!probe.is_null() && !probe->IsTheHole()) { | |
13164 Handle<Context> context(Context::cast(parameter_map->get(0))); | |
13165 int context_index = Handle<Smi>::cast(probe)->value(); | |
13166 DCHECK(!context->get(context_index)->IsTheHole()); | |
13167 context->set(context_index, *value); | |
13168 // Redefining attributes of an aliased element destroys fast aliasing. | |
13169 if (set_mode == SET_PROPERTY || attributes == NONE) return value; | |
13170 parameter_map->set_the_hole(index + 2); | |
13171 // For elements that are still writable we re-establish slow aliasing. | |
13172 if ((attributes & READ_ONLY) == 0) { | |
13173 value = Handle<Object>::cast( | |
13174 isolate->factory()->NewAliasedArgumentsEntry(context_index)); | |
13175 } | |
13176 } | |
13177 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1))); | |
13178 if (arguments->IsDictionary()) { | |
13179 return SetDictionaryElement(object, index, value, attributes, | |
13180 language_mode, check_prototype, set_mode); | |
13181 } else { | |
13182 return SetFastElement(object, index, value, language_mode, | |
13183 check_prototype); | |
13184 } | |
13185 } | |
13186 } | |
13187 // All possible cases have been handled above. Add a return to avoid the | |
13188 // complaints from the compiler. | |
13189 UNREACHABLE(); | |
13190 return isolate->factory()->null_value(); | |
13191 } | |
13192 | |
13193 | |
13194 const double AllocationSite::kPretenureRatio = 0.85; | 12917 const double AllocationSite::kPretenureRatio = 0.85; |
13195 | 12918 |
13196 | 12919 |
13197 void AllocationSite::ResetPretenureDecision() { | 12920 void AllocationSite::ResetPretenureDecision() { |
13198 set_pretenure_decision(kUndecided); | 12921 set_pretenure_decision(kUndecided); |
13199 set_memento_found_count(0); | 12922 set_memento_found_count(0); |
13200 set_memento_create_count(0); | 12923 set_memento_create_count(0); |
13201 } | 12924 } |
13202 | 12925 |
13203 | 12926 |
(...skipping 1767 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
14971 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE) | 14694 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE) |
14972 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE | 14695 #undef INSTANCE_TYPE_TO_ELEMENT_SIZE |
14973 | 14696 |
14974 default: | 14697 default: |
14975 UNREACHABLE(); | 14698 UNREACHABLE(); |
14976 return 0; | 14699 return 0; |
14977 } | 14700 } |
14978 } | 14701 } |
14979 | 14702 |
14980 | 14703 |
14704 Handle<Object> FixedArray::SetValue(Handle<JSObject> holder, | |
14705 Handle<FixedArray> array, uint32_t index, | |
14706 Handle<Object> value) { | |
14707 array->set(index, *value); | |
14708 return value; | |
14709 } | |
14710 | |
14711 | |
14712 Handle<Object> FixedDoubleArray::SetValue(Handle<JSObject> holder, | |
14713 Handle<FixedDoubleArray> array, | |
14714 uint32_t index, | |
14715 Handle<Object> value) { | |
14716 array->set(index, value->Number()); | |
14717 return value; | |
14718 } | |
14719 | |
14720 | |
14981 Handle<Object> ExternalUint8ClampedArray::SetValue( | 14721 Handle<Object> ExternalUint8ClampedArray::SetValue( |
14982 Handle<JSObject> holder, Handle<ExternalUint8ClampedArray> array, | 14722 Handle<JSObject> holder, Handle<ExternalUint8ClampedArray> array, |
14983 uint32_t index, Handle<Object> value) { | 14723 uint32_t index, Handle<Object> value) { |
14984 uint8_t clamped_value = 0; | 14724 uint8_t clamped_value = 0; |
14985 Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(holder); | 14725 Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(holder); |
14986 if (!view->WasNeutered()) { | 14726 if (!view->WasNeutered()) { |
14987 if (index < static_cast<uint32_t>(array->length())) { | 14727 if (index < static_cast<uint32_t>(array->length())) { |
14988 if (value->IsSmi()) { | 14728 if (value->IsSmi()) { |
14989 int int_value = Handle<Smi>::cast(value)->value(); | 14729 int int_value = Handle<Smi>::cast(value)->value(); |
14990 if (int_value < 0) { | 14730 if (int_value < 0) { |
(...skipping 1983 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
16974 Handle<Object> new_value) { | 16714 Handle<Object> new_value) { |
16975 if (cell->value() != *new_value) { | 16715 if (cell->value() != *new_value) { |
16976 cell->set_value(*new_value); | 16716 cell->set_value(*new_value); |
16977 Isolate* isolate = cell->GetIsolate(); | 16717 Isolate* isolate = cell->GetIsolate(); |
16978 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 16718 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
16979 isolate, DependentCode::kPropertyCellChangedGroup); | 16719 isolate, DependentCode::kPropertyCellChangedGroup); |
16980 } | 16720 } |
16981 } | 16721 } |
16982 } // namespace internal | 16722 } // namespace internal |
16983 } // namespace v8 | 16723 } // namespace v8 |
OLD | NEW |