| 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 593 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 604 auto curr = PrototypeIterator::GetCurrent(iter); | 604 auto curr = PrototypeIterator::GetCurrent(iter); |
| 605 if (!curr->IsJSObject()) break; | 605 if (!curr->IsJSObject()) break; |
| 606 auto obj = Handle<JSObject>::cast(curr); | 606 auto obj = Handle<JSObject>::cast(curr); |
| 607 if (!obj->HasIndexedInterceptor()) continue; | 607 if (!obj->HasIndexedInterceptor()) continue; |
| 608 if (obj->GetIndexedInterceptor()->all_can_read()) return obj; | 608 if (obj->GetIndexedInterceptor()->all_can_read()) return obj; |
| 609 } | 609 } |
| 610 return MaybeHandle<JSObject>(); | 610 return MaybeHandle<JSObject>(); |
| 611 } | 611 } |
| 612 | 612 |
| 613 | 613 |
| 614 MaybeHandle<Object> JSObject::GetElementWithFailedAccessCheck( | |
| 615 Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver, | |
| 616 uint32_t index) { | |
| 617 Handle<JSObject> holder = object; | |
| 618 PrototypeIterator::WhereToStart where_to_start = | |
| 619 PrototypeIterator::START_AT_RECEIVER; | |
| 620 while (true) { | |
| 621 auto all_can_read_holder = | |
| 622 FindIndexedAllCanReadHolder(isolate, holder, where_to_start); | |
| 623 if (!all_can_read_holder.ToHandle(&holder)) break; | |
| 624 auto result = | |
| 625 JSObject::GetElementWithInterceptor(holder, receiver, index, false); | |
| 626 if (isolate->has_scheduled_exception()) break; | |
| 627 if (!result.is_null()) return result; | |
| 628 where_to_start = PrototypeIterator::START_AT_PROTOTYPE; | |
| 629 } | |
| 630 isolate->ReportFailedAccessCheck(object); | |
| 631 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
| 632 return isolate->factory()->undefined_value(); | |
| 633 } | |
| 634 | |
| 635 | |
| 636 Maybe<PropertyAttributes> JSObject::GetElementAttributesWithFailedAccessCheck( | 614 Maybe<PropertyAttributes> JSObject::GetElementAttributesWithFailedAccessCheck( |
| 637 Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver, | 615 Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver, |
| 638 uint32_t index) { | 616 uint32_t index) { |
| 639 Handle<JSObject> holder = object; | 617 Handle<JSObject> holder = object; |
| 640 PrototypeIterator::WhereToStart where_to_start = | 618 PrototypeIterator::WhereToStart where_to_start = |
| 641 PrototypeIterator::START_AT_RECEIVER; | 619 PrototypeIterator::START_AT_RECEIVER; |
| 642 while (true) { | 620 while (true) { |
| 643 auto all_can_read_holder = | 621 auto all_can_read_holder = |
| 644 FindIndexedAllCanReadHolder(isolate, holder, where_to_start); | 622 FindIndexedAllCanReadHolder(isolate, holder, where_to_start); |
| 645 if (!all_can_read_holder.ToHandle(&holder)) break; | 623 if (!all_can_read_holder.ToHandle(&holder)) break; |
| 646 auto result = | 624 auto result = |
| 647 JSObject::GetElementAttributeFromInterceptor(holder, receiver, index); | 625 JSObject::GetElementAttributeFromInterceptor(holder, receiver, index); |
| 648 if (isolate->has_scheduled_exception()) break; | 626 if (isolate->has_scheduled_exception()) break; |
| 649 if (result.IsJust() && result.FromJust() != ABSENT) return result; | 627 if (result.IsJust() && result.FromJust() != ABSENT) return result; |
| 650 where_to_start = PrototypeIterator::START_AT_PROTOTYPE; | 628 where_to_start = PrototypeIterator::START_AT_PROTOTYPE; |
| 651 } | 629 } |
| 652 isolate->ReportFailedAccessCheck(object); | 630 isolate->ReportFailedAccessCheck(object); |
| 653 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); | 631 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); |
| 654 return Just(ABSENT); | 632 return Just(ABSENT); |
| 655 } | 633 } |
| 656 | 634 |
| 657 | 635 |
| 658 MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate, | |
| 659 Handle<Object> object, | |
| 660 Handle<Object> receiver, | |
| 661 uint32_t index) { | |
| 662 DCHECK(!object->IsUndefined()); | |
| 663 | |
| 664 // Iterate up the prototype chain until an element is found or the null | |
| 665 // prototype is encountered. | |
| 666 for (PrototypeIterator iter(isolate, object, | |
| 667 object->IsJSProxy() || object->IsJSObject() | |
| 668 ? PrototypeIterator::START_AT_RECEIVER | |
| 669 : PrototypeIterator::START_AT_PROTOTYPE); | |
| 670 !iter.IsAtEnd(); iter.Advance()) { | |
| 671 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | |
| 672 return JSProxy::GetElementWithHandler( | |
| 673 Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), receiver, | |
| 674 index); | |
| 675 } | |
| 676 | |
| 677 // Inline the case for JSObjects. Doing so significantly improves the | |
| 678 // performance of fetching elements where checking the prototype chain is | |
| 679 // necessary. | |
| 680 Handle<JSObject> js_object = | |
| 681 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
| 682 | |
| 683 // Check access rights if needed. | |
| 684 if (js_object->IsAccessCheckNeeded()) { | |
| 685 if (!isolate->MayAccess(js_object)) { | |
| 686 return JSObject::GetElementWithFailedAccessCheck(isolate, js_object, | |
| 687 receiver, index); | |
| 688 } | |
| 689 } | |
| 690 | |
| 691 if (js_object->HasIndexedInterceptor()) { | |
| 692 return JSObject::GetElementWithInterceptor(js_object, receiver, index, | |
| 693 true); | |
| 694 } | |
| 695 | |
| 696 if (js_object->elements() != isolate->heap()->empty_fixed_array()) { | |
| 697 Handle<Object> result; | |
| 698 ASSIGN_RETURN_ON_EXCEPTION( | |
| 699 isolate, result, | |
| 700 js_object->GetElementsAccessor()->Get(receiver, js_object, index), | |
| 701 Object); | |
| 702 if (!result->IsTheHole()) return result; | |
| 703 } | |
| 704 } | |
| 705 | |
| 706 return isolate->factory()->undefined_value(); | |
| 707 } | |
| 708 | |
| 709 | |
| 710 MaybeHandle<Object> Object::SetElementWithReceiver( | 636 MaybeHandle<Object> Object::SetElementWithReceiver( |
| 711 Isolate* isolate, Handle<Object> object, Handle<Object> receiver, | 637 Isolate* isolate, Handle<Object> object, Handle<Object> receiver, |
| 712 uint32_t index, Handle<Object> value, LanguageMode language_mode) { | 638 uint32_t index, Handle<Object> value, LanguageMode language_mode) { |
| 713 // Iterate up the prototype chain until an element is found or the null | 639 // Iterate up the prototype chain until an element is found or the null |
| 714 // prototype is encountered. | 640 // prototype is encountered. |
| 715 bool done = false; | 641 bool done = false; |
| 716 for (PrototypeIterator iter(isolate, object, | 642 for (PrototypeIterator iter(isolate, object, |
| 717 object->IsJSProxy() || object->IsJSObject() | 643 object->IsJSProxy() || object->IsJSObject() |
| 718 ? PrototypeIterator::START_AT_RECEIVER | 644 ? PrototypeIterator::START_AT_RECEIVER |
| 719 : PrototypeIterator::START_AT_PROTOTYPE); | 645 : PrototypeIterator::START_AT_PROTOTYPE); |
| (...skipping 7521 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8241 GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>( | 8167 GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>( |
| 8242 this, length() - new_length); | 8168 this, length() - new_length); |
| 8243 } | 8169 } |
| 8244 } | 8170 } |
| 8245 | 8171 |
| 8246 | 8172 |
| 8247 MaybeHandle<FixedArray> FixedArray::AddKeysFromArrayLike( | 8173 MaybeHandle<FixedArray> FixedArray::AddKeysFromArrayLike( |
| 8248 Handle<FixedArray> content, Handle<JSObject> array, KeyFilter filter) { | 8174 Handle<FixedArray> content, Handle<JSObject> array, KeyFilter filter) { |
| 8249 DCHECK(array->IsJSArray() || array->HasSloppyArgumentsElements()); | 8175 DCHECK(array->IsJSArray() || array->HasSloppyArgumentsElements()); |
| 8250 ElementsAccessor* accessor = array->GetElementsAccessor(); | 8176 ElementsAccessor* accessor = array->GetElementsAccessor(); |
| 8251 Handle<FixedArray> result; | 8177 Handle<FixedArray> result = |
| 8252 ASSIGN_RETURN_ON_EXCEPTION( | 8178 accessor->AddElementsToFixedArray(array, content, filter); |
| 8253 array->GetIsolate(), result, | |
| 8254 accessor->AddElementsToFixedArray(array, content, filter), FixedArray); | |
| 8255 | 8179 |
| 8256 #ifdef ENABLE_SLOW_DCHECKS | 8180 #ifdef ENABLE_SLOW_DCHECKS |
| 8257 if (FLAG_enable_slow_asserts) { | 8181 if (FLAG_enable_slow_asserts) { |
| 8258 DisallowHeapAllocation no_allocation; | 8182 DisallowHeapAllocation no_allocation; |
| 8259 for (int i = 0; i < result->length(); i++) { | 8183 for (int i = 0; i < result->length(); i++) { |
| 8260 Object* current = result->get(i); | 8184 Object* current = result->get(i); |
| 8261 DCHECK(current->IsNumber() || current->IsName()); | 8185 DCHECK(current->IsNumber() || current->IsName()); |
| 8262 } | 8186 } |
| 8263 } | 8187 } |
| 8264 #endif | 8188 #endif |
| (...skipping 4025 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12290 DCHECK(array->AllowsSetElementsLength()); | 12214 DCHECK(array->AllowsSetElementsLength()); |
| 12291 if (!array->map()->is_observed()) { | 12215 if (!array->map()->is_observed()) { |
| 12292 return array->GetElementsAccessor()->SetLength(array, new_length_handle); | 12216 return array->GetElementsAccessor()->SetLength(array, new_length_handle); |
| 12293 } | 12217 } |
| 12294 | 12218 |
| 12295 Isolate* isolate = array->GetIsolate(); | 12219 Isolate* isolate = array->GetIsolate(); |
| 12296 List<uint32_t> indices; | 12220 List<uint32_t> indices; |
| 12297 List<Handle<Object> > old_values; | 12221 List<Handle<Object> > old_values; |
| 12298 Handle<Object> old_length_handle(array->length(), isolate); | 12222 Handle<Object> old_length_handle(array->length(), isolate); |
| 12299 uint32_t old_length = 0; | 12223 uint32_t old_length = 0; |
| 12300 CHECK(old_length_handle->ToArrayIndex(&old_length)); | 12224 CHECK(old_length_handle->ToArrayLength(&old_length)); |
| 12301 uint32_t new_length = 0; | 12225 uint32_t new_length = 0; |
| 12302 CHECK(new_length_handle->ToArrayIndex(&new_length)); | 12226 CHECK(new_length_handle->ToArrayLength(&new_length)); |
| 12303 | 12227 |
| 12304 static const PropertyAttributes kNoAttrFilter = NONE; | 12228 static const PropertyAttributes kNoAttrFilter = NONE; |
| 12305 int num_elements = array->NumberOfOwnElements(kNoAttrFilter); | 12229 int num_elements = array->NumberOfOwnElements(kNoAttrFilter); |
| 12306 if (num_elements > 0) { | 12230 if (num_elements > 0) { |
| 12307 if (old_length == static_cast<uint32_t>(num_elements)) { | 12231 if (old_length == static_cast<uint32_t>(num_elements)) { |
| 12308 // Simple case for arrays without holes. | 12232 // Simple case for arrays without holes. |
| 12309 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) { | 12233 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) { |
| 12310 if (!GetOldValue(isolate, array, i, &old_values, &indices)) break; | 12234 if (!GetOldValue(isolate, array, i, &old_values, &indices)) break; |
| 12311 } | 12235 } |
| 12312 } else { | 12236 } else { |
| 12313 // For sparse arrays, only iterate over existing elements. | 12237 // For sparse arrays, only iterate over existing elements. |
| 12314 // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over | 12238 // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over |
| 12315 // the to-be-removed indices twice. | 12239 // the to-be-removed indices twice. |
| 12316 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements); | 12240 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements); |
| 12317 array->GetOwnElementKeys(*keys, kNoAttrFilter); | 12241 array->GetOwnElementKeys(*keys, kNoAttrFilter); |
| 12318 while (num_elements-- > 0) { | 12242 while (num_elements-- > 0) { |
| 12319 uint32_t index = NumberToUint32(keys->get(num_elements)); | 12243 uint32_t index = NumberToUint32(keys->get(num_elements)); |
| 12320 if (index < new_length) break; | 12244 if (index < new_length) break; |
| 12321 if (!GetOldValue(isolate, array, index, &old_values, &indices)) break; | 12245 if (!GetOldValue(isolate, array, index, &old_values, &indices)) break; |
| 12322 } | 12246 } |
| 12323 } | 12247 } |
| 12324 } | 12248 } |
| 12325 | 12249 |
| 12326 Handle<Object> hresult; | 12250 Handle<Object> hresult; |
| 12327 ASSIGN_RETURN_ON_EXCEPTION( | 12251 ASSIGN_RETURN_ON_EXCEPTION( |
| 12328 isolate, hresult, | 12252 isolate, hresult, |
| 12329 array->GetElementsAccessor()->SetLength(array, new_length_handle), | 12253 array->GetElementsAccessor()->SetLength(array, new_length_handle), |
| 12330 Object); | 12254 Object); |
| 12331 | 12255 |
| 12332 CHECK(array->length()->ToArrayIndex(&new_length)); | 12256 CHECK(array->length()->ToArrayLength(&new_length)); |
| 12333 if (old_length == new_length) return hresult; | 12257 if (old_length == new_length) return hresult; |
| 12334 | 12258 |
| 12335 RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object); | 12259 RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object); |
| 12336 | 12260 |
| 12337 for (int i = 0; i < indices.length(); ++i) { | 12261 for (int i = 0; i < indices.length(); ++i) { |
| 12338 // For deletions where the property was an accessor, old_values[i] | 12262 // For deletions where the property was an accessor, old_values[i] |
| 12339 // will be the hole, which instructs EnqueueChangeRecord to elide | 12263 // will be the hole, which instructs EnqueueChangeRecord to elide |
| 12340 // the "oldValue" property. | 12264 // the "oldValue" property. |
| 12341 RETURN_ON_EXCEPTION( | 12265 RETURN_ON_EXCEPTION( |
| 12342 isolate, | 12266 isolate, |
| (...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12818 args.Call(setter, index, v8::Utils::ToLocal(value)); | 12742 args.Call(setter, index, v8::Utils::ToLocal(value)); |
| 12819 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | 12743 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
| 12820 if (!result.IsEmpty()) return value; | 12744 if (!result.IsEmpty()) return value; |
| 12821 } | 12745 } |
| 12822 | 12746 |
| 12823 return SetElementWithoutInterceptor(object, index, value, attributes, | 12747 return SetElementWithoutInterceptor(object, index, value, attributes, |
| 12824 language_mode, check_prototype, set_mode); | 12748 language_mode, check_prototype, set_mode); |
| 12825 } | 12749 } |
| 12826 | 12750 |
| 12827 | 12751 |
| 12828 MaybeHandle<Object> JSObject::GetElementWithCallback( | |
| 12829 Handle<JSObject> object, | |
| 12830 Handle<Object> receiver, | |
| 12831 Handle<Object> structure, | |
| 12832 uint32_t index, | |
| 12833 Handle<Object> holder) { | |
| 12834 Isolate* isolate = object->GetIsolate(); | |
| 12835 DCHECK(!structure->IsForeign()); | |
| 12836 // api style callbacks. | |
| 12837 if (structure->IsExecutableAccessorInfo()) { | |
| 12838 Handle<ExecutableAccessorInfo> data = | |
| 12839 Handle<ExecutableAccessorInfo>::cast(structure); | |
| 12840 Object* fun_obj = data->getter(); | |
| 12841 v8::AccessorNameGetterCallback call_fun = | |
| 12842 v8::ToCData<v8::AccessorNameGetterCallback>(fun_obj); | |
| 12843 if (call_fun == NULL) return isolate->factory()->undefined_value(); | |
| 12844 Handle<JSObject> holder_handle = Handle<JSObject>::cast(holder); | |
| 12845 Handle<String> key = isolate->factory()->Uint32ToString(index); | |
| 12846 LOG(isolate, ApiNamedPropertyAccess("load", *holder_handle, *key)); | |
| 12847 PropertyCallbackArguments | |
| 12848 args(isolate, data->data(), *receiver, *holder_handle); | |
| 12849 v8::Handle<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(key)); | |
| 12850 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
| 12851 if (result.IsEmpty()) return isolate->factory()->undefined_value(); | |
| 12852 Handle<Object> result_internal = v8::Utils::OpenHandle(*result); | |
| 12853 result_internal->VerifyApiCallResultType(); | |
| 12854 // Rebox handle before return. | |
| 12855 return handle(*result_internal, isolate); | |
| 12856 } | |
| 12857 | |
| 12858 // __defineGetter__ callback | |
| 12859 if (structure->IsAccessorPair()) { | |
| 12860 Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(), | |
| 12861 isolate); | |
| 12862 if (getter->IsSpecFunction()) { | |
| 12863 // TODO(rossberg): nicer would be to cast to some JSCallable here... | |
| 12864 return GetPropertyWithDefinedGetter( | |
| 12865 receiver, Handle<JSReceiver>::cast(getter)); | |
| 12866 } | |
| 12867 // Getter is not a function. | |
| 12868 return isolate->factory()->undefined_value(); | |
| 12869 } | |
| 12870 | |
| 12871 UNREACHABLE(); | |
| 12872 return MaybeHandle<Object>(); | |
| 12873 } | |
| 12874 | |
| 12875 | |
| 12876 MaybeHandle<Object> JSObject::SetElementWithCallback( | 12752 MaybeHandle<Object> JSObject::SetElementWithCallback( |
| 12877 Handle<Object> object, Handle<Object> structure, uint32_t index, | 12753 Handle<Object> object, Handle<Object> structure, uint32_t index, |
| 12878 Handle<Object> value, Handle<JSObject> holder, LanguageMode language_mode) { | 12754 Handle<Object> value, Handle<JSObject> holder, LanguageMode language_mode) { |
| 12879 Isolate* isolate = holder->GetIsolate(); | 12755 Isolate* isolate = holder->GetIsolate(); |
| 12880 | 12756 |
| 12881 // We should never get here to initialize a const with the hole | 12757 // We should never get here to initialize a const with the hole |
| 12882 // value since a const declaration would conflict with the setter. | 12758 // value since a const declaration would conflict with the setter. |
| 12883 DCHECK(!value->IsTheHole()); | 12759 DCHECK(!value->IsTheHole()); |
| 12884 DCHECK(!structure->IsForeign()); | 12760 DCHECK(!structure->IsForeign()); |
| 12885 if (structure->IsExecutableAccessorInfo()) { | 12761 if (structure->IsExecutableAccessorInfo()) { |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12980 object, index, value, &found, language_mode); | 12856 object, index, value, &found, language_mode); |
| 12981 if (found) return result; | 12857 if (found) return result; |
| 12982 } | 12858 } |
| 12983 | 12859 |
| 12984 uint32_t new_capacity = capacity; | 12860 uint32_t new_capacity = capacity; |
| 12985 // Check if the length property of this object needs to be updated. | 12861 // Check if the length property of this object needs to be updated. |
| 12986 uint32_t array_length = 0; | 12862 uint32_t array_length = 0; |
| 12987 bool must_update_array_length = false; | 12863 bool must_update_array_length = false; |
| 12988 bool introduces_holes = true; | 12864 bool introduces_holes = true; |
| 12989 if (object->IsJSArray()) { | 12865 if (object->IsJSArray()) { |
| 12990 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length)); | 12866 CHECK( |
| 12867 Handle<JSArray>::cast(object)->length()->ToArrayLength(&array_length)); |
| 12991 introduces_holes = index > array_length; | 12868 introduces_holes = index > array_length; |
| 12992 if (index >= array_length) { | 12869 if (index >= array_length) { |
| 12993 must_update_array_length = true; | 12870 must_update_array_length = true; |
| 12994 array_length = index + 1; | 12871 array_length = index + 1; |
| 12995 } | 12872 } |
| 12996 } else { | 12873 } else { |
| 12997 introduces_holes = index >= capacity; | 12874 introduces_holes = index >= capacity; |
| 12998 } | 12875 } |
| 12999 | 12876 |
| 13000 // If the array is growing, and it's not growth by a single element at the | 12877 // If the array is growing, and it's not growth by a single element at the |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13175 // Update the array length if this JSObject is an array. | 13052 // Update the array length if this JSObject is an array. |
| 13176 if (object->IsJSArray()) { | 13053 if (object->IsJSArray()) { |
| 13177 JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray>::cast(object), index, | 13054 JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray>::cast(object), index, |
| 13178 value); | 13055 value); |
| 13179 } | 13056 } |
| 13180 | 13057 |
| 13181 // Attempt to put this object back in fast case. | 13058 // Attempt to put this object back in fast case. |
| 13182 if (object->ShouldConvertToFastElements()) { | 13059 if (object->ShouldConvertToFastElements()) { |
| 13183 uint32_t new_length = 0; | 13060 uint32_t new_length = 0; |
| 13184 if (object->IsJSArray()) { | 13061 if (object->IsJSArray()) { |
| 13185 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&new_length)); | 13062 CHECK( |
| 13063 Handle<JSArray>::cast(object)->length()->ToArrayLength(&new_length)); |
| 13186 } else { | 13064 } else { |
| 13187 new_length = dictionary->max_number_key() + 1; | 13065 new_length = dictionary->max_number_key() + 1; |
| 13188 } | 13066 } |
| 13189 bool has_smi_only_elements = false; | 13067 bool has_smi_only_elements = false; |
| 13190 bool should_convert_to_fast_double_elements = | 13068 bool should_convert_to_fast_double_elements = |
| 13191 object->ShouldConvertToFastDoubleElements(&has_smi_only_elements); | 13069 object->ShouldConvertToFastDoubleElements(&has_smi_only_elements); |
| 13192 SetFastElementsCapacitySmiMode smi_mode = | 13070 SetFastElementsCapacitySmiMode smi_mode = |
| 13193 has_smi_only_elements ? kForceSmiElements : kAllowSmiElements; | 13071 has_smi_only_elements ? kForceSmiElements : kAllowSmiElements; |
| 13194 | 13072 |
| 13195 if (should_convert_to_fast_double_elements) { | 13073 if (should_convert_to_fast_double_elements) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13230 object, index, value, &found, language_mode); | 13108 object, index, value, &found, language_mode); |
| 13231 if (found) return result; | 13109 if (found) return result; |
| 13232 } | 13110 } |
| 13233 | 13111 |
| 13234 // If the value object is not a heap number, switch to fast elements and try | 13112 // If the value object is not a heap number, switch to fast elements and try |
| 13235 // again. | 13113 // again. |
| 13236 bool value_is_smi = value->IsSmi(); | 13114 bool value_is_smi = value->IsSmi(); |
| 13237 bool introduces_holes = true; | 13115 bool introduces_holes = true; |
| 13238 uint32_t length = elms_length; | 13116 uint32_t length = elms_length; |
| 13239 if (object->IsJSArray()) { | 13117 if (object->IsJSArray()) { |
| 13240 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&length)); | 13118 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength(&length)); |
| 13241 introduces_holes = index > length; | 13119 introduces_holes = index > length; |
| 13242 } else { | 13120 } else { |
| 13243 introduces_holes = index >= elms_length; | 13121 introduces_holes = index >= elms_length; |
| 13244 } | 13122 } |
| 13245 | 13123 |
| 13246 if (!value->IsNumber()) { | 13124 if (!value->IsNumber()) { |
| 13247 SetFastElementsCapacityAndLength(object, elms_length, length, | 13125 SetFastElementsCapacityAndLength(object, elms_length, length, |
| 13248 kDontAllowSmiElements); | 13126 kDontAllowSmiElements); |
| 13249 Handle<Object> result; | 13127 Handle<Object> result; |
| 13250 ASSIGN_RETURN_ON_EXCEPTION( | 13128 ASSIGN_RETURN_ON_EXCEPTION( |
| (...skipping 16 matching lines...) Expand all Loading... |
| 13267 TransitionElementsKind(object, transitioned_kind); | 13145 TransitionElementsKind(object, transitioned_kind); |
| 13268 } | 13146 } |
| 13269 | 13147 |
| 13270 // Check whether there is extra space in the fixed array. | 13148 // Check whether there is extra space in the fixed array. |
| 13271 if (index < elms_length) { | 13149 if (index < elms_length) { |
| 13272 Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements())); | 13150 Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements())); |
| 13273 elms->set(index, double_value); | 13151 elms->set(index, double_value); |
| 13274 if (object->IsJSArray()) { | 13152 if (object->IsJSArray()) { |
| 13275 // Update the length of the array if needed. | 13153 // Update the length of the array if needed. |
| 13276 uint32_t array_length = 0; | 13154 uint32_t array_length = 0; |
| 13277 CHECK( | 13155 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength( |
| 13278 Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length)); | 13156 &array_length)); |
| 13279 if (index >= array_length) { | 13157 if (index >= array_length) { |
| 13280 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1)); | 13158 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1)); |
| 13281 } | 13159 } |
| 13282 } | 13160 } |
| 13283 return value; | 13161 return value; |
| 13284 } | 13162 } |
| 13285 | 13163 |
| 13286 // Allow gap in fast case. | 13164 // Allow gap in fast case. |
| 13287 if ((index - elms_length) < kMaxGap) { | 13165 if ((index - elms_length) < kMaxGap) { |
| 13288 // Try allocating extra space. | 13166 // Try allocating extra space. |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13429 PropertyAttributes new_attributes = maybe.FromJust(); | 13307 PropertyAttributes new_attributes = maybe.FromJust(); |
| 13430 | 13308 |
| 13431 if (old_attributes == ABSENT) { | 13309 if (old_attributes == ABSENT) { |
| 13432 if (object->IsJSArray() && | 13310 if (object->IsJSArray() && |
| 13433 !old_length_handle->SameValue( | 13311 !old_length_handle->SameValue( |
| 13434 Handle<JSArray>::cast(object)->length())) { | 13312 Handle<JSArray>::cast(object)->length())) { |
| 13435 new_length_handle = handle(Handle<JSArray>::cast(object)->length(), | 13313 new_length_handle = handle(Handle<JSArray>::cast(object)->length(), |
| 13436 isolate); | 13314 isolate); |
| 13437 uint32_t old_length = 0; | 13315 uint32_t old_length = 0; |
| 13438 uint32_t new_length = 0; | 13316 uint32_t new_length = 0; |
| 13439 CHECK(old_length_handle->ToArrayIndex(&old_length)); | 13317 CHECK(old_length_handle->ToArrayLength(&old_length)); |
| 13440 CHECK(new_length_handle->ToArrayIndex(&new_length)); | 13318 CHECK(new_length_handle->ToArrayLength(&new_length)); |
| 13441 | 13319 |
| 13442 RETURN_ON_EXCEPTION( | 13320 RETURN_ON_EXCEPTION( |
| 13443 isolate, BeginPerformSplice(Handle<JSArray>::cast(object)), Object); | 13321 isolate, BeginPerformSplice(Handle<JSArray>::cast(object)), Object); |
| 13444 RETURN_ON_EXCEPTION( | 13322 RETURN_ON_EXCEPTION( |
| 13445 isolate, EnqueueChangeRecord(object, "add", name, old_value), Object); | 13323 isolate, EnqueueChangeRecord(object, "add", name, old_value), Object); |
| 13446 RETURN_ON_EXCEPTION( | 13324 RETURN_ON_EXCEPTION( |
| 13447 isolate, EnqueueChangeRecord(object, "update", | 13325 isolate, EnqueueChangeRecord(object, "update", |
| 13448 isolate->factory()->length_string(), | 13326 isolate->factory()->length_string(), |
| 13449 old_length_handle), | 13327 old_length_handle), |
| 13450 Object); | 13328 Object); |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13618 handle(JSArray::cast(site->transition_info())); | 13496 handle(JSArray::cast(site->transition_info())); |
| 13619 ElementsKind kind = transition_info->GetElementsKind(); | 13497 ElementsKind kind = transition_info->GetElementsKind(); |
| 13620 // if kind is holey ensure that to_kind is as well. | 13498 // if kind is holey ensure that to_kind is as well. |
| 13621 if (IsHoleyElementsKind(kind)) { | 13499 if (IsHoleyElementsKind(kind)) { |
| 13622 to_kind = GetHoleyElementsKind(to_kind); | 13500 to_kind = GetHoleyElementsKind(to_kind); |
| 13623 } | 13501 } |
| 13624 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { | 13502 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { |
| 13625 // If the array is huge, it's not likely to be defined in a local | 13503 // If the array is huge, it's not likely to be defined in a local |
| 13626 // function, so we shouldn't make new instances of it very often. | 13504 // function, so we shouldn't make new instances of it very often. |
| 13627 uint32_t length = 0; | 13505 uint32_t length = 0; |
| 13628 CHECK(transition_info->length()->ToArrayIndex(&length)); | 13506 CHECK(transition_info->length()->ToArrayLength(&length)); |
| 13629 if (length <= kMaximumArrayBytesToPretransition) { | 13507 if (length <= kMaximumArrayBytesToPretransition) { |
| 13630 if (FLAG_trace_track_allocation_sites) { | 13508 if (FLAG_trace_track_allocation_sites) { |
| 13631 bool is_nested = site->IsNestedSite(); | 13509 bool is_nested = site->IsNestedSite(); |
| 13632 PrintF( | 13510 PrintF( |
| 13633 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n", | 13511 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n", |
| 13634 reinterpret_cast<void*>(*site), | 13512 reinterpret_cast<void*>(*site), |
| 13635 is_nested ? "(nested)" : "", | 13513 is_nested ? "(nested)" : "", |
| 13636 ElementsKindToString(kind), | 13514 ElementsKindToString(kind), |
| 13637 ElementsKindToString(to_kind)); | 13515 ElementsKindToString(to_kind)); |
| 13638 } | 13516 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13732 uint32_t capacity = static_cast<uint32_t>(elms->length()); | 13610 uint32_t capacity = static_cast<uint32_t>(elms->length()); |
| 13733 uint32_t length = capacity; | 13611 uint32_t length = capacity; |
| 13734 | 13612 |
| 13735 if (object->IsJSArray()) { | 13613 if (object->IsJSArray()) { |
| 13736 Object* raw_length = Handle<JSArray>::cast(object)->length(); | 13614 Object* raw_length = Handle<JSArray>::cast(object)->length(); |
| 13737 if (raw_length->IsUndefined()) { | 13615 if (raw_length->IsUndefined()) { |
| 13738 // If length is undefined, then JSArray is being initialized and has no | 13616 // If length is undefined, then JSArray is being initialized and has no |
| 13739 // elements, assume a length of zero. | 13617 // elements, assume a length of zero. |
| 13740 length = 0; | 13618 length = 0; |
| 13741 } else { | 13619 } else { |
| 13742 CHECK(raw_length->ToArrayIndex(&length)); | 13620 CHECK(raw_length->ToArrayLength(&length)); |
| 13743 } | 13621 } |
| 13744 } | 13622 } |
| 13745 | 13623 |
| 13746 if (IsFastSmiElementsKind(from_kind) && | 13624 if (IsFastSmiElementsKind(from_kind) && |
| 13747 IsFastDoubleElementsKind(to_kind)) { | 13625 IsFastDoubleElementsKind(to_kind)) { |
| 13748 SetFastDoubleElementsCapacityAndLength(object, capacity, length); | 13626 SetFastDoubleElementsCapacityAndLength(object, capacity, length); |
| 13749 JSObject::ValidateElements(object); | 13627 JSObject::ValidateElements(object); |
| 13750 return; | 13628 return; |
| 13751 } | 13629 } |
| 13752 | 13630 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 13775 // Transitions from HOLEY -> PACKED are not allowed. | 13653 // Transitions from HOLEY -> PACKED are not allowed. |
| 13776 return !IsFastHoleyElementsKind(from_kind) || | 13654 return !IsFastHoleyElementsKind(from_kind) || |
| 13777 IsFastHoleyElementsKind(to_kind); | 13655 IsFastHoleyElementsKind(to_kind); |
| 13778 } | 13656 } |
| 13779 | 13657 |
| 13780 | 13658 |
| 13781 void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array, | 13659 void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array, |
| 13782 uint32_t index, | 13660 uint32_t index, |
| 13783 Handle<Object> value) { | 13661 Handle<Object> value) { |
| 13784 uint32_t old_len = 0; | 13662 uint32_t old_len = 0; |
| 13785 CHECK(array->length()->ToArrayIndex(&old_len)); | 13663 CHECK(array->length()->ToArrayLength(&old_len)); |
| 13786 // Check to see if we need to update the length. For now, we make | 13664 // Check to see if we need to update the length. For now, we make |
| 13787 // sure that the length stays within 32-bits (unsigned). | 13665 // sure that the length stays within 32-bits (unsigned). |
| 13788 if (index >= old_len && index != 0xffffffff) { | 13666 if (index >= old_len && index != 0xffffffff) { |
| 13789 Handle<Object> len = array->GetIsolate()->factory()->NewNumber( | 13667 Handle<Object> len = array->GetIsolate()->factory()->NewNumber( |
| 13790 static_cast<double>(index) + 1); | 13668 static_cast<double>(index) + 1); |
| 13791 array->set_length(*len); | 13669 array->set_length(*len); |
| 13792 } | 13670 } |
| 13793 } | 13671 } |
| 13794 | 13672 |
| 13795 | 13673 |
| 13796 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) { | 13674 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) { |
| 13797 LookupIterator it(array, array->GetIsolate()->factory()->length_string(), | 13675 LookupIterator it(array, array->GetIsolate()->factory()->length_string(), |
| 13798 LookupIterator::OWN_SKIP_INTERCEPTOR); | 13676 LookupIterator::OWN_SKIP_INTERCEPTOR); |
| 13799 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state()); | 13677 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state()); |
| 13800 CHECK(it.IsFound()); | 13678 CHECK(it.IsFound()); |
| 13801 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); | 13679 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); |
| 13802 return it.IsReadOnly(); | 13680 return it.IsReadOnly(); |
| 13803 } | 13681 } |
| 13804 | 13682 |
| 13805 | 13683 |
| 13806 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array, | 13684 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array, |
| 13807 uint32_t index) { | 13685 uint32_t index) { |
| 13808 uint32_t length = 0; | 13686 uint32_t length = 0; |
| 13809 CHECK(array->length()->ToArrayIndex(&length)); | 13687 CHECK(array->length()->ToArrayLength(&length)); |
| 13810 if (length <= index) return HasReadOnlyLength(array); | 13688 if (length <= index) return HasReadOnlyLength(array); |
| 13811 return false; | 13689 return false; |
| 13812 } | 13690 } |
| 13813 | 13691 |
| 13814 | 13692 |
| 13815 MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) { | 13693 MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) { |
| 13816 Isolate* isolate = array->GetIsolate(); | 13694 Isolate* isolate = array->GetIsolate(); |
| 13817 Handle<Name> length = isolate->factory()->length_string(); | 13695 Handle<Name> length = isolate->factory()->length_string(); |
| 13818 THROW_NEW_ERROR( | 13696 THROW_NEW_ERROR( |
| 13819 isolate, | 13697 isolate, |
| 13820 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, length, array), | 13698 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, length, array), |
| 13821 Object); | 13699 Object); |
| 13822 } | 13700 } |
| 13823 | 13701 |
| 13824 | 13702 |
| 13825 MaybeHandle<Object> JSObject::GetElementWithInterceptor(Handle<JSObject> object, | |
| 13826 Handle<Object> receiver, | |
| 13827 uint32_t index, | |
| 13828 bool check_prototype) { | |
| 13829 Isolate* isolate = object->GetIsolate(); | |
| 13830 | |
| 13831 // Make sure that the top context does not change when doing | |
| 13832 // callbacks or interceptor calls. | |
| 13833 AssertNoContextChange ncc(isolate); | |
| 13834 | |
| 13835 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor(), isolate); | |
| 13836 if (!interceptor->getter()->IsUndefined()) { | |
| 13837 v8::IndexedPropertyGetterCallback getter = | |
| 13838 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter()); | |
| 13839 LOG(isolate, | |
| 13840 ApiIndexedPropertyAccess("interceptor-indexed-get", *object, index)); | |
| 13841 PropertyCallbackArguments | |
| 13842 args(isolate, interceptor->data(), *receiver, *object); | |
| 13843 v8::Handle<v8::Value> result = args.Call(getter, index); | |
| 13844 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
| 13845 if (!result.IsEmpty()) { | |
| 13846 Handle<Object> result_internal = v8::Utils::OpenHandle(*result); | |
| 13847 result_internal->VerifyApiCallResultType(); | |
| 13848 // Rebox handle before return. | |
| 13849 return handle(*result_internal, isolate); | |
| 13850 } | |
| 13851 } | |
| 13852 | |
| 13853 if (!check_prototype) return MaybeHandle<Object>(); | |
| 13854 | |
| 13855 ElementsAccessor* handler = object->GetElementsAccessor(); | |
| 13856 Handle<Object> result; | |
| 13857 ASSIGN_RETURN_ON_EXCEPTION( | |
| 13858 isolate, result, handler->Get(receiver, object, index), | |
| 13859 Object); | |
| 13860 if (!result->IsTheHole()) return result; | |
| 13861 | |
| 13862 PrototypeIterator iter(isolate, object); | |
| 13863 if (iter.IsAtEnd()) return isolate->factory()->undefined_value(); | |
| 13864 return Object::GetElementWithReceiver( | |
| 13865 isolate, PrototypeIterator::GetCurrent(iter), receiver, index); | |
| 13866 } | |
| 13867 | |
| 13868 | |
| 13869 bool JSObject::HasDenseElements() { | 13703 bool JSObject::HasDenseElements() { |
| 13870 int capacity = 0; | 13704 int capacity = 0; |
| 13871 int used = 0; | 13705 int used = 0; |
| 13872 GetElementsCapacityAndUsage(&capacity, &used); | 13706 GetElementsCapacityAndUsage(&capacity, &used); |
| 13873 return (capacity == 0) || (used > (capacity / 2)); | 13707 return (capacity == 0) || (used > (capacity / 2)); |
| 13874 } | 13708 } |
| 13875 | 13709 |
| 13876 | 13710 |
| 13877 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { | 13711 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { |
| 13878 *capacity = 0; | 13712 *capacity = 0; |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14002 dictionary = SeededNumberDictionary::cast(elements); | 13836 dictionary = SeededNumberDictionary::cast(elements); |
| 14003 } | 13837 } |
| 14004 // If an element has been added at a very high index in the elements | 13838 // If an element has been added at a very high index in the elements |
| 14005 // dictionary, we cannot go back to fast case. | 13839 // dictionary, we cannot go back to fast case. |
| 14006 if (dictionary->requires_slow_elements()) return false; | 13840 if (dictionary->requires_slow_elements()) return false; |
| 14007 // If the dictionary backing storage takes up roughly half as much | 13841 // If the dictionary backing storage takes up roughly half as much |
| 14008 // space (in machine words) as a fast-case backing storage would, | 13842 // space (in machine words) as a fast-case backing storage would, |
| 14009 // the object should have fast elements. | 13843 // the object should have fast elements. |
| 14010 uint32_t array_size = 0; | 13844 uint32_t array_size = 0; |
| 14011 if (IsJSArray()) { | 13845 if (IsJSArray()) { |
| 14012 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size)); | 13846 CHECK(JSArray::cast(this)->length()->ToArrayLength(&array_size)); |
| 14013 } else { | 13847 } else { |
| 14014 array_size = dictionary->max_number_key(); | 13848 array_size = dictionary->max_number_key(); |
| 14015 } | 13849 } |
| 14016 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * | 13850 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * |
| 14017 SeededNumberDictionary::kEntrySize; | 13851 SeededNumberDictionary::kEntrySize; |
| 14018 return 2 * dictionary_size >= array_size; | 13852 return 2 * dictionary_size >= array_size; |
| 14019 } | 13853 } |
| 14020 | 13854 |
| 14021 | 13855 |
| 14022 bool JSObject::ShouldConvertToFastDoubleElements( | 13856 bool JSObject::ShouldConvertToFastDoubleElements( |
| (...skipping 3399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 17422 Handle<Object> new_value) { | 17256 Handle<Object> new_value) { |
| 17423 if (cell->value() != *new_value) { | 17257 if (cell->value() != *new_value) { |
| 17424 cell->set_value(*new_value); | 17258 cell->set_value(*new_value); |
| 17425 Isolate* isolate = cell->GetIsolate(); | 17259 Isolate* isolate = cell->GetIsolate(); |
| 17426 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 17260 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
| 17427 isolate, DependentCode::kPropertyCellChangedGroup); | 17261 isolate, DependentCode::kPropertyCellChangedGroup); |
| 17428 } | 17262 } |
| 17429 } | 17263 } |
| 17430 } // namespace internal | 17264 } // namespace internal |
| 17431 } // namespace v8 | 17265 } // namespace v8 |
| OLD | NEW |