| 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 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 599 auto curr = PrototypeIterator::GetCurrent(iter); | 599 auto curr = PrototypeIterator::GetCurrent(iter); |
| 600 if (!curr->IsJSObject()) break; | 600 if (!curr->IsJSObject()) break; |
| 601 auto obj = Handle<JSObject>::cast(curr); | 601 auto obj = Handle<JSObject>::cast(curr); |
| 602 if (!obj->HasIndexedInterceptor()) continue; | 602 if (!obj->HasIndexedInterceptor()) continue; |
| 603 if (obj->GetIndexedInterceptor()->all_can_read()) return obj; | 603 if (obj->GetIndexedInterceptor()->all_can_read()) return obj; |
| 604 } | 604 } |
| 605 return MaybeHandle<JSObject>(); | 605 return MaybeHandle<JSObject>(); |
| 606 } | 606 } |
| 607 | 607 |
| 608 | 608 |
| 609 MaybeHandle<Object> JSObject::GetElementWithFailedAccessCheck( | |
| 610 Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver, | |
| 611 uint32_t index) { | |
| 612 Handle<JSObject> holder = object; | |
| 613 PrototypeIterator::WhereToStart where_to_start = | |
| 614 PrototypeIterator::START_AT_RECEIVER; | |
| 615 while (true) { | |
| 616 auto all_can_read_holder = | |
| 617 FindIndexedAllCanReadHolder(isolate, holder, where_to_start); | |
| 618 if (!all_can_read_holder.ToHandle(&holder)) break; | |
| 619 auto result = | |
| 620 JSObject::GetElementWithInterceptor(holder, receiver, index, false); | |
| 621 if (isolate->has_scheduled_exception()) break; | |
| 622 if (!result.is_null()) return result; | |
| 623 where_to_start = PrototypeIterator::START_AT_PROTOTYPE; | |
| 624 } | |
| 625 isolate->ReportFailedAccessCheck(object); | |
| 626 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
| 627 return isolate->factory()->undefined_value(); | |
| 628 } | |
| 629 | |
| 630 | |
| 631 Maybe<PropertyAttributes> JSObject::GetElementAttributesWithFailedAccessCheck( | 609 Maybe<PropertyAttributes> JSObject::GetElementAttributesWithFailedAccessCheck( |
| 632 Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver, | 610 Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver, |
| 633 uint32_t index) { | 611 uint32_t index) { |
| 634 Handle<JSObject> holder = object; | 612 Handle<JSObject> holder = object; |
| 635 PrototypeIterator::WhereToStart where_to_start = | 613 PrototypeIterator::WhereToStart where_to_start = |
| 636 PrototypeIterator::START_AT_RECEIVER; | 614 PrototypeIterator::START_AT_RECEIVER; |
| 637 while (true) { | 615 while (true) { |
| 638 auto all_can_read_holder = | 616 auto all_can_read_holder = |
| 639 FindIndexedAllCanReadHolder(isolate, holder, where_to_start); | 617 FindIndexedAllCanReadHolder(isolate, holder, where_to_start); |
| 640 if (!all_can_read_holder.ToHandle(&holder)) break; | 618 if (!all_can_read_holder.ToHandle(&holder)) break; |
| 641 auto result = | 619 auto result = |
| 642 JSObject::GetElementAttributeFromInterceptor(holder, receiver, index); | 620 JSObject::GetElementAttributeFromInterceptor(holder, receiver, index); |
| 643 if (isolate->has_scheduled_exception()) break; | 621 if (isolate->has_scheduled_exception()) break; |
| 644 if (result.IsJust() && result.FromJust() != ABSENT) return result; | 622 if (result.IsJust() && result.FromJust() != ABSENT) return result; |
| 645 where_to_start = PrototypeIterator::START_AT_PROTOTYPE; | 623 where_to_start = PrototypeIterator::START_AT_PROTOTYPE; |
| 646 } | 624 } |
| 647 isolate->ReportFailedAccessCheck(object); | 625 isolate->ReportFailedAccessCheck(object); |
| 648 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); | 626 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<PropertyAttributes>()); |
| 649 return Just(ABSENT); | 627 return Just(ABSENT); |
| 650 } | 628 } |
| 651 | 629 |
| 652 | 630 |
| 653 MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate, | |
| 654 Handle<Object> object, | |
| 655 Handle<Object> receiver, | |
| 656 uint32_t index) { | |
| 657 DCHECK(!object->IsUndefined()); | |
| 658 | |
| 659 // Iterate up the prototype chain until an element is found or the null | |
| 660 // prototype is encountered. | |
| 661 for (PrototypeIterator iter(isolate, object, | |
| 662 object->IsJSProxy() || object->IsJSObject() | |
| 663 ? PrototypeIterator::START_AT_RECEIVER | |
| 664 : PrototypeIterator::START_AT_PROTOTYPE); | |
| 665 !iter.IsAtEnd(); iter.Advance()) { | |
| 666 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | |
| 667 return JSProxy::GetElementWithHandler( | |
| 668 Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), receiver, | |
| 669 index); | |
| 670 } | |
| 671 | |
| 672 // Inline the case for JSObjects. Doing so significantly improves the | |
| 673 // performance of fetching elements where checking the prototype chain is | |
| 674 // necessary. | |
| 675 Handle<JSObject> js_object = | |
| 676 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)); | |
| 677 | |
| 678 // Check access rights if needed. | |
| 679 if (js_object->IsAccessCheckNeeded()) { | |
| 680 if (!isolate->MayAccess(js_object)) { | |
| 681 return JSObject::GetElementWithFailedAccessCheck(isolate, js_object, | |
| 682 receiver, index); | |
| 683 } | |
| 684 } | |
| 685 | |
| 686 if (js_object->HasIndexedInterceptor()) { | |
| 687 return JSObject::GetElementWithInterceptor(js_object, receiver, index, | |
| 688 true); | |
| 689 } | |
| 690 | |
| 691 if (js_object->elements() != isolate->heap()->empty_fixed_array()) { | |
| 692 Handle<Object> result; | |
| 693 ASSIGN_RETURN_ON_EXCEPTION( | |
| 694 isolate, result, | |
| 695 js_object->GetElementsAccessor()->Get(receiver, js_object, index), | |
| 696 Object); | |
| 697 if (!result->IsTheHole()) return result; | |
| 698 } | |
| 699 } | |
| 700 | |
| 701 return isolate->factory()->undefined_value(); | |
| 702 } | |
| 703 | |
| 704 | |
| 705 MaybeHandle<Object> Object::SetElementWithReceiver( | 631 MaybeHandle<Object> Object::SetElementWithReceiver( |
| 706 Isolate* isolate, Handle<Object> object, Handle<Object> receiver, | 632 Isolate* isolate, Handle<Object> object, Handle<Object> receiver, |
| 707 uint32_t index, Handle<Object> value, LanguageMode language_mode) { | 633 uint32_t index, Handle<Object> value, LanguageMode language_mode) { |
| 708 // Iterate up the prototype chain until an element is found or the null | 634 // Iterate up the prototype chain until an element is found or the null |
| 709 // prototype is encountered. | 635 // prototype is encountered. |
| 710 bool done = false; | 636 bool done = false; |
| 711 for (PrototypeIterator iter(isolate, object, | 637 for (PrototypeIterator iter(isolate, object, |
| 712 object->IsJSProxy() || object->IsJSObject() | 638 object->IsJSProxy() || object->IsJSObject() |
| 713 ? PrototypeIterator::START_AT_RECEIVER | 639 ? PrototypeIterator::START_AT_RECEIVER |
| 714 : PrototypeIterator::START_AT_PROTOTYPE); | 640 : PrototypeIterator::START_AT_PROTOTYPE); |
| (...skipping 7493 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8208 GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>( | 8134 GetHeap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>( |
| 8209 this, length() - new_length); | 8135 this, length() - new_length); |
| 8210 } | 8136 } |
| 8211 } | 8137 } |
| 8212 | 8138 |
| 8213 | 8139 |
| 8214 MaybeHandle<FixedArray> FixedArray::AddKeysFromArrayLike( | 8140 MaybeHandle<FixedArray> FixedArray::AddKeysFromArrayLike( |
| 8215 Handle<FixedArray> content, Handle<JSObject> array, KeyFilter filter) { | 8141 Handle<FixedArray> content, Handle<JSObject> array, KeyFilter filter) { |
| 8216 DCHECK(array->IsJSArray() || array->HasSloppyArgumentsElements()); | 8142 DCHECK(array->IsJSArray() || array->HasSloppyArgumentsElements()); |
| 8217 ElementsAccessor* accessor = array->GetElementsAccessor(); | 8143 ElementsAccessor* accessor = array->GetElementsAccessor(); |
| 8218 Handle<FixedArray> result; | 8144 Handle<FixedArray> result = |
| 8219 ASSIGN_RETURN_ON_EXCEPTION( | 8145 accessor->AddElementsToFixedArray(array, content, filter); |
| 8220 array->GetIsolate(), result, | |
| 8221 accessor->AddElementsToFixedArray(array, content, filter), FixedArray); | |
| 8222 | 8146 |
| 8223 #ifdef ENABLE_SLOW_DCHECKS | 8147 #ifdef ENABLE_SLOW_DCHECKS |
| 8224 if (FLAG_enable_slow_asserts) { | 8148 if (FLAG_enable_slow_asserts) { |
| 8225 DisallowHeapAllocation no_allocation; | 8149 DisallowHeapAllocation no_allocation; |
| 8226 for (int i = 0; i < result->length(); i++) { | 8150 for (int i = 0; i < result->length(); i++) { |
| 8227 Object* current = result->get(i); | 8151 Object* current = result->get(i); |
| 8228 DCHECK(current->IsNumber() || current->IsName()); | 8152 DCHECK(current->IsNumber() || current->IsName()); |
| 8229 } | 8153 } |
| 8230 } | 8154 } |
| 8231 #endif | 8155 #endif |
| (...skipping 4005 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12237 DCHECK(array->AllowsSetElementsLength()); | 12161 DCHECK(array->AllowsSetElementsLength()); |
| 12238 if (!array->map()->is_observed()) { | 12162 if (!array->map()->is_observed()) { |
| 12239 return array->GetElementsAccessor()->SetLength(array, new_length_handle); | 12163 return array->GetElementsAccessor()->SetLength(array, new_length_handle); |
| 12240 } | 12164 } |
| 12241 | 12165 |
| 12242 Isolate* isolate = array->GetIsolate(); | 12166 Isolate* isolate = array->GetIsolate(); |
| 12243 List<uint32_t> indices; | 12167 List<uint32_t> indices; |
| 12244 List<Handle<Object> > old_values; | 12168 List<Handle<Object> > old_values; |
| 12245 Handle<Object> old_length_handle(array->length(), isolate); | 12169 Handle<Object> old_length_handle(array->length(), isolate); |
| 12246 uint32_t old_length = 0; | 12170 uint32_t old_length = 0; |
| 12247 CHECK(old_length_handle->ToArrayIndex(&old_length)); | 12171 CHECK(old_length_handle->ToArrayLength(&old_length)); |
| 12248 uint32_t new_length = 0; | 12172 uint32_t new_length = 0; |
| 12249 CHECK(new_length_handle->ToArrayIndex(&new_length)); | 12173 CHECK(new_length_handle->ToArrayLength(&new_length)); |
| 12250 | 12174 |
| 12251 static const PropertyAttributes kNoAttrFilter = NONE; | 12175 static const PropertyAttributes kNoAttrFilter = NONE; |
| 12252 int num_elements = array->NumberOfOwnElements(kNoAttrFilter); | 12176 int num_elements = array->NumberOfOwnElements(kNoAttrFilter); |
| 12253 if (num_elements > 0) { | 12177 if (num_elements > 0) { |
| 12254 if (old_length == static_cast<uint32_t>(num_elements)) { | 12178 if (old_length == static_cast<uint32_t>(num_elements)) { |
| 12255 // Simple case for arrays without holes. | 12179 // Simple case for arrays without holes. |
| 12256 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) { | 12180 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) { |
| 12257 if (!GetOldValue(isolate, array, i, &old_values, &indices)) break; | 12181 if (!GetOldValue(isolate, array, i, &old_values, &indices)) break; |
| 12258 } | 12182 } |
| 12259 } else { | 12183 } else { |
| 12260 // For sparse arrays, only iterate over existing elements. | 12184 // For sparse arrays, only iterate over existing elements. |
| 12261 // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over | 12185 // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over |
| 12262 // the to-be-removed indices twice. | 12186 // the to-be-removed indices twice. |
| 12263 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements); | 12187 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements); |
| 12264 array->GetOwnElementKeys(*keys, kNoAttrFilter); | 12188 array->GetOwnElementKeys(*keys, kNoAttrFilter); |
| 12265 while (num_elements-- > 0) { | 12189 while (num_elements-- > 0) { |
| 12266 uint32_t index = NumberToUint32(keys->get(num_elements)); | 12190 uint32_t index = NumberToUint32(keys->get(num_elements)); |
| 12267 if (index < new_length) break; | 12191 if (index < new_length) break; |
| 12268 if (!GetOldValue(isolate, array, index, &old_values, &indices)) break; | 12192 if (!GetOldValue(isolate, array, index, &old_values, &indices)) break; |
| 12269 } | 12193 } |
| 12270 } | 12194 } |
| 12271 } | 12195 } |
| 12272 | 12196 |
| 12273 Handle<Object> hresult; | 12197 Handle<Object> hresult; |
| 12274 ASSIGN_RETURN_ON_EXCEPTION( | 12198 ASSIGN_RETURN_ON_EXCEPTION( |
| 12275 isolate, hresult, | 12199 isolate, hresult, |
| 12276 array->GetElementsAccessor()->SetLength(array, new_length_handle), | 12200 array->GetElementsAccessor()->SetLength(array, new_length_handle), |
| 12277 Object); | 12201 Object); |
| 12278 | 12202 |
| 12279 CHECK(array->length()->ToArrayIndex(&new_length)); | 12203 CHECK(array->length()->ToArrayLength(&new_length)); |
| 12280 if (old_length == new_length) return hresult; | 12204 if (old_length == new_length) return hresult; |
| 12281 | 12205 |
| 12282 RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object); | 12206 RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object); |
| 12283 | 12207 |
| 12284 for (int i = 0; i < indices.length(); ++i) { | 12208 for (int i = 0; i < indices.length(); ++i) { |
| 12285 // For deletions where the property was an accessor, old_values[i] | 12209 // For deletions where the property was an accessor, old_values[i] |
| 12286 // will be the hole, which instructs EnqueueChangeRecord to elide | 12210 // will be the hole, which instructs EnqueueChangeRecord to elide |
| 12287 // the "oldValue" property. | 12211 // the "oldValue" property. |
| 12288 RETURN_ON_EXCEPTION( | 12212 RETURN_ON_EXCEPTION( |
| 12289 isolate, | 12213 isolate, |
| (...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12758 args.Call(setter, index, v8::Utils::ToLocal(value)); | 12682 args.Call(setter, index, v8::Utils::ToLocal(value)); |
| 12759 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | 12683 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
| 12760 if (!result.IsEmpty()) return value; | 12684 if (!result.IsEmpty()) return value; |
| 12761 } | 12685 } |
| 12762 | 12686 |
| 12763 return SetElementWithoutInterceptor(object, index, value, attributes, | 12687 return SetElementWithoutInterceptor(object, index, value, attributes, |
| 12764 language_mode, check_prototype, set_mode); | 12688 language_mode, check_prototype, set_mode); |
| 12765 } | 12689 } |
| 12766 | 12690 |
| 12767 | 12691 |
| 12768 MaybeHandle<Object> JSObject::GetElementWithCallback( | |
| 12769 Handle<JSObject> object, | |
| 12770 Handle<Object> receiver, | |
| 12771 Handle<Object> structure, | |
| 12772 uint32_t index, | |
| 12773 Handle<Object> holder) { | |
| 12774 Isolate* isolate = object->GetIsolate(); | |
| 12775 DCHECK(!structure->IsForeign()); | |
| 12776 // api style callbacks. | |
| 12777 if (structure->IsExecutableAccessorInfo()) { | |
| 12778 Handle<ExecutableAccessorInfo> data = | |
| 12779 Handle<ExecutableAccessorInfo>::cast(structure); | |
| 12780 Object* fun_obj = data->getter(); | |
| 12781 v8::AccessorNameGetterCallback call_fun = | |
| 12782 v8::ToCData<v8::AccessorNameGetterCallback>(fun_obj); | |
| 12783 if (call_fun == NULL) return isolate->factory()->undefined_value(); | |
| 12784 Handle<JSObject> holder_handle = Handle<JSObject>::cast(holder); | |
| 12785 Handle<String> key = isolate->factory()->Uint32ToString(index); | |
| 12786 LOG(isolate, ApiNamedPropertyAccess("load", *holder_handle, *key)); | |
| 12787 PropertyCallbackArguments | |
| 12788 args(isolate, data->data(), *receiver, *holder_handle); | |
| 12789 v8::Handle<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(key)); | |
| 12790 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
| 12791 if (result.IsEmpty()) return isolate->factory()->undefined_value(); | |
| 12792 Handle<Object> result_internal = v8::Utils::OpenHandle(*result); | |
| 12793 result_internal->VerifyApiCallResultType(); | |
| 12794 // Rebox handle before return. | |
| 12795 return handle(*result_internal, isolate); | |
| 12796 } | |
| 12797 | |
| 12798 // __defineGetter__ callback | |
| 12799 if (structure->IsAccessorPair()) { | |
| 12800 Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(), | |
| 12801 isolate); | |
| 12802 if (getter->IsSpecFunction()) { | |
| 12803 // TODO(rossberg): nicer would be to cast to some JSCallable here... | |
| 12804 return GetPropertyWithDefinedGetter( | |
| 12805 receiver, Handle<JSReceiver>::cast(getter)); | |
| 12806 } | |
| 12807 // Getter is not a function. | |
| 12808 return isolate->factory()->undefined_value(); | |
| 12809 } | |
| 12810 | |
| 12811 UNREACHABLE(); | |
| 12812 return MaybeHandle<Object>(); | |
| 12813 } | |
| 12814 | |
| 12815 | |
| 12816 MaybeHandle<Object> JSObject::SetElementWithCallback( | 12692 MaybeHandle<Object> JSObject::SetElementWithCallback( |
| 12817 Handle<Object> object, Handle<Object> structure, uint32_t index, | 12693 Handle<Object> object, Handle<Object> structure, uint32_t index, |
| 12818 Handle<Object> value, Handle<JSObject> holder, LanguageMode language_mode) { | 12694 Handle<Object> value, Handle<JSObject> holder, LanguageMode language_mode) { |
| 12819 Isolate* isolate = holder->GetIsolate(); | 12695 Isolate* isolate = holder->GetIsolate(); |
| 12820 | 12696 |
| 12821 // We should never get here to initialize a const with the hole | 12697 // We should never get here to initialize a const with the hole |
| 12822 // value since a const declaration would conflict with the setter. | 12698 // value since a const declaration would conflict with the setter. |
| 12823 DCHECK(!value->IsTheHole()); | 12699 DCHECK(!value->IsTheHole()); |
| 12824 DCHECK(!structure->IsForeign()); | 12700 DCHECK(!structure->IsForeign()); |
| 12825 if (structure->IsExecutableAccessorInfo()) { | 12701 if (structure->IsExecutableAccessorInfo()) { |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12920 object, index, value, &found, language_mode); | 12796 object, index, value, &found, language_mode); |
| 12921 if (found) return result; | 12797 if (found) return result; |
| 12922 } | 12798 } |
| 12923 | 12799 |
| 12924 uint32_t new_capacity = capacity; | 12800 uint32_t new_capacity = capacity; |
| 12925 // Check if the length property of this object needs to be updated. | 12801 // Check if the length property of this object needs to be updated. |
| 12926 uint32_t array_length = 0; | 12802 uint32_t array_length = 0; |
| 12927 bool must_update_array_length = false; | 12803 bool must_update_array_length = false; |
| 12928 bool introduces_holes = true; | 12804 bool introduces_holes = true; |
| 12929 if (object->IsJSArray()) { | 12805 if (object->IsJSArray()) { |
| 12930 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length)); | 12806 CHECK( |
| 12807 Handle<JSArray>::cast(object)->length()->ToArrayLength(&array_length)); |
| 12931 introduces_holes = index > array_length; | 12808 introduces_holes = index > array_length; |
| 12932 if (index >= array_length) { | 12809 if (index >= array_length) { |
| 12933 must_update_array_length = true; | 12810 must_update_array_length = true; |
| 12934 array_length = index + 1; | 12811 array_length = index + 1; |
| 12935 } | 12812 } |
| 12936 } else { | 12813 } else { |
| 12937 introduces_holes = index >= capacity; | 12814 introduces_holes = index >= capacity; |
| 12938 } | 12815 } |
| 12939 | 12816 |
| 12940 // If the array is growing, and it's not growth by a single element at the | 12817 // 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... |
| 13115 // Update the array length if this JSObject is an array. | 12992 // Update the array length if this JSObject is an array. |
| 13116 if (object->IsJSArray()) { | 12993 if (object->IsJSArray()) { |
| 13117 JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray>::cast(object), index, | 12994 JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray>::cast(object), index, |
| 13118 value); | 12995 value); |
| 13119 } | 12996 } |
| 13120 | 12997 |
| 13121 // Attempt to put this object back in fast case. | 12998 // Attempt to put this object back in fast case. |
| 13122 if (object->ShouldConvertToFastElements()) { | 12999 if (object->ShouldConvertToFastElements()) { |
| 13123 uint32_t new_length = 0; | 13000 uint32_t new_length = 0; |
| 13124 if (object->IsJSArray()) { | 13001 if (object->IsJSArray()) { |
| 13125 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&new_length)); | 13002 CHECK( |
| 13003 Handle<JSArray>::cast(object)->length()->ToArrayLength(&new_length)); |
| 13126 } else { | 13004 } else { |
| 13127 new_length = dictionary->max_number_key() + 1; | 13005 new_length = dictionary->max_number_key() + 1; |
| 13128 } | 13006 } |
| 13129 bool has_smi_only_elements = false; | 13007 bool has_smi_only_elements = false; |
| 13130 bool should_convert_to_fast_double_elements = | 13008 bool should_convert_to_fast_double_elements = |
| 13131 object->ShouldConvertToFastDoubleElements(&has_smi_only_elements); | 13009 object->ShouldConvertToFastDoubleElements(&has_smi_only_elements); |
| 13132 SetFastElementsCapacitySmiMode smi_mode = | 13010 SetFastElementsCapacitySmiMode smi_mode = |
| 13133 has_smi_only_elements ? kForceSmiElements : kAllowSmiElements; | 13011 has_smi_only_elements ? kForceSmiElements : kAllowSmiElements; |
| 13134 | 13012 |
| 13135 if (should_convert_to_fast_double_elements) { | 13013 if (should_convert_to_fast_double_elements) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13170 object, index, value, &found, language_mode); | 13048 object, index, value, &found, language_mode); |
| 13171 if (found) return result; | 13049 if (found) return result; |
| 13172 } | 13050 } |
| 13173 | 13051 |
| 13174 // If the value object is not a heap number, switch to fast elements and try | 13052 // If the value object is not a heap number, switch to fast elements and try |
| 13175 // again. | 13053 // again. |
| 13176 bool value_is_smi = value->IsSmi(); | 13054 bool value_is_smi = value->IsSmi(); |
| 13177 bool introduces_holes = true; | 13055 bool introduces_holes = true; |
| 13178 uint32_t length = elms_length; | 13056 uint32_t length = elms_length; |
| 13179 if (object->IsJSArray()) { | 13057 if (object->IsJSArray()) { |
| 13180 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&length)); | 13058 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength(&length)); |
| 13181 introduces_holes = index > length; | 13059 introduces_holes = index > length; |
| 13182 } else { | 13060 } else { |
| 13183 introduces_holes = index >= elms_length; | 13061 introduces_holes = index >= elms_length; |
| 13184 } | 13062 } |
| 13185 | 13063 |
| 13186 if (!value->IsNumber()) { | 13064 if (!value->IsNumber()) { |
| 13187 SetFastElementsCapacityAndLength(object, elms_length, length, | 13065 SetFastElementsCapacityAndLength(object, elms_length, length, |
| 13188 kDontAllowSmiElements); | 13066 kDontAllowSmiElements); |
| 13189 Handle<Object> result; | 13067 Handle<Object> result; |
| 13190 ASSIGN_RETURN_ON_EXCEPTION( | 13068 ASSIGN_RETURN_ON_EXCEPTION( |
| (...skipping 16 matching lines...) Expand all Loading... |
| 13207 TransitionElementsKind(object, transitioned_kind); | 13085 TransitionElementsKind(object, transitioned_kind); |
| 13208 } | 13086 } |
| 13209 | 13087 |
| 13210 // Check whether there is extra space in the fixed array. | 13088 // Check whether there is extra space in the fixed array. |
| 13211 if (index < elms_length) { | 13089 if (index < elms_length) { |
| 13212 Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements())); | 13090 Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements())); |
| 13213 elms->set(index, double_value); | 13091 elms->set(index, double_value); |
| 13214 if (object->IsJSArray()) { | 13092 if (object->IsJSArray()) { |
| 13215 // Update the length of the array if needed. | 13093 // Update the length of the array if needed. |
| 13216 uint32_t array_length = 0; | 13094 uint32_t array_length = 0; |
| 13217 CHECK( | 13095 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayLength( |
| 13218 Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length)); | 13096 &array_length)); |
| 13219 if (index >= array_length) { | 13097 if (index >= array_length) { |
| 13220 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1)); | 13098 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1)); |
| 13221 } | 13099 } |
| 13222 } | 13100 } |
| 13223 return value; | 13101 return value; |
| 13224 } | 13102 } |
| 13225 | 13103 |
| 13226 // Allow gap in fast case. | 13104 // Allow gap in fast case. |
| 13227 if ((index - elms_length) < kMaxGap) { | 13105 if ((index - elms_length) < kMaxGap) { |
| 13228 // Try allocating extra space. | 13106 // Try allocating extra space. |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13369 PropertyAttributes new_attributes = maybe.FromJust(); | 13247 PropertyAttributes new_attributes = maybe.FromJust(); |
| 13370 | 13248 |
| 13371 if (old_attributes == ABSENT) { | 13249 if (old_attributes == ABSENT) { |
| 13372 if (object->IsJSArray() && | 13250 if (object->IsJSArray() && |
| 13373 !old_length_handle->SameValue( | 13251 !old_length_handle->SameValue( |
| 13374 Handle<JSArray>::cast(object)->length())) { | 13252 Handle<JSArray>::cast(object)->length())) { |
| 13375 new_length_handle = handle(Handle<JSArray>::cast(object)->length(), | 13253 new_length_handle = handle(Handle<JSArray>::cast(object)->length(), |
| 13376 isolate); | 13254 isolate); |
| 13377 uint32_t old_length = 0; | 13255 uint32_t old_length = 0; |
| 13378 uint32_t new_length = 0; | 13256 uint32_t new_length = 0; |
| 13379 CHECK(old_length_handle->ToArrayIndex(&old_length)); | 13257 CHECK(old_length_handle->ToArrayLength(&old_length)); |
| 13380 CHECK(new_length_handle->ToArrayIndex(&new_length)); | 13258 CHECK(new_length_handle->ToArrayLength(&new_length)); |
| 13381 | 13259 |
| 13382 RETURN_ON_EXCEPTION( | 13260 RETURN_ON_EXCEPTION( |
| 13383 isolate, BeginPerformSplice(Handle<JSArray>::cast(object)), Object); | 13261 isolate, BeginPerformSplice(Handle<JSArray>::cast(object)), Object); |
| 13384 RETURN_ON_EXCEPTION( | 13262 RETURN_ON_EXCEPTION( |
| 13385 isolate, EnqueueChangeRecord(object, "add", name, old_value), Object); | 13263 isolate, EnqueueChangeRecord(object, "add", name, old_value), Object); |
| 13386 RETURN_ON_EXCEPTION( | 13264 RETURN_ON_EXCEPTION( |
| 13387 isolate, EnqueueChangeRecord(object, "update", | 13265 isolate, EnqueueChangeRecord(object, "update", |
| 13388 isolate->factory()->length_string(), | 13266 isolate->factory()->length_string(), |
| 13389 old_length_handle), | 13267 old_length_handle), |
| 13390 Object); | 13268 Object); |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13558 handle(JSArray::cast(site->transition_info())); | 13436 handle(JSArray::cast(site->transition_info())); |
| 13559 ElementsKind kind = transition_info->GetElementsKind(); | 13437 ElementsKind kind = transition_info->GetElementsKind(); |
| 13560 // if kind is holey ensure that to_kind is as well. | 13438 // if kind is holey ensure that to_kind is as well. |
| 13561 if (IsHoleyElementsKind(kind)) { | 13439 if (IsHoleyElementsKind(kind)) { |
| 13562 to_kind = GetHoleyElementsKind(to_kind); | 13440 to_kind = GetHoleyElementsKind(to_kind); |
| 13563 } | 13441 } |
| 13564 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { | 13442 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) { |
| 13565 // If the array is huge, it's not likely to be defined in a local | 13443 // If the array is huge, it's not likely to be defined in a local |
| 13566 // function, so we shouldn't make new instances of it very often. | 13444 // function, so we shouldn't make new instances of it very often. |
| 13567 uint32_t length = 0; | 13445 uint32_t length = 0; |
| 13568 CHECK(transition_info->length()->ToArrayIndex(&length)); | 13446 CHECK(transition_info->length()->ToArrayLength(&length)); |
| 13569 if (length <= kMaximumArrayBytesToPretransition) { | 13447 if (length <= kMaximumArrayBytesToPretransition) { |
| 13570 if (FLAG_trace_track_allocation_sites) { | 13448 if (FLAG_trace_track_allocation_sites) { |
| 13571 bool is_nested = site->IsNestedSite(); | 13449 bool is_nested = site->IsNestedSite(); |
| 13572 PrintF( | 13450 PrintF( |
| 13573 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n", | 13451 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n", |
| 13574 reinterpret_cast<void*>(*site), | 13452 reinterpret_cast<void*>(*site), |
| 13575 is_nested ? "(nested)" : "", | 13453 is_nested ? "(nested)" : "", |
| 13576 ElementsKindToString(kind), | 13454 ElementsKindToString(kind), |
| 13577 ElementsKindToString(to_kind)); | 13455 ElementsKindToString(to_kind)); |
| 13578 } | 13456 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13672 uint32_t capacity = static_cast<uint32_t>(elms->length()); | 13550 uint32_t capacity = static_cast<uint32_t>(elms->length()); |
| 13673 uint32_t length = capacity; | 13551 uint32_t length = capacity; |
| 13674 | 13552 |
| 13675 if (object->IsJSArray()) { | 13553 if (object->IsJSArray()) { |
| 13676 Object* raw_length = Handle<JSArray>::cast(object)->length(); | 13554 Object* raw_length = Handle<JSArray>::cast(object)->length(); |
| 13677 if (raw_length->IsUndefined()) { | 13555 if (raw_length->IsUndefined()) { |
| 13678 // If length is undefined, then JSArray is being initialized and has no | 13556 // If length is undefined, then JSArray is being initialized and has no |
| 13679 // elements, assume a length of zero. | 13557 // elements, assume a length of zero. |
| 13680 length = 0; | 13558 length = 0; |
| 13681 } else { | 13559 } else { |
| 13682 CHECK(raw_length->ToArrayIndex(&length)); | 13560 CHECK(raw_length->ToArrayLength(&length)); |
| 13683 } | 13561 } |
| 13684 } | 13562 } |
| 13685 | 13563 |
| 13686 if (IsFastSmiElementsKind(from_kind) && | 13564 if (IsFastSmiElementsKind(from_kind) && |
| 13687 IsFastDoubleElementsKind(to_kind)) { | 13565 IsFastDoubleElementsKind(to_kind)) { |
| 13688 SetFastDoubleElementsCapacityAndLength(object, capacity, length); | 13566 SetFastDoubleElementsCapacityAndLength(object, capacity, length); |
| 13689 JSObject::ValidateElements(object); | 13567 JSObject::ValidateElements(object); |
| 13690 return; | 13568 return; |
| 13691 } | 13569 } |
| 13692 | 13570 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 13715 // Transitions from HOLEY -> PACKED are not allowed. | 13593 // Transitions from HOLEY -> PACKED are not allowed. |
| 13716 return !IsFastHoleyElementsKind(from_kind) || | 13594 return !IsFastHoleyElementsKind(from_kind) || |
| 13717 IsFastHoleyElementsKind(to_kind); | 13595 IsFastHoleyElementsKind(to_kind); |
| 13718 } | 13596 } |
| 13719 | 13597 |
| 13720 | 13598 |
| 13721 void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array, | 13599 void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array, |
| 13722 uint32_t index, | 13600 uint32_t index, |
| 13723 Handle<Object> value) { | 13601 Handle<Object> value) { |
| 13724 uint32_t old_len = 0; | 13602 uint32_t old_len = 0; |
| 13725 CHECK(array->length()->ToArrayIndex(&old_len)); | 13603 CHECK(array->length()->ToArrayLength(&old_len)); |
| 13726 // Check to see if we need to update the length. For now, we make | 13604 // Check to see if we need to update the length. For now, we make |
| 13727 // sure that the length stays within 32-bits (unsigned). | 13605 // sure that the length stays within 32-bits (unsigned). |
| 13728 if (index >= old_len && index != 0xffffffff) { | 13606 if (index >= old_len && index != 0xffffffff) { |
| 13729 Handle<Object> len = array->GetIsolate()->factory()->NewNumber( | 13607 Handle<Object> len = array->GetIsolate()->factory()->NewNumber( |
| 13730 static_cast<double>(index) + 1); | 13608 static_cast<double>(index) + 1); |
| 13731 array->set_length(*len); | 13609 array->set_length(*len); |
| 13732 } | 13610 } |
| 13733 } | 13611 } |
| 13734 | 13612 |
| 13735 | 13613 |
| 13736 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) { | 13614 bool JSArray::HasReadOnlyLength(Handle<JSArray> array) { |
| 13737 LookupIterator it(array, array->GetIsolate()->factory()->length_string(), | 13615 LookupIterator it(array, array->GetIsolate()->factory()->length_string(), |
| 13738 LookupIterator::OWN_SKIP_INTERCEPTOR); | 13616 LookupIterator::OWN_SKIP_INTERCEPTOR); |
| 13739 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state()); | 13617 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state()); |
| 13740 CHECK(it.IsFound()); | 13618 CHECK(it.IsFound()); |
| 13741 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); | 13619 CHECK_EQ(LookupIterator::ACCESSOR, it.state()); |
| 13742 return it.IsReadOnly(); | 13620 return it.IsReadOnly(); |
| 13743 } | 13621 } |
| 13744 | 13622 |
| 13745 | 13623 |
| 13746 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array, | 13624 bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array, |
| 13747 uint32_t index) { | 13625 uint32_t index) { |
| 13748 uint32_t length = 0; | 13626 uint32_t length = 0; |
| 13749 CHECK(array->length()->ToArrayIndex(&length)); | 13627 CHECK(array->length()->ToArrayLength(&length)); |
| 13750 if (length <= index) return HasReadOnlyLength(array); | 13628 if (length <= index) return HasReadOnlyLength(array); |
| 13751 return false; | 13629 return false; |
| 13752 } | 13630 } |
| 13753 | 13631 |
| 13754 | 13632 |
| 13755 MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) { | 13633 MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) { |
| 13756 Isolate* isolate = array->GetIsolate(); | 13634 Isolate* isolate = array->GetIsolate(); |
| 13757 Handle<Name> length = isolate->factory()->length_string(); | 13635 Handle<Name> length = isolate->factory()->length_string(); |
| 13758 THROW_NEW_ERROR( | 13636 THROW_NEW_ERROR( |
| 13759 isolate, | 13637 isolate, |
| 13760 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, length, array), | 13638 NewTypeError(MessageTemplate::kStrictReadOnlyProperty, length, array), |
| 13761 Object); | 13639 Object); |
| 13762 } | 13640 } |
| 13763 | 13641 |
| 13764 | 13642 |
| 13765 MaybeHandle<Object> JSObject::GetElementWithInterceptor(Handle<JSObject> object, | |
| 13766 Handle<Object> receiver, | |
| 13767 uint32_t index, | |
| 13768 bool check_prototype) { | |
| 13769 Isolate* isolate = object->GetIsolate(); | |
| 13770 | |
| 13771 // Make sure that the top context does not change when doing | |
| 13772 // callbacks or interceptor calls. | |
| 13773 AssertNoContextChange ncc(isolate); | |
| 13774 | |
| 13775 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor(), isolate); | |
| 13776 if (!interceptor->getter()->IsUndefined()) { | |
| 13777 v8::IndexedPropertyGetterCallback getter = | |
| 13778 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter()); | |
| 13779 LOG(isolate, | |
| 13780 ApiIndexedPropertyAccess("interceptor-indexed-get", *object, index)); | |
| 13781 PropertyCallbackArguments | |
| 13782 args(isolate, interceptor->data(), *receiver, *object); | |
| 13783 v8::Handle<v8::Value> result = args.Call(getter, index); | |
| 13784 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); | |
| 13785 if (!result.IsEmpty()) { | |
| 13786 Handle<Object> result_internal = v8::Utils::OpenHandle(*result); | |
| 13787 result_internal->VerifyApiCallResultType(); | |
| 13788 // Rebox handle before return. | |
| 13789 return handle(*result_internal, isolate); | |
| 13790 } | |
| 13791 } | |
| 13792 | |
| 13793 if (!check_prototype) return MaybeHandle<Object>(); | |
| 13794 | |
| 13795 ElementsAccessor* handler = object->GetElementsAccessor(); | |
| 13796 Handle<Object> result; | |
| 13797 ASSIGN_RETURN_ON_EXCEPTION( | |
| 13798 isolate, result, handler->Get(receiver, object, index), | |
| 13799 Object); | |
| 13800 if (!result->IsTheHole()) return result; | |
| 13801 | |
| 13802 PrototypeIterator iter(isolate, object); | |
| 13803 if (iter.IsAtEnd()) return isolate->factory()->undefined_value(); | |
| 13804 return Object::GetElementWithReceiver( | |
| 13805 isolate, PrototypeIterator::GetCurrent(iter), receiver, index); | |
| 13806 } | |
| 13807 | |
| 13808 | |
| 13809 bool JSObject::HasDenseElements() { | 13643 bool JSObject::HasDenseElements() { |
| 13810 int capacity = 0; | 13644 int capacity = 0; |
| 13811 int used = 0; | 13645 int used = 0; |
| 13812 GetElementsCapacityAndUsage(&capacity, &used); | 13646 GetElementsCapacityAndUsage(&capacity, &used); |
| 13813 return (capacity == 0) || (used > (capacity / 2)); | 13647 return (capacity == 0) || (used > (capacity / 2)); |
| 13814 } | 13648 } |
| 13815 | 13649 |
| 13816 | 13650 |
| 13817 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { | 13651 void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) { |
| 13818 *capacity = 0; | 13652 *capacity = 0; |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13942 dictionary = SeededNumberDictionary::cast(elements); | 13776 dictionary = SeededNumberDictionary::cast(elements); |
| 13943 } | 13777 } |
| 13944 // If an element has been added at a very high index in the elements | 13778 // If an element has been added at a very high index in the elements |
| 13945 // dictionary, we cannot go back to fast case. | 13779 // dictionary, we cannot go back to fast case. |
| 13946 if (dictionary->requires_slow_elements()) return false; | 13780 if (dictionary->requires_slow_elements()) return false; |
| 13947 // If the dictionary backing storage takes up roughly half as much | 13781 // If the dictionary backing storage takes up roughly half as much |
| 13948 // space (in machine words) as a fast-case backing storage would, | 13782 // space (in machine words) as a fast-case backing storage would, |
| 13949 // the object should have fast elements. | 13783 // the object should have fast elements. |
| 13950 uint32_t array_size = 0; | 13784 uint32_t array_size = 0; |
| 13951 if (IsJSArray()) { | 13785 if (IsJSArray()) { |
| 13952 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size)); | 13786 CHECK(JSArray::cast(this)->length()->ToArrayLength(&array_size)); |
| 13953 } else { | 13787 } else { |
| 13954 array_size = dictionary->max_number_key(); | 13788 array_size = dictionary->max_number_key(); |
| 13955 } | 13789 } |
| 13956 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * | 13790 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) * |
| 13957 SeededNumberDictionary::kEntrySize; | 13791 SeededNumberDictionary::kEntrySize; |
| 13958 return 2 * dictionary_size >= array_size; | 13792 return 2 * dictionary_size >= array_size; |
| 13959 } | 13793 } |
| 13960 | 13794 |
| 13961 | 13795 |
| 13962 bool JSObject::ShouldConvertToFastDoubleElements( | 13796 bool JSObject::ShouldConvertToFastDoubleElements( |
| (...skipping 3365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 17328 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell, | 17162 void PropertyCell::SetValueWithInvalidation(Handle<PropertyCell> cell, |
| 17329 Handle<Object> new_value) { | 17163 Handle<Object> new_value) { |
| 17330 if (cell->value() != *new_value) { | 17164 if (cell->value() != *new_value) { |
| 17331 cell->set_value(*new_value); | 17165 cell->set_value(*new_value); |
| 17332 Isolate* isolate = cell->GetIsolate(); | 17166 Isolate* isolate = cell->GetIsolate(); |
| 17333 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 17167 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
| 17334 isolate, DependentCode::kPropertyCellChangedGroup); | 17168 isolate, DependentCode::kPropertyCellChangedGroup); |
| 17335 } | 17169 } |
| 17336 } | 17170 } |
| 17337 } } // namespace v8::internal | 17171 } } // namespace v8::internal |
| OLD | NEW |