Chromium Code Reviews| Index: src/elements.cc |
| diff --git a/src/elements.cc b/src/elements.cc |
| index 16e8b067cf9273b15fc0dd291b4ad0471d47a721..c73939e992eba771dea13c868f43590e2f39b5d0 100644 |
| --- a/src/elements.cc |
| +++ b/src/elements.cc |
| @@ -40,7 +40,9 @@ |
| // - SloppyArgumentsElementsAccessor |
| // - FastSloppyArgumentsElementsAccessor |
| // - SlowSloppyArgumentsElementsAccessor |
| - |
| +// - StringWrapperElementsAccessor |
| +// - FastStringWrapperElementsAccessor |
| +// - SlowStringWrapperElementsAccessor |
| namespace v8 { |
| namespace internal { |
| @@ -72,6 +74,10 @@ enum Where { AT_START, AT_END }; |
| FixedArray) \ |
| V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS, \ |
| FixedArray) \ |
| + V(FastStringWrapperElementsAccessor, FAST_STRING_WRAPPER_ELEMENTS, \ |
| + FixedArray) \ |
| + V(SlowStringWrapperElementsAccessor, SLOW_STRING_WRAPPER_ELEMENTS, \ |
| + FixedArray) \ |
| V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array) \ |
| V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array) \ |
| V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array) \ |
| @@ -83,7 +89,6 @@ enum Where { AT_START, AT_END }; |
| V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS, \ |
| FixedUint8ClampedArray) |
| - |
| template<ElementsKind Kind> class ElementsKindTraits { |
| public: |
| typedef FixedArrayBase BackingStore; |
| @@ -230,15 +235,16 @@ static void CopyDoubleToObjectElements(FixedArrayBase* from_base, |
| Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate); |
| Handle<FixedArray> to(FixedArray::cast(to_base), isolate); |
| - // create an outer loop to not waste too much time on creating HandleScopes |
| - // on the other hand we might overflow a single handle scope depending on |
| - // the copy_size |
| + // Use an outer loop to not waste too much time on creating HandleScopes. |
| + // On the other hand we might overflow a single handle scope depending on |
| + // the copy_size. |
| int offset = 0; |
| while (offset < copy_size) { |
| HandleScope scope(isolate); |
| offset += 100; |
| for (int i = offset - 100; i < offset && i < copy_size; ++i) { |
| - Handle<Object> value = FixedDoubleArray::get(from, i + from_start); |
| + Handle<Object> value = |
| + FixedDoubleArray::get(*from, i + from_start, isolate); |
| to->set(i + to_start, *value, UPDATE_WRITE_BARRIER); |
| } |
| } |
| @@ -545,30 +551,22 @@ class ElementsAccessorBase : public ElementsAccessor { |
| *holder, *backing_store, index, filter) != kMaxUInt32; |
| } |
| - Handle<Object> Get(Handle<FixedArrayBase> backing_store, |
| - uint32_t entry) final { |
| - return ElementsAccessorSubclass::GetImpl(backing_store, entry); |
| + Handle<Object> Get(Handle<JSObject> holder, uint32_t entry) final { |
| + return ElementsAccessorSubclass::GetImpl(holder, entry); |
| } |
| - static Handle<Object> GetImpl(Handle<FixedArrayBase> backing_store, |
| - uint32_t entry) { |
| - uint32_t index = GetIndexForEntryImpl(*backing_store, entry); |
| - return BackingStore::get(Handle<BackingStore>::cast(backing_store), index); |
| + static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) { |
| + return ElementsAccessorSubclass::GetImpl(holder->elements(), entry); |
| } |
| - void Set(FixedArrayBase* backing_store, uint32_t entry, Object* value) final { |
| - ElementsAccessorSubclass::SetImpl(backing_store, entry, value); |
| + static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) { |
| + Isolate* isolate = backing_store->GetIsolate(); |
| + uint32_t index = GetIndexForEntryImpl(backing_store, entry); |
| + return handle(BackingStore::cast(backing_store)->get(index), isolate); |
| } |
| - static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, |
|
Jakob Kummerow
2016/01/26 14:21:24
Having the compiler complain about not finding a S
|
| - Object* value) { |
| - UNREACHABLE(); |
| - } |
| - |
| - |
| - static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, |
| - Object* value, WriteBarrierMode mode) { |
| - UNREACHABLE(); |
| + void Set(Handle<JSObject> holder, uint32_t entry, Object* value) final { |
| + ElementsAccessorSubclass::SetImpl(holder, entry, value); |
| } |
| void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store, |
| @@ -780,6 +778,7 @@ class ElementsAccessorBase : public ElementsAccessor { |
| DCHECK(IsFastDoubleElementsKind(from_kind) != |
| IsFastDoubleElementsKind(kind()) || |
| IsDictionaryElementsKind(from_kind) || |
| + from_kind == SLOW_STRING_WRAPPER_ELEMENTS || |
| static_cast<uint32_t>(old_elements->length()) < capacity); |
| Handle<FixedArrayBase> elements = |
| ConvertElementsWithCapacity(object, old_elements, from_kind, capacity); |
| @@ -814,21 +813,6 @@ class ElementsAccessorBase : public ElementsAccessor { |
| UNREACHABLE(); |
| } |
| - void CopyElements(Handle<FixedArrayBase> from, uint32_t from_start, |
| - ElementsKind from_kind, Handle<FixedArrayBase> to, |
| - uint32_t to_start, int copy_size) final { |
| - DCHECK(!from.is_null()); |
| - // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods |
| - // violate the handlified function signature convention: |
| - // raw pointer parameters in the function that allocates. This is done |
| - // intentionally to avoid ArrayConcat() builtin performance degradation. |
| - // See the comment in another ElementsAccessorBase::CopyElements() for |
| - // details. |
| - ElementsAccessorSubclass::CopyElementsImpl(*from, from_start, *to, |
| - from_kind, to_start, |
| - kPackedSizeNotKnown, copy_size); |
| - } |
| - |
| void CopyElements(JSObject* from_holder, uint32_t from_start, |
| ElementsKind from_kind, Handle<FixedArrayBase> to, |
| uint32_t to_start, int copy_size) final { |
| @@ -861,6 +845,7 @@ class ElementsAccessorBase : public ElementsAccessor { |
| KeyAccumulator* keys, uint32_t range, |
| PropertyFilter filter, |
| uint32_t offset) { |
| + DCHECK_NE(DICTIONARY_ELEMENTS, kind()); |
| if (filter & ONLY_ALL_CAN_READ) { |
| // Non-dictionary elements can't have all-can-read accessors. |
| return; |
| @@ -875,8 +860,9 @@ class ElementsAccessorBase : public ElementsAccessor { |
| if (range < length) length = range; |
| for (uint32_t i = offset; i < length; i++) { |
| if (!ElementsAccessorSubclass::HasElementImpl(object, i, backing_store, |
| - filter)) |
| + filter)) { |
| continue; |
| + } |
| keys->AddKey(i); |
| } |
| } |
| @@ -892,19 +878,8 @@ class ElementsAccessorBase : public ElementsAccessor { |
| void AddElementsToKeyAccumulator(Handle<JSObject> receiver, |
| KeyAccumulator* accumulator, |
| AddKeyConversion convert) final { |
| - Handle<FixedArrayBase> from(receiver->elements()); |
| - uint32_t add_length = |
| - ElementsAccessorSubclass::GetCapacityImpl(*receiver, *from); |
| - if (add_length == 0) return; |
| - |
| - for (uint32_t i = 0; i < add_length; i++) { |
| - if (!ElementsAccessorSubclass::HasEntryImpl(*from, i)) continue; |
| - Handle<Object> value = ElementsAccessorSubclass::GetImpl(from, i); |
| - DCHECK(!value->IsTheHole()); |
| - DCHECK(!value->IsAccessorPair()); |
| - DCHECK(!value->IsAccessorInfo()); |
| - accumulator->AddKey(value, convert); |
| - } |
| + ElementsAccessorSubclass::AddElementsToKeyAccumulatorImpl( |
| + receiver, accumulator, convert); |
| } |
| static uint32_t GetCapacityImpl(JSObject* holder, |
| @@ -916,10 +891,6 @@ class ElementsAccessorBase : public ElementsAccessor { |
| return ElementsAccessorSubclass::GetCapacityImpl(holder, backing_store); |
| } |
| - static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) { |
| - return true; |
| - } |
| - |
| static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store, |
| uint32_t entry) { |
| return entry; |
| @@ -956,9 +927,12 @@ class ElementsAccessorBase : public ElementsAccessor { |
| return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell); |
| } |
| - PropertyDetails GetDetails(FixedArrayBase* backing_store, |
| - uint32_t entry) final { |
| - return ElementsAccessorSubclass::GetDetailsImpl(backing_store, entry); |
| + static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) { |
| + return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell); |
| + } |
| + |
| + PropertyDetails GetDetails(JSObject* holder, uint32_t entry) final { |
| + return ElementsAccessorSubclass::GetDetailsImpl(holder, entry); |
| } |
| private: |
| @@ -1053,15 +1027,22 @@ class DictionaryElementsAccessor |
| return backing_store->ValueAt(entry); |
| } |
| - static Handle<Object> GetImpl(Handle<FixedArrayBase> store, uint32_t entry) { |
| - Isolate* isolate = store->GetIsolate(); |
| - return handle(GetRaw(*store, entry), isolate); |
| + static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) { |
|
Jakob Kummerow
2016/01/26 14:21:24
This does exactly the same as the superclass imple
|
| + return GetImpl(holder->elements(), entry); |
| } |
| - static inline void SetImpl(FixedArrayBase* store, uint32_t entry, |
| + static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) { |
| + return handle(GetRaw(backing_store, entry), backing_store->GetIsolate()); |
| + } |
| + |
| + static inline void SetImpl(Handle<JSObject> holder, uint32_t entry, |
| Object* value) { |
| - SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store); |
| - dictionary->ValueAtPut(entry, value); |
| + SetImpl(holder->elements(), entry, value); |
| + } |
| + |
| + static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, |
| + Object* value) { |
| + SeededNumberDictionary::cast(backing_store)->ValueAtPut(entry, value); |
| } |
| static void ReconfigureImpl(Handle<JSObject> object, |
| @@ -1082,7 +1063,7 @@ class DictionaryElementsAccessor |
| uint32_t new_capacity) { |
| PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); |
| Handle<SeededNumberDictionary> dictionary = |
| - object->HasFastElements() |
| + object->HasFastElements() || object->HasFastStringWrapperElements() |
| ? JSObject::NormalizeElements(object) |
| : handle(SeededNumberDictionary::cast(object->elements())); |
| Handle<SeededNumberDictionary> new_dictionary = |
| @@ -1123,6 +1104,10 @@ class DictionaryElementsAccessor |
| return static_cast<uint32_t>(entry); |
| } |
| + static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) { |
| + return GetDetailsImpl(holder->elements(), entry); |
| + } |
| + |
| static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store, |
| uint32_t entry) { |
| return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry); |
| @@ -1159,6 +1144,24 @@ class DictionaryElementsAccessor |
| keys->SortCurrentElementsList(); |
| } |
| + |
| + static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, |
| + KeyAccumulator* accumulator, |
| + AddKeyConversion convert) { |
| + SeededNumberDictionary* dictionary = |
| + SeededNumberDictionary::cast(receiver->elements()); |
| + int capacity = dictionary->Capacity(); |
| + for (int i = 0; i < capacity; i++) { |
| + Object* k = dictionary->KeyAt(i); |
| + if (!dictionary->IsKey(k)) continue; |
| + if (dictionary->IsDeleted(i)) continue; |
| + Object* value = dictionary->ValueAt(i); |
| + DCHECK(!value->IsTheHole()); |
| + DCHECK(!value->IsAccessorPair()); |
| + DCHECK(!value->IsAccessorInfo()); |
| + accumulator->AddKey(value, convert); |
| + } |
| + } |
| }; |
| @@ -1197,9 +1200,9 @@ class FastElementsAccessor |
| static void DeleteCommon(Handle<JSObject> obj, uint32_t entry, |
| Handle<FixedArrayBase> store) { |
| - DCHECK(obj->HasFastSmiOrObjectElements() || |
| - obj->HasFastDoubleElements() || |
| - obj->HasFastArgumentsElements()); |
| + DCHECK(obj->HasFastSmiOrObjectElements() || obj->HasFastDoubleElements() || |
| + obj->HasFastArgumentsElements() || |
| + obj->HasFastStringWrapperElements()); |
| Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store); |
| if (!obj->IsJSArray() && |
| entry == static_cast<uint32_t>(store->length()) - 1) { |
| @@ -1277,7 +1280,7 @@ class FastElementsAccessor |
| FastElementsAccessorSubclass::GrowCapacityAndConvertImpl(object, |
| new_capacity); |
| } else { |
| - if (from_kind != to_kind) { |
| + if (IsFastElementsKind(from_kind) && from_kind != to_kind) { |
| JSObject::TransitionElementsKind(object, to_kind); |
| } |
| if (IsFastSmiOrObjectElementsKind(from_kind)) { |
| @@ -1285,7 +1288,7 @@ class FastElementsAccessor |
| JSObject::EnsureWritableFastElements(object); |
| } |
| } |
| - FastElementsAccessorSubclass::SetImpl(object->elements(), index, *value); |
| + FastElementsAccessorSubclass::SetImpl(object, index, *value); |
| } |
| static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) { |
| @@ -1303,6 +1306,27 @@ class FastElementsAccessor |
| return !BackingStore::cast(backing_store)->is_the_hole(entry); |
| } |
| + static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, |
| + KeyAccumulator* accumulator, |
| + AddKeyConversion convert) { |
| + uint32_t length = 0; |
| + Handle<FixedArrayBase> elements(receiver->elements(), |
| + receiver->GetIsolate()); |
| + if (receiver->IsJSArray()) { |
| + length = Smi::cast(JSArray::cast(*receiver)->length())->value(); |
| + } else { |
| + length = |
| + FastElementsAccessorSubclass::GetCapacityImpl(*receiver, *elements); |
| + } |
| + for (uint32_t i = 0; i < length; i++) { |
| + if (IsFastPackedElementsKind(KindTraits::Kind) || |
| + HasEntryImpl(*elements, i)) { |
| + accumulator->AddKey(FastElementsAccessorSubclass::GetImpl(*elements, i), |
| + convert); |
| + } |
| + } |
| + } |
| + |
| static void ValidateContents(Handle<JSObject> holder, int length) { |
| #if DEBUG |
| Isolate* isolate = holder->GetIsolate(); |
| @@ -1320,7 +1344,7 @@ class FastElementsAccessor |
| Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements); |
| if (IsFastSmiElementsKind(KindTraits::Kind)) { |
| for (int i = 0; i < length; i++) { |
| - DCHECK(BackingStore::get(backing_store, i)->IsSmi() || |
| + DCHECK(BackingStore::get(*backing_store, i, isolate)->IsSmi() || |
| (IsFastHoleyElementsKind(KindTraits::Kind) && |
| backing_store->is_the_hole(i))); |
| } |
| @@ -1480,7 +1504,7 @@ class FastElementsAccessor |
| int new_length = length - 1; |
| int remove_index = remove_position == AT_START ? 0 : new_length; |
| Handle<Object> result = |
| - FastElementsAccessorSubclass::GetImpl(backing_store, remove_index); |
| + FastElementsAccessorSubclass::GetImpl(*backing_store, remove_index); |
| if (remove_position == AT_START) { |
| FastElementsAccessorSubclass::MoveElements( |
| isolate, receiver, backing_store, 0, 1, new_length, 0, 0); |
| @@ -1557,6 +1581,11 @@ class FastSmiOrObjectElementsAccessor |
| : FastElementsAccessor<FastElementsAccessorSubclass, |
| KindTraits>(name) {} |
| + static inline void SetImpl(Handle<JSObject> holder, uint32_t entry, |
| + Object* value) { |
| + SetImpl(holder->elements(), entry, value); |
| + } |
| + |
| static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, |
| Object* value) { |
| FixedArray::cast(backing_store)->set(entry, value); |
| @@ -1613,6 +1642,7 @@ class FastSmiOrObjectElementsAccessor |
| case FAST_HOLEY_SMI_ELEMENTS: |
| case FAST_ELEMENTS: |
| case FAST_HOLEY_ELEMENTS: |
| + case FAST_STRING_WRAPPER_ELEMENTS: |
| CopyObjectToObjectElements(from, from_kind, from_start, to, to_kind, |
| to_start, copy_size); |
| break; |
| @@ -1624,17 +1654,21 @@ class FastSmiOrObjectElementsAccessor |
| break; |
| } |
| case DICTIONARY_ELEMENTS: |
| + case SLOW_STRING_WRAPPER_ELEMENTS: |
| CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start, |
| copy_size); |
| break; |
| case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
| case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: |
| - UNREACHABLE(); |
| -#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
| - case TYPE##_ELEMENTS: \ |
| - UNREACHABLE(); |
| +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: |
| TYPED_ARRAYS(TYPED_ARRAY_CASE) |
| #undef TYPED_ARRAY_CASE |
| + // This function is currently only used for JSArrays with non-zero |
| + // length. |
| + UNREACHABLE(); |
| + break; |
| + case NO_ELEMENTS: |
| + break; // Nothing to do. |
| } |
| } |
| }; |
| @@ -1697,6 +1731,21 @@ class FastDoubleElementsAccessor |
| : FastElementsAccessor<FastElementsAccessorSubclass, |
| KindTraits>(name) {} |
| + static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) { |
| + return GetImpl(holder->elements(), entry); |
| + } |
| + |
| + static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) { |
| + Isolate* isolate = backing_store->GetIsolate(); |
| + return FixedDoubleArray::get(FixedDoubleArray::cast(backing_store), entry, |
| + isolate); |
| + } |
| + |
| + static inline void SetImpl(Handle<JSObject> holder, uint32_t entry, |
| + Object* value) { |
| + SetImpl(holder->elements(), entry, value); |
| + } |
| + |
| static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, |
| Object* value) { |
| FixedDoubleArray::cast(backing_store)->set(entry, value->Number()); |
| @@ -1759,13 +1808,16 @@ class FastDoubleElementsAccessor |
| break; |
| case FAST_SLOPPY_ARGUMENTS_ELEMENTS: |
| case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: |
| - UNREACHABLE(); |
| - |
| -#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
| - case TYPE##_ELEMENTS: \ |
| - UNREACHABLE(); |
| + case FAST_STRING_WRAPPER_ELEMENTS: |
| + case SLOW_STRING_WRAPPER_ELEMENTS: |
| + case NO_ELEMENTS: |
| +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: |
| TYPED_ARRAYS(TYPED_ARRAY_CASE) |
| #undef TYPED_ARRAY_CASE |
| + // This function is currently only used for JSArrays with non-zero |
| + // length. |
| + UNREACHABLE(); |
| + break; |
| } |
| } |
| }; |
| @@ -1808,6 +1860,11 @@ class TypedElementsAccessor |
| typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore; |
| typedef TypedElementsAccessor<Kind> AccessorClass; |
| + static inline void SetImpl(Handle<JSObject> holder, uint32_t entry, |
| + Object* value) { |
| + SetImpl(holder->elements(), entry, value); |
| + } |
| + |
| static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry, |
| Object* value) { |
| BackingStore::cast(backing_store)->SetValue(entry, value); |
| @@ -1818,10 +1875,16 @@ class TypedElementsAccessor |
| BackingStore::cast(backing_store)->SetValue(entry, value); |
| } |
| - static Handle<Object> GetImpl(Handle<FixedArrayBase> backing_store, |
| - uint32_t entry) { |
| - uint32_t index = GetIndexForEntryImpl(*backing_store, entry); |
| - return BackingStore::get(Handle<BackingStore>::cast(backing_store), index); |
| + static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) { |
| + return GetImpl(holder->elements(), entry); |
| + } |
| + |
| + static Handle<Object> GetImpl(FixedArrayBase* backing_store, uint32_t entry) { |
| + return BackingStore::get(BackingStore::cast(backing_store), entry); |
| + } |
| + |
| + static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) { |
| + return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell); |
| } |
| static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store, |
| @@ -1829,6 +1892,12 @@ class TypedElementsAccessor |
| return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell); |
| } |
| + static bool HasElementImpl(Handle<JSObject> holder, uint32_t index, |
| + Handle<FixedArrayBase> backing_store, |
| + PropertyFilter filter) { |
| + return index < AccessorClass::GetCapacityImpl(*holder, *backing_store); |
| + } |
| + |
| static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array, |
| uint32_t length, |
| Handle<FixedArrayBase> backing_store) { |
| @@ -1859,6 +1928,18 @@ class TypedElementsAccessor |
| if (view->WasNeutered()) return 0; |
| return backing_store->length(); |
| } |
| + |
| + static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, |
| + KeyAccumulator* accumulator, |
| + AddKeyConversion convert) { |
| + Handle<FixedArrayBase> elements(receiver->elements(), |
| + receiver->GetIsolate()); |
| + uint32_t length = AccessorClass::GetCapacityImpl(*receiver, *elements); |
| + for (uint32_t i = 0; i < length; i++) { |
| + Handle<Object> value = AccessorClass::GetImpl(*elements, i); |
| + accumulator->AddKey(value, convert); |
| + } |
| + } |
| }; |
| @@ -1883,10 +1964,13 @@ class SloppyArgumentsElementsAccessor |
| USE(KindTraits::Kind); |
| } |
| - static Handle<Object> GetImpl(Handle<FixedArrayBase> parameters, |
| - uint32_t entry) { |
| + static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) { |
| + return GetImpl(holder->elements(), entry); |
| + } |
| + |
| + static Handle<Object> GetImpl(FixedArrayBase* parameters, uint32_t entry) { |
| Isolate* isolate = parameters->GetIsolate(); |
| - Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters); |
| + Handle<FixedArray> parameter_map(FixedArray::cast(parameters), isolate); |
| uint32_t length = parameter_map->length() - 2; |
| if (entry < length) { |
| DisallowHeapAllocation no_gc; |
| @@ -1897,10 +1981,8 @@ class SloppyArgumentsElementsAccessor |
| return handle(context->get(context_entry), isolate); |
| } else { |
| // Object is not mapped, defer to the arguments. |
| - Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)), |
| - isolate); |
| - Handle<Object> result = |
| - ArgumentsAccessor::GetImpl(arguments, entry - length); |
| + Handle<Object> result = ArgumentsAccessor::GetImpl( |
| + FixedArray::cast(parameter_map->get(1)), entry - length); |
| // Elements of the arguments object in slow mode might be slow aliases. |
| if (result->IsAliasedArgumentsEntry()) { |
| DisallowHeapAllocation no_gc; |
| @@ -1919,6 +2001,11 @@ class SloppyArgumentsElementsAccessor |
| UNREACHABLE(); |
| } |
| + static inline void SetImpl(Handle<JSObject> holder, uint32_t entry, |
| + Object* value) { |
| + SetImpl(holder->elements(), entry, value); |
| + } |
| + |
| static inline void SetImpl(FixedArrayBase* store, uint32_t entry, |
| Object* value) { |
| FixedArray* parameter_map = FixedArray::cast(store); |
| @@ -1959,6 +2046,18 @@ class SloppyArgumentsElementsAccessor |
| ArgumentsAccessor::GetCapacityImpl(holder, arguments); |
| } |
| + static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, |
| + KeyAccumulator* accumulator, |
| + AddKeyConversion convert) { |
| + FixedArrayBase* elements = receiver->elements(); |
| + uint32_t length = GetCapacityImpl(*receiver, elements); |
| + for (uint32_t entry = 0; entry < length; entry++) { |
| + if (!HasEntryImpl(elements, entry)) continue; |
| + Handle<Object> value = GetImpl(elements, entry); |
| + accumulator->AddKey(value, convert); |
| + } |
| + } |
| + |
| static bool HasEntryImpl(FixedArrayBase* parameters, uint32_t entry) { |
| FixedArray* parameter_map = FixedArray::cast(parameters); |
| uint32_t length = parameter_map->length() - 2; |
| @@ -1994,9 +2093,8 @@ class SloppyArgumentsElementsAccessor |
| return (parameter_map->length() - 2) + entry; |
| } |
| - static PropertyDetails GetDetailsImpl(FixedArrayBase* parameters, |
| - uint32_t entry) { |
| - FixedArray* parameter_map = FixedArray::cast(parameters); |
| + static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) { |
| + FixedArray* parameter_map = FixedArray::cast(holder->elements()); |
| uint32_t length = parameter_map->length() - 2; |
| if (entry < length) { |
| return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell); |
| @@ -2201,6 +2299,164 @@ class FastSloppyArgumentsElementsAccessor |
| } |
| }; |
| +template <typename StringWrapperElementsAccessorSubclass, |
| + typename ElementsAccessor, typename KindTraits> |
| +class StringWrapperElementsAccessor |
| + : public ElementsAccessorBase<StringWrapperElementsAccessorSubclass, |
| + KindTraits> { |
| + public: |
| + explicit StringWrapperElementsAccessor(const char* name) |
| + : ElementsAccessorBase<StringWrapperElementsAccessorSubclass, KindTraits>( |
| + name) { |
| + USE(KindTraits::Kind); |
| + } |
| + |
| + static Handle<Object> GetImpl(Handle<JSObject> holder, uint32_t entry) { |
| + Isolate* isolate = holder->GetIsolate(); |
| + Handle<String> string(GetString(*holder), isolate); |
| + uint32_t length = static_cast<uint32_t>(string->length()); |
| + if (entry < length) { |
| + return isolate->factory()->LookupSingleCharacterStringFromCode( |
| + String::Flatten(string)->Get(entry)); |
| + } |
| + return ElementsAccessor::GetImpl(holder, entry - length); |
| + } |
| + |
| + static PropertyDetails GetDetailsImpl(JSObject* holder, uint32_t entry) { |
| + uint32_t length = static_cast<uint32_t>(GetString(holder)->length()); |
| + if (entry < length) { |
| + PropertyAttributes attributes = |
| + static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE); |
| + return PropertyDetails(attributes, v8::internal::DATA, 0, |
| + PropertyCellType::kNoCell); |
| + } |
| + return ElementsAccessor::GetDetailsImpl(holder, entry - length); |
| + } |
| + |
| + static uint32_t GetEntryForIndexImpl(JSObject* holder, |
| + FixedArrayBase* backing_store, |
| + uint32_t index, PropertyFilter filter) { |
| + uint32_t length = static_cast<uint32_t>(GetString(holder)->length()); |
| + if (index < length) return index; |
| + uint32_t backing_store_entry = ElementsAccessor::GetEntryForIndexImpl( |
| + holder, backing_store, index, filter); |
| + if (backing_store_entry == kMaxUInt32) return kMaxUInt32; |
| + DCHECK(backing_store_entry < kMaxUInt32 - length); |
| + return backing_store_entry + length; |
| + } |
| + |
| + static void DeleteImpl(Handle<JSObject> holder, uint32_t entry) { |
| + uint32_t length = static_cast<uint32_t>(GetString(*holder)->length()); |
| + if (entry < length) { |
| + return; // String contents can't be deleted. |
| + } |
| + ElementsAccessor::DeleteImpl(holder, entry - length); |
| + } |
| + |
| + static void SetImpl(Handle<JSObject> holder, uint32_t entry, Object* value) { |
| + uint32_t length = static_cast<uint32_t>(GetString(*holder)->length()); |
| + if (entry < length) { |
| + return; // String contents are read-only. |
| + } |
| + ElementsAccessor::SetImpl(holder->elements(), entry - length, value); |
| + } |
| + |
| + static void AddImpl(Handle<JSObject> object, uint32_t index, |
| + Handle<Object> value, PropertyAttributes attributes, |
| + uint32_t new_capacity) { |
| + DCHECK(index >= static_cast<uint32_t>(GetString(*object)->length())); |
| + if ((KindTraits::Kind == FAST_STRING_WRAPPER_ELEMENTS && |
| + object->GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS) || |
| + ElementsAccessor::GetCapacityImpl(*object, object->elements()) != |
| + new_capacity) { |
| + StringWrapperElementsAccessorSubclass::GrowCapacityAndConvertImpl( |
| + object, new_capacity); |
| + } |
| + ElementsAccessor::AddImpl(object, index, value, attributes, new_capacity); |
| + } |
| + |
| + static void ReconfigureImpl(Handle<JSObject> object, |
| + Handle<FixedArrayBase> store, uint32_t entry, |
| + Handle<Object> value, |
| + PropertyAttributes attributes) { |
| + uint32_t length = static_cast<uint32_t>(GetString(*object)->length()); |
| + if (entry < length) { |
| + return; // String contents can't be reconfigured. |
| + } |
| + ElementsAccessor::ReconfigureImpl(object, store, entry - length, value, |
| + attributes); |
| + } |
| + |
| + static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, |
| + KeyAccumulator* accumulator, |
| + AddKeyConversion convert) { |
| + Isolate* isolate = receiver->GetIsolate(); |
| + Handle<String> string(GetString(*receiver), isolate); |
| + string = String::Flatten(string); |
| + uint32_t length = static_cast<uint32_t>(string->length()); |
| + for (uint32_t i = 0; i < length; i++) { |
| + accumulator->AddKey( |
| + isolate->factory()->LookupSingleCharacterStringFromCode( |
| + string->Get(i)), |
| + convert); |
| + } |
| + ElementsAccessor::AddElementsToKeyAccumulatorImpl(receiver, accumulator, |
| + convert); |
| + } |
| + |
| + static void CollectElementIndicesImpl(Handle<JSObject> object, |
| + Handle<FixedArrayBase> backing_store, |
| + KeyAccumulator* keys, uint32_t range, |
| + PropertyFilter filter, |
| + uint32_t offset) { |
| + if ((filter & ONLY_ALL_CAN_READ) == 0) { |
| + uint32_t length = GetString(*object)->length(); |
| + for (uint32_t i = 0; i < length; i++) { |
| + keys->AddKey(i); |
| + } |
| + } |
| + ElementsAccessor::CollectElementIndicesImpl(object, backing_store, keys, |
| + range, filter, offset); |
| + } |
| + |
| + static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, |
| + FixedArrayBase* to, ElementsKind from_kind, |
| + uint32_t to_start, int packed_size, |
| + int copy_size) { |
| + ElementsAccessor::CopyElementsImpl(from, from_start, to, from_kind, |
| + to_start, packed_size, copy_size); |
| + } |
| + |
| + private: |
| + static String* GetString(JSObject* holder) { |
| + DCHECK(holder->IsJSValue()); |
| + JSValue* js_value = JSValue::cast(holder); |
| + DCHECK(js_value->value()->IsString()); |
| + return String::cast(js_value->value()); |
| + } |
| +}; |
| + |
| +class FastStringWrapperElementsAccessor |
| + : public StringWrapperElementsAccessor< |
| + FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor, |
| + ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>> { |
| + public: |
| + explicit FastStringWrapperElementsAccessor(const char* name) |
| + : StringWrapperElementsAccessor< |
| + FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor, |
| + ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>>(name) {} |
| +}; |
| + |
| +class SlowStringWrapperElementsAccessor |
| + : public StringWrapperElementsAccessor< |
| + SlowStringWrapperElementsAccessor, DictionaryElementsAccessor, |
| + ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>> { |
| + public: |
| + explicit SlowStringWrapperElementsAccessor(const char* name) |
| + : StringWrapperElementsAccessor< |
| + SlowStringWrapperElementsAccessor, DictionaryElementsAccessor, |
| + ElementsKindTraits<SLOW_STRING_WRAPPER_ELEMENTS>>(name) {} |
| +}; |
| } // namespace |