Introduce {FAST,SLOW}_STRING_WRAPPER_ELEMENTS

String wrappers (new String("foo")) are special objects: their string
characters are accessed like elements, and they also have an elements
backing store. This used to require a bunch of explicit checks like:

if (obj->IsJSValue() && JSValue::cast(obj)->value()->IsString()) {
  /* Handle string characters */
}
// Handle regular elements (for string wrappers and other objects)
obj->GetElementsAccessor()->Whatever(...);

This CL introduces new ElementsKinds for string wrapper objects (one for
fast elements, one for dictionary elements), which allow folding the
special-casing into new StringWrapperElementsAccessors.

No observable change in behavior is intended.

Review URL: https://codereview.chromium.org/1612323003

Cr-Commit-Position: refs/heads/master@{#33616}
This commit is contained in:
jkummerow 2016-01-29 10:57:26 -08:00 committed by Commit bot
parent 0e2854585b
commit f4872f7477
35 changed files with 656 additions and 333 deletions

View File

@ -1241,6 +1241,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Handle<Map> string_map =
Handle<Map>(native_context()->string_function()->initial_map());
string_map->set_elements_kind(FAST_STRING_WRAPPER_ELEMENTS);
Map::EnsureDescriptorSlack(string_map, 1);
PropertyAttributes attribs = static_cast<PropertyAttributes>(

View File

@ -835,14 +835,20 @@ uint32_t EstimateElementCount(Handle<JSArray> array) {
}
break;
}
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
// External arrays are always dense.
return length;
case NO_ELEMENTS:
return 0;
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
UNREACHABLE();
return 0;
}
// As an estimate, we assume that the prototype doesn't contain any
// inherited elements.
@ -983,6 +989,28 @@ void CollectElementIndices(Handle<JSObject> object, uint32_t range,
}
break;
}
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS: {
DCHECK(object->IsJSValue());
Handle<JSValue> js_value = Handle<JSValue>::cast(object);
DCHECK(js_value->value()->IsString());
Handle<String> string(String::cast(js_value->value()), isolate);
uint32_t length = static_cast<uint32_t>(string->length());
uint32_t i = 0;
uint32_t limit = Min(length, range);
for (; i < limit; i++) {
indices->Add(i);
}
ElementsAccessor* accessor = object->GetElementsAccessor();
for (; i < range; i++) {
if (accessor->HasElement(object, i)) {
indices->Add(i);
}
}
break;
}
case NO_ELEMENTS:
break;
}
PrototypeIterator iter(isolate, object);
@ -1218,6 +1246,13 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
}
break;
}
case NO_ELEMENTS:
break;
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
// |array| is guaranteed to be an array or typed array.
UNREACHABLE();
break;
}
visitor->increase_index_offset(length);
return true;
@ -1367,6 +1402,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species,
case FAST_HOLEY_ELEMENTS:
case FAST_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NO_ELEMENTS:
DCHECK_EQ(0u, length);
break;
default:
@ -1728,7 +1764,7 @@ BUILTIN(ObjectValues) {
CONVERT_TO_STRING));
for (int i = 0; i < keys->length(); ++i) {
auto key = Handle<Name>::cast(FixedArray::get(keys, i));
auto key = Handle<Name>::cast(FixedArray::get(*keys, i, isolate));
Handle<Object> value;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
@ -1754,7 +1790,7 @@ BUILTIN(ObjectEntries) {
CONVERT_TO_STRING));
for (int i = 0; i < keys->length(); ++i) {
auto key = Handle<Name>::cast(FixedArray::get(keys, i));
auto key = Handle<Name>::cast(FixedArray::get(*keys, i, isolate));
Handle<Object> value;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(

View File

@ -804,28 +804,8 @@ void CreateWeakCellStub::GenerateAheadOfTime(Isolate* isolate) {
void StoreElementStub::Generate(MacroAssembler* masm) {
switch (elements_kind()) {
case FAST_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case FAST_SMI_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case TYPE##_ELEMENTS:
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
UNREACHABLE();
break;
case DICTIONARY_ELEMENTS:
ElementHandlerCompiler::GenerateStoreSlow(masm);
break;
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNREACHABLE();
break;
}
DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind());
ElementHandlerCompiler::GenerateStoreSlow(masm);
}

View File

@ -2726,6 +2726,9 @@ class StoreElementStub : public PlatformCodeStub {
StoreElementStub(Isolate* isolate, ElementsKind elements_kind,
KeyedAccessStoreMode mode)
: PlatformCodeStub(isolate) {
// TODO(jkummerow): Rename this stub to StoreSlowElementStub,
// drop elements_kind parameter.
DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind);
minor_key_ = ElementsKindBits::encode(elements_kind) |
CommonStoreModeBits::encode(mode);
}

View File

@ -33,7 +33,8 @@ void ScriptContextTable::set_used(int used) {
Handle<Context> ScriptContextTable::GetContext(Handle<ScriptContextTable> table,
int i) {
DCHECK(i < table->used());
return Handle<Context>::cast(FixedArray::get(table, i + kFirstContextSlot));
return Handle<Context>::cast(
FixedArray::get(*table, i + kFirstContextSlot, table->GetIsolate()));
}

View File

@ -2946,6 +2946,9 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}
@ -4016,6 +4019,9 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}

View File

@ -3186,6 +3186,9 @@ void LCodeGen::DoLoadKeyedExternal(LLoadKeyedExternal* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}
@ -4874,6 +4877,9 @@ void LCodeGen::DoStoreKeyedExternal(LStoreKeyedExternal* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}

View File

@ -5695,7 +5695,7 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
Handle<Context> script_context = ScriptContextTable::GetContext(
script_contexts, lookup.context_index);
Handle<Object> current_value =
FixedArray::get(script_context, lookup.slot_index);
FixedArray::get(*script_context, lookup.slot_index, isolate());
// If the values is not the hole, it will stay initialized,
// so no need to generate a check.
@ -6891,7 +6891,7 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
ScriptContextTable::GetContext(script_contexts, lookup.context_index);
Handle<Object> current_value =
FixedArray::get(script_context, lookup.slot_index);
FixedArray::get(*script_context, lookup.slot_index, isolate());
// If the values is not the hole, it will stay initialized,
// so no need to generate a check.
@ -7415,8 +7415,8 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
static bool CanInlineElementAccess(Handle<Map> map) {
return map->IsJSObjectMap() && !map->has_dictionary_elements() &&
!map->has_sloppy_arguments_elements() &&
return map->IsJSObjectMap() &&
(map->has_fast_elements() || map->has_fixed_typed_array_elements()) &&
!map->has_indexed_interceptor() && !map->is_access_check_needed();
}

View File

@ -2871,6 +2871,9 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}
@ -3945,6 +3948,9 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}

View File

@ -2871,6 +2871,9 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}
@ -3973,6 +3976,9 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}

View File

@ -3020,6 +3020,9 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}
@ -4198,6 +4201,9 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}

View File

@ -3086,6 +3086,9 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}
@ -4275,6 +4278,9 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}

View File

@ -2903,6 +2903,9 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}
@ -4106,6 +4109,9 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}

View File

@ -3144,6 +3144,9 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}
@ -4318,6 +4321,9 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case NO_ELEMENTS:
UNREACHABLE();
break;
}

View File

@ -1857,8 +1857,8 @@ bool LiveEdit::FindActiveGenerators(Handle<FixedArray> shared_info_array,
HandleScope scope(isolate);
for (int i = 0; i < len; i++) {
Handle<JSValue> jsvalue =
Handle<JSValue>::cast(FixedArray::get(shared_info_array, i));
Handle<JSValue> jsvalue = Handle<JSValue>::cast(
FixedArray::get(*shared_info_array, i, isolate));
Handle<SharedFunctionInfo> shared =
UnwrapSharedFunctionInfoFromJSValue(jsvalue);

View File

@ -37,7 +37,12 @@ int ElementsKindToShiftSize(ElementsKind elements_kind) {
case DICTIONARY_ELEMENTS:
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
return kPointerSizeLog2;
case NO_ELEMENTS:
UNREACHABLE();
return 0;
}
UNREACHABLE();
return 0;

View File

@ -30,10 +30,16 @@ enum ElementsKind {
// The "slow" kind.
DICTIONARY_ELEMENTS,
// Elements kind of the "arguments" object (only in sloppy mode).
FAST_SLOPPY_ARGUMENTS_ELEMENTS,
SLOW_SLOPPY_ARGUMENTS_ELEMENTS,
// Fixed typed arrays
// For string wrapper objects ("new String('...')"), the string's characters
// are overlaid onto a regular elements backing store.
FAST_STRING_WRAPPER_ELEMENTS,
SLOW_STRING_WRAPPER_ELEMENTS,
// Fixed typed arrays.
UINT8_ELEMENTS,
INT8_ELEMENTS,
UINT16_ELEMENTS,
@ -44,7 +50,10 @@ enum ElementsKind {
FLOAT64_ELEMENTS,
UINT8_CLAMPED_ELEMENTS,
// Derived constants from ElementsKind
// Sentinel ElementsKind for objects with no elements.
NO_ELEMENTS,
// Derived constants from ElementsKind.
FIRST_ELEMENTS_KIND = FAST_SMI_ELEMENTS,
LAST_ELEMENTS_KIND = UINT8_CLAMPED_ELEMENTS,
FIRST_FAST_ELEMENTS_KIND = FAST_SMI_ELEMENTS,
@ -83,6 +92,10 @@ inline bool IsSloppyArgumentsElements(ElementsKind kind) {
kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
}
inline bool IsStringWrapperElementsKind(ElementsKind kind) {
return kind == FAST_STRING_WRAPPER_ELEMENTS ||
kind == SLOW_STRING_WRAPPER_ELEMENTS;
}
inline bool IsFixedTypedArrayElementsKind(ElementsKind kind) {
return kind >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND &&
@ -104,7 +117,8 @@ inline bool IsFastElementsKind(ElementsKind kind) {
inline bool IsTransitionElementsKind(ElementsKind kind) {
return IsFastElementsKind(kind) || IsFixedTypedArrayElementsKind(kind) ||
kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS;
kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS ||
kind == FAST_STRING_WRAPPER_ELEMENTS;
}

View File

@ -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,
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) {
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,165 @@ class FastSloppyArgumentsElementsAccessor
}
};
template <typename StringWrapperElementsAccessorSubclass,
typename BackingStoreAccessor, 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 BackingStoreAccessor::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 BackingStoreAccessor::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 = BackingStoreAccessor::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.
}
BackingStoreAccessor::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.
}
BackingStoreAccessor::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) ||
BackingStoreAccessor::GetCapacityImpl(*object, object->elements()) !=
new_capacity) {
StringWrapperElementsAccessorSubclass::GrowCapacityAndConvertImpl(
object, new_capacity);
}
BackingStoreAccessor::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.
}
BackingStoreAccessor::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);
}
BackingStoreAccessor::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);
}
}
BackingStoreAccessor::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) {
BackingStoreAccessor::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

View File

@ -29,8 +29,6 @@ class ElementsAccessor {
return elements_accessors_[elements_kind];
}
static ElementsAccessor* ForArray(Handle<FixedArrayBase> array);
// Checks the elements of an object for consistency, asserting when a problem
// is found.
virtual void Validate(Handle<JSObject> obj) = 0;
@ -59,8 +57,9 @@ class ElementsAccessor {
Handle<FixedArrayBase> backing_store, uint32_t start,
uint32_t end) = 0;
virtual Handle<Object> Get(Handle<FixedArrayBase> backing_store,
uint32_t entry) = 0;
virtual Handle<Object> Get(Handle<JSObject> holder, uint32_t entry) = 0;
virtual PropertyDetails GetDetails(JSObject* holder, uint32_t entry) = 0;
// Modifies the length data property as specified for JSArrays and resizes the
// underlying backing store accordingly. The method honors the semantics of
@ -81,38 +80,6 @@ class ElementsAccessor {
// destination array with the hole.
static const int kCopyToEndAndInitializeToHole = -2;
// Copy elements from one backing store to another. Typically, callers specify
// the source JSObject or JSArray in source_holder. If the holder's backing
// store is available, it can be passed in source and source_holder is
// ignored.
virtual void CopyElements(
Handle<FixedArrayBase> source,
uint32_t source_start,
ElementsKind source_kind,
Handle<FixedArrayBase> destination,
uint32_t destination_start,
int copy_size) = 0;
// NOTE: this method violates the handlified function signature convention:
// raw pointer parameter |source_holder| in the function that allocates.
// This is done intentionally to avoid ArrayConcat() builtin performance
// degradation.
virtual void CopyElements(
JSObject* source_holder,
uint32_t source_start,
ElementsKind source_kind,
Handle<FixedArrayBase> destination,
uint32_t destination_start,
int copy_size) = 0;
inline void CopyElements(
Handle<JSObject> from_holder,
Handle<FixedArrayBase> to,
ElementsKind from_kind) {
CopyElements(
*from_holder, 0, from_kind, to, 0, kCopyToEndAndInitializeToHole);
}
// Copy all indices that have elements from |object| into the given
// KeyAccumulator. For Dictionary-based element-kinds we filter out elements
// whose PropertyAttribute match |filter|.
@ -142,8 +109,7 @@ class ElementsAccessor {
static void InitializeOncePerProcess();
static void TearDown();
virtual void Set(FixedArrayBase* backing_store, uint32_t entry,
Object* value) = 0;
virtual void Set(Handle<JSObject> holder, uint32_t entry, Object* value) = 0;
virtual void Reconfigure(Handle<JSObject> object,
Handle<FixedArrayBase> backing_store, uint32_t entry,
@ -183,9 +149,6 @@ class ElementsAccessor {
protected:
friend class LookupIterator;
static ElementsAccessor* ForArray(FixedArrayBase* array);
// Element handlers distinguish between entries and indices when they
// manipulate elements. Entries refer to elements in terms of their location
// in the underlying storage's backing store representation, and are between 0
@ -197,8 +160,15 @@ class ElementsAccessor {
virtual uint32_t GetEntryForIndex(JSObject* holder,
FixedArrayBase* backing_store,
uint32_t index) = 0;
virtual PropertyDetails GetDetails(FixedArrayBase* backing_store,
uint32_t entry) = 0;
// NOTE: this method violates the handlified function signature convention:
// raw pointer parameter |source_holder| in the function that allocates.
// This is done intentionally to avoid ArrayConcat() builtin performance
// degradation.
virtual void CopyElements(JSObject* source_holder, uint32_t source_start,
ElementsKind source_kind,
Handle<FixedArrayBase> destination,
uint32_t destination_start, int copy_size) = 0;
private:
virtual uint32_t GetCapacity(JSObject* holder,

View File

@ -395,11 +395,6 @@ class Factory final {
// JS arrays are pretenured when allocated by the parser.
// Create a JSArray with no elements.
Handle<JSArray> NewJSArray(ElementsKind elements_kind,
Strength strength = Strength::WEAK,
PretenureFlag pretenure = NOT_TENURED);
// Create a JSArray with a specified length and elements initialized
// according to the specified mode.
Handle<JSArray> NewJSArray(
@ -704,6 +699,11 @@ class Factory final {
Handle<SharedFunctionInfo> info,
Handle<Context> context,
PretenureFlag pretenure = TENURED);
// Create a JSArray with no elements and no length.
Handle<JSArray> NewJSArray(ElementsKind elements_kind,
Strength strength = Strength::WEAK,
PretenureFlag pretenure = NOT_TENURED);
};
} // namespace internal

View File

@ -3517,7 +3517,8 @@ AllocationResult Heap::AllocateJSObjectFromMap(
// Initialize the JSObject.
InitializeJSObjectFromMap(js_obj, properties, map);
DCHECK(js_obj->HasFastElements() || js_obj->HasFixedTypedArrayElements());
DCHECK(js_obj->HasFastElements() || js_obj->HasFixedTypedArrayElements() ||
js_obj->HasFastStringWrapperElements());
return js_obj;
}

View File

@ -49,7 +49,6 @@ Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
if (receiver_map->has_indexed_interceptor()) {
stub = LoadIndexedInterceptorStub(isolate).GetCode();
} else if (receiver_map->IsStringMap()) {
// We have a string.
stub = LoadIndexedStringStub(isolate).GetCode();
} else if (receiver_map->has_sloppy_arguments_elements()) {
stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode();
@ -58,6 +57,7 @@ Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
stub = LoadFastElementStub(isolate, is_js_array, elements_kind,
convert_hole_to_undefined).GetCode();
} else {
DCHECK(receiver_map->has_dictionary_elements());
stub = LoadDictionaryElementStub(isolate, LoadICState(extra_ic_state))
.GetCode();
}

View File

@ -686,9 +686,9 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
ScriptContextTable::LookupResult lookup_result;
if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
Handle<Object> result =
FixedArray::get(ScriptContextTable::GetContext(
FixedArray::get(*ScriptContextTable::GetContext(
script_contexts, lookup_result.context_index),
lookup_result.slot_index);
lookup_result.slot_index, isolate());
if (*result == *isolate()->factory()->the_hole_value()) {
// Do not install stubs and stay pre-monomorphic for
// uninitialized accesses.
@ -1375,7 +1375,8 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
ASSIGN_RETURN_ON_EXCEPTION(isolate(), load_handle,
LoadIC::Load(object, Handle<Name>::cast(key)),
Object);
} else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
} else if (FLAG_use_ic && !object->IsAccessCheckNeeded() &&
!object->IsJSValue()) {
if (object->IsJSObject() || (object->IsString() && key->IsNumber())) {
Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
if (object->IsString() || key->IsSmi()) stub = LoadElementStub(receiver);
@ -1507,7 +1508,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
}
Handle<Object> previous_value =
FixedArray::get(script_context, lookup_result.slot_index);
FixedArray::get(*script_context, lookup_result.slot_index, isolate());
if (*previous_value == *isolate()->factory()->the_hole_value()) {
// Do not install stubs and stay pre-monomorphic for

View File

@ -133,8 +133,9 @@ int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const {
Handle<Object> BytecodeArrayIterator::GetConstantForIndexOperand(
int operand_index) const {
Handle<FixedArray> constants = handle(bytecode_array()->constant_pool());
return FixedArray::get(constants, GetIndexOperand(operand_index));
return FixedArray::get(bytecode_array()->constant_pool(),
GetIndexOperand(operand_index),
bytecode_array()->GetIsolate());
}

View File

@ -36,12 +36,10 @@ class KeyAccumulator final BASE_EMBEDDED {
~KeyAccumulator();
bool AddKey(uint32_t key);
bool AddKey(Object* key, AddKeyConversion convert = DO_NOT_CONVERT);
bool AddKey(Handle<Object> key, AddKeyConversion convert = DO_NOT_CONVERT);
void AddKeys(Handle<FixedArray> array,
AddKeyConversion convert = DO_NOT_CONVERT);
void AddKeys(Handle<JSObject> array,
AddKeyConversion convert = DO_NOT_CONVERT);
bool AddKey(Object* key, AddKeyConversion convert);
bool AddKey(Handle<Object> key, AddKeyConversion convert);
void AddKeys(Handle<FixedArray> array, AddKeyConversion convert);
void AddKeys(Handle<JSObject> array, AddKeyConversion convert);
void AddKeysFromProxy(Handle<JSObject> array);
Maybe<bool> AddKeysFromProxy(Handle<JSProxy> proxy, Handle<FixedArray> keys);
void AddElementKeysFromInterceptor(Handle<JSObject> array);

View File

@ -398,19 +398,17 @@ bool LookupIterator::InternalHolderIsReceiverOrHiddenPrototype() const {
if (!check_prototype_chain()) return true;
DisallowHeapAllocation no_gc;
if (!receiver_->IsJSReceiver()) return false;
Object* current = *receiver_;
JSReceiver* current = JSReceiver::cast(*receiver_);
JSReceiver* holder = *holder_;
if (current == holder) return true;
if (!holder->map()->is_hidden_prototype()) return false;
// JSProxy do not occur as hidden prototypes.
if (current->IsJSProxy()) {
return JSReceiver::cast(current) == holder;
}
PrototypeIterator iter(isolate(), current,
PrototypeIterator::START_AT_RECEIVER);
do {
if (current->IsJSProxy()) return false;
PrototypeIterator iter(isolate(), current);
while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
if (iter.GetCurrent<JSReceiver>() == holder) return true;
DCHECK(!current->IsJSProxy());
iter.Advance();
} while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
}
return false;
}
@ -419,16 +417,8 @@ Handle<Object> LookupIterator::FetchValue() const {
Object* result = NULL;
if (IsElement()) {
Handle<JSObject> holder = GetHolder<JSObject>();
// TODO(verwaest): Optimize.
if (holder->IsStringObjectWithCharacterAt(index_)) {
Handle<JSValue> js_value = Handle<JSValue>::cast(holder);
Handle<String> string(String::cast(js_value->value()));
return factory()->LookupSingleCharacterStringFromCode(
String::Flatten(string)->Get(index_));
}
ElementsAccessor* accessor = holder->GetElementsAccessor();
return accessor->Get(handle(holder->elements()), number_);
return accessor->Get(holder, number_);
} else if (holder_map_->IsJSGlobalObjectMap()) {
Handle<JSObject> holder = GetHolder<JSObject>();
result = holder->global_dictionary()->ValueAt(number_);
@ -515,7 +505,7 @@ void LookupIterator::WriteDataValue(Handle<Object> value) {
if (IsElement()) {
Handle<JSObject> object = Handle<JSObject>::cast(holder);
ElementsAccessor* accessor = object->GetElementsAccessor();
accessor->Set(object->elements(), number_, *value);
accessor->Set(object, number_, *value);
} else if (holder->IsJSGlobalObject()) {
Handle<GlobalDictionary> property_dictionary =
handle(JSObject::cast(*holder)->global_dictionary());
@ -625,10 +615,6 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* const map,
}
// Fall through.
case ACCESS_CHECK:
if (exotic_index_state_ != ExoticIndexState::kNotExotic &&
holder->IsJSTypedArray() && IsIntegerIndexedExotic(holder)) {
return INTEGER_INDEXED_EXOTIC;
}
if (check_interceptor() && HasInterceptor(map) &&
!SkipInterceptor(JSObject::cast(holder))) {
// Do not leak private property names.
@ -638,25 +624,20 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* const map,
// Fall through.
case INTERCEPTOR:
if (IsElement()) {
// TODO(verwaest): Optimize.
if (holder->IsStringObjectWithCharacterAt(index_)) {
PropertyAttributes attributes =
static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
property_details_ = PropertyDetails(attributes, v8::internal::DATA, 0,
PropertyCellType::kNoCell);
} else {
JSObject* js_object = JSObject::cast(holder);
if (js_object->elements() == isolate()->heap()->empty_fixed_array()) {
return NOT_FOUND;
JSObject* js_object = JSObject::cast(holder);
ElementsAccessor* accessor = js_object->GetElementsAccessor();
FixedArrayBase* backing_store = js_object->elements();
number_ = accessor->GetEntryForIndex(js_object, backing_store, index_);
if (number_ == kMaxUInt32) {
if (*receiver_ == Object::cast(holder) && holder->IsJSTypedArray()) {
return INTEGER_INDEXED_EXOTIC;
}
ElementsAccessor* accessor = js_object->GetElementsAccessor();
FixedArrayBase* backing_store = js_object->elements();
number_ =
accessor->GetEntryForIndex(js_object, backing_store, index_);
if (number_ == kMaxUInt32) return NOT_FOUND;
property_details_ = accessor->GetDetails(backing_store, number_);
return NOT_FOUND;
}
property_details_ = accessor->GetDetails(js_object, number_);
} else if (exotic_index_state_ != ExoticIndexState::kNotExotic &&
holder->IsJSTypedArray() && IsIntegerIndexedExotic(holder)) {
return INTEGER_INDEXED_EXOTIC;
} else if (!map->is_dictionary_map()) {
DescriptorArray* descriptors = map->instance_descriptors();
int number = descriptors->SearchWithCache(*name_, map);

View File

@ -318,7 +318,8 @@ void JSObject::JSObjectVerify() {
// pointer may point to a one pointer filler map.
if (ElementsAreSafeToExamine()) {
CHECK_EQ((map()->has_fast_smi_or_object_elements() ||
(elements() == GetHeap()->empty_fixed_array())),
(elements() == GetHeap()->empty_fixed_array()) ||
HasFastStringWrapperElements()),
(elements()->map() == GetHeap()->fixed_array_map() ||
elements()->map() == GetHeap()->fixed_cow_array_map()));
CHECK(map()->has_fast_object_elements() == HasFastObjectElements());
@ -1069,7 +1070,8 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) {
case FAST_HOLEY_DOUBLE_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case FAST_ELEMENTS: {
case FAST_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS: {
info->number_of_objects_with_fast_elements_++;
int holes = 0;
FixedArray* e = FixedArray::cast(elements());
@ -1093,7 +1095,8 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) {
info->number_of_fast_used_elements_ += e->length();
break;
}
case DICTIONARY_ELEMENTS: {
case DICTIONARY_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS: {
SeededNumberDictionary* dict = element_dictionary();
info->number_of_slow_used_elements_ += dict->NumberOfElements();
info->number_of_slow_unused_elements_ +=
@ -1102,6 +1105,7 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) {
}
case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case NO_ELEMENTS:
break;
}
}

View File

@ -1954,7 +1954,8 @@ void JSObject::SetMapAndElements(Handle<JSObject> object,
Handle<FixedArrayBase> value) {
JSObject::MigrateToMap(object, new_map);
DCHECK((object->map()->has_fast_smi_or_object_elements() ||
(*value == object->GetHeap()->empty_fixed_array())) ==
(*value == object->GetHeap()->empty_fixed_array()) ||
object->map()->has_fast_string_wrapper_elements()) ==
(value->map() == object->GetHeap()->fixed_array_map() ||
value->map() == object->GetHeap()->fixed_cow_array_map()));
DCHECK((*value == object->GetHeap()->empty_fixed_array()) ||
@ -2336,19 +2337,6 @@ bool Object::ToArrayIndex(uint32_t* index) {
}
bool Object::IsStringObjectWithCharacterAt(uint32_t index) {
if (!this->IsJSValue()) return false;
JSValue* js_value = JSValue::cast(this);
if (!js_value->value()->IsString()) return false;
String* str = String::cast(js_value->value());
if (index >= static_cast<uint32_t>(str->length())) return false;
return true;
}
void Object::VerifyApiCallResultType() {
#if DEBUG
if (!(IsSmi() || IsString() || IsSymbol() || IsJSReceiver() ||
@ -2365,9 +2353,8 @@ Object* FixedArray::get(int index) const {
return READ_FIELD(this, kHeaderSize + index * kPointerSize);
}
Handle<Object> FixedArray::get(Handle<FixedArray> array, int index) {
return handle(array->get(index), array->GetIsolate());
Handle<Object> FixedArray::get(FixedArray* array, int index, Isolate* isolate) {
return handle(array->get(index), isolate);
}
@ -2412,13 +2399,12 @@ uint64_t FixedDoubleArray::get_representation(int index) {
return READ_UINT64_FIELD(this, offset);
}
Handle<Object> FixedDoubleArray::get(Handle<FixedDoubleArray> array,
int index) {
Handle<Object> FixedDoubleArray::get(FixedDoubleArray* array, int index,
Isolate* isolate) {
if (array->is_the_hole(index)) {
return array->GetIsolate()->factory()->the_hole_value();
return isolate->factory()->the_hole_value();
} else {
return array->GetIsolate()->factory()->NewNumber(array->get_scalar(index));
return isolate->factory()->NewNumber(array->get_scalar(index));
}
}
@ -2875,8 +2861,7 @@ void Map::SetEnumLength(int length) {
FixedArrayBase* Map::GetInitialElements() {
if (has_fast_smi_or_object_elements() ||
has_fast_double_elements()) {
if (has_fast_elements() || has_fast_string_wrapper_elements()) {
DCHECK(!GetHeap()->InNewSpace(GetHeap()->empty_fixed_array()));
return GetHeap()->empty_fixed_array();
} else if (has_fixed_typed_array_elements()) {
@ -4236,11 +4221,9 @@ double FixedTypedArray<Float64ArrayTraits>::from_double(double value) {
return value;
}
template <class Traits>
Handle<Object> FixedTypedArray<Traits>::get(
Handle<FixedTypedArray<Traits> > array,
int index) {
Handle<Object> FixedTypedArray<Traits>::get(FixedTypedArray<Traits>* array,
int index) {
return Traits::ToHandle(array->GetIsolate(), array->get_scalar(index));
}
@ -4617,6 +4600,10 @@ bool Map::has_sloppy_arguments_elements() {
return IsSloppyArgumentsElements(elements_kind());
}
bool Map::has_fast_string_wrapper_elements() {
return elements_kind() == FAST_STRING_WRAPPER_ELEMENTS;
}
bool Map::has_fixed_typed_array_elements() {
return IsFixedTypedArrayElementsKind(elements_kind());
}
@ -6752,6 +6739,17 @@ bool JSObject::HasSloppyArgumentsElements() {
return IsSloppyArgumentsElements(GetElementsKind());
}
bool JSObject::HasStringWrapperElements() {
return IsStringWrapperElementsKind(GetElementsKind());
}
bool JSObject::HasFastStringWrapperElements() {
return GetElementsKind() == FAST_STRING_WRAPPER_ELEMENTS;
}
bool JSObject::HasSlowStringWrapperElements() {
return GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS;
}
bool JSObject::HasFixedTypedArrayElements() {
HeapObject* array = elements();
@ -6792,7 +6790,7 @@ GlobalDictionary* JSObject::global_dictionary() {
SeededNumberDictionary* JSObject::element_dictionary() {
DCHECK(HasDictionaryElements());
DCHECK(HasDictionaryElements() || HasSlowStringWrapperElements());
return SeededNumberDictionary::cast(elements());
}

View File

@ -326,7 +326,8 @@ void JSObject::PrintElements(std::ostream& os) { // NOLINT
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case FAST_ELEMENTS: {
case FAST_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS: {
// Print in array notation for non-sparse arrays.
FixedArray* p = FixedArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
@ -371,6 +372,7 @@ void JSObject::PrintElements(std::ostream& os) { // NOLINT
#undef PRINT_ELEMENTS
case DICTIONARY_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
os << "\n - elements: ";
elements()->Print(os);
break;
@ -385,6 +387,8 @@ void JSObject::PrintElements(std::ostream& os) { // NOLINT
<< "\n arguments: " << Brief(p->get(1));
break;
}
case NO_ELEMENTS:
break;
}
}

View File

@ -1058,7 +1058,8 @@ MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
Handle<FixedArray> JSObject::EnsureWritableFastElements(
Handle<JSObject> object) {
DCHECK(object->HasFastSmiOrObjectElements());
DCHECK(object->HasFastSmiOrObjectElements() ||
object->HasFastStringWrapperElements());
Isolate* isolate = object->GetIsolate();
Handle<FixedArray> elems(FixedArray::cast(object->elements()), isolate);
if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems;
@ -5876,14 +5877,18 @@ Handle<SeededNumberDictionary> JSObject::NormalizeElements(
DCHECK(object->HasFastSmiOrObjectElements() ||
object->HasFastDoubleElements() ||
object->HasFastArgumentsElements());
object->HasFastArgumentsElements() ||
object->HasFastStringWrapperElements());
Handle<SeededNumberDictionary> dictionary =
GetNormalizedElementDictionary(object, elements);
// Switch to using the dictionary as the backing storage for elements.
ElementsKind target_kind =
is_arguments ? SLOW_SLOPPY_ARGUMENTS_ELEMENTS : DICTIONARY_ELEMENTS;
ElementsKind target_kind = is_arguments
? SLOW_SLOPPY_ARGUMENTS_ELEMENTS
: object->HasFastStringWrapperElements()
? SLOW_STRING_WRAPPER_ELEMENTS
: DICTIONARY_ELEMENTS;
Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind);
// Set the new map first to satify the elements type assert in set_elements().
JSObject::MigrateToMap(object, new_map);
@ -5904,7 +5909,9 @@ Handle<SeededNumberDictionary> JSObject::NormalizeElements(
}
#endif
DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements());
DCHECK(object->HasDictionaryElements() ||
object->HasSlowArgumentsElements() ||
object->HasSlowStringWrapperElements());
return dictionary;
}
@ -7407,9 +7414,7 @@ Maybe<bool> JSProxy::GetOwnPropertyDescriptor(Isolate* isolate,
bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
ElementsKind kind,
Object* object) {
DCHECK(IsFastObjectElementsKind(kind) ||
kind == DICTIONARY_ELEMENTS);
if (IsFastObjectElementsKind(kind)) {
if (IsFastObjectElementsKind(kind) || kind == FAST_STRING_WRAPPER_ELEMENTS) {
int length = IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value()
: elements->length();
@ -7418,6 +7423,7 @@ bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
if (!element->IsTheHole() && element == object) return true;
}
} else {
DCHECK(kind == DICTIONARY_ELEMENTS || kind == SLOW_STRING_WRAPPER_ELEMENTS);
Object* key =
SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
if (!key->IsUndefined()) return true;
@ -7468,7 +7474,9 @@ bool JSObject::ReferencesObject(Object* obj) {
break;
case FAST_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case DICTIONARY_ELEMENTS: {
case DICTIONARY_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS: {
FixedArray* elements = FixedArray::cast(this->elements());
if (ReferencesObjectFromElements(elements, kind, obj)) return true;
break;
@ -7489,6 +7497,8 @@ bool JSObject::ReferencesObject(Object* obj) {
if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
break;
}
case NO_ELEMENTS:
break;
}
// For functions check the context.
@ -7870,7 +7880,8 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
Handle<SeededNumberDictionary> new_element_dictionary;
if (!object->HasFixedTypedArrayElements() &&
!object->HasDictionaryElements()) {
!object->HasDictionaryElements() &&
!object->HasSlowStringWrapperElements()) {
int length =
object->IsJSArray()
? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
@ -7917,7 +7928,11 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
new_map->set_is_extensible(false);
if (!new_element_dictionary.is_null()) {
new_map->set_elements_kind(DICTIONARY_ELEMENTS);
ElementsKind new_kind =
IsStringWrapperElementsKind(old_map->elements_kind())
? SLOW_STRING_WRAPPER_ELEMENTS
: DICTIONARY_ELEMENTS;
new_map->set_elements_kind(new_kind);
}
JSObject::MigrateToMap(object, new_map);
@ -7942,7 +7957,8 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition(
return Just(true);
}
DCHECK(object->map()->has_dictionary_elements());
DCHECK(object->map()->has_dictionary_elements() ||
object->map()->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS);
if (!new_element_dictionary.is_null()) {
object->set_elements(*new_element_dictionary);
}
@ -8134,12 +8150,8 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
}
// Deep copy own elements.
// Pixel elements cannot be created using an object literal.
DCHECK(!copy->HasFixedTypedArrayElements());
switch (kind) {
case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS: {
Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
@ -8151,9 +8163,6 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
} else {
for (int i = 0; i < elements->length(); i++) {
Handle<Object> value(elements->get(i), isolate);
DCHECK(value->IsSmi() ||
value->IsTheHole() ||
(IsFastObjectElementsKind(copy->GetElementsKind())));
if (value->IsJSObject()) {
Handle<JSObject> result;
ASSIGN_RETURN_ON_EXCEPTION(
@ -8194,16 +8203,25 @@ MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
UNIMPLEMENTED();
break;
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
UNREACHABLE();
break;
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case TYPE##_ELEMENTS: \
TYPED_ARRAYS(TYPED_ARRAY_CASE)
#undef TYPED_ARRAY_CASE
// Typed elements cannot be created using an object literal.
UNREACHABLE();
break;
case FAST_SMI_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
case NO_ELEMENTS:
// No contained objects, nothing to do.
break;
}
@ -8309,12 +8327,6 @@ MaybeHandle<Object> JSReceiver::OrdinaryToPrimitive(
// TODO(cbruni/jkummerow): Consider moving this into elements.cc.
bool HasEnumerableElements(JSObject* object) {
if (object->IsJSValue()) {
Object* value = JSValue::cast(object)->value();
if (value->IsString()) {
if (String::cast(value)->length() > 0) return true;
}
}
switch (object->GetElementsKind()) {
case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
@ -8366,6 +8378,14 @@ bool HasEnumerableElements(JSObject* object) {
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
// We're approximating non-empty arguments objects here.
return true;
case FAST_STRING_WRAPPER_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
if (String::cast(JSValue::cast(object)->value())->length() > 0) {
return true;
}
return object->elements()->length() > 0;
case NO_ELEMENTS:
return false;
}
UNREACHABLE();
return true;
@ -8598,8 +8618,8 @@ static Maybe<bool> GetKeysFromInterceptor(Isolate* isolate,
accumulator->AddElementKeysFromInterceptor(
Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)));
} else {
accumulator->AddKeys(
Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)));
accumulator->AddKeys(Handle<JSObject>::cast(v8::Utils::OpenHandle(*result)),
DO_NOT_CONVERT);
}
return Just(true);
}
@ -8655,7 +8675,7 @@ static Maybe<bool> GetKeysFromJSObject(Isolate* isolate,
// Compute the property keys and cache them if possible.
Handle<FixedArray> enum_keys =
JSObject::GetEnumPropertyKeys(object, cache_enum_length);
accumulator->AddKeys(enum_keys);
accumulator->AddKeys(enum_keys, DO_NOT_CONVERT);
} else {
object->CollectOwnPropertyNames(accumulator, *filter);
}
@ -9748,7 +9768,10 @@ Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
transition_marker, reason, SPECIAL_TRANSITION);
new_map->set_is_extensible(false);
if (!IsFixedTypedArrayElementsKind(map->elements_kind())) {
new_map->set_elements_kind(DICTIONARY_ELEMENTS);
ElementsKind new_kind = IsStringWrapperElementsKind(map->elements_kind())
? SLOW_STRING_WRAPPER_ELEMENTS
: DICTIONARY_ELEMENTS;
new_map->set_elements_kind(new_kind);
}
return new_map;
}
@ -15783,6 +15806,9 @@ static ElementsKind BestFittingFastElementsKind(JSObject* object) {
if (object->HasSloppyArgumentsElements()) {
return FAST_SLOPPY_ARGUMENTS_ELEMENTS;
}
if (object->HasStringWrapperElements()) {
return FAST_STRING_WRAPPER_ELEMENTS;
}
DCHECK(object->HasDictionaryElements());
SeededNumberDictionary* dictionary = object->element_dictionary();
ElementsKind kind = FAST_HOLEY_SMI_ELEMENTS;
@ -15866,6 +15892,8 @@ Maybe<bool> JSObject::AddDataElement(Handle<JSObject> object, uint32_t index,
if (IsSloppyArgumentsElements(kind)) {
elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1));
dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
} else if (IsStringWrapperElementsKind(kind)) {
dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS;
}
if (attributes != NONE) {
@ -16161,13 +16189,16 @@ int JSObject::GetFastElementsUsage() {
// Fall through.
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS:
return FastHoleyElementsUsage(this, FixedArray::cast(store));
case FAST_HOLEY_DOUBLE_ELEMENTS:
if (elements()->length() == 0) return 0;
return FastHoleyElementsUsage(this, FixedDoubleArray::cast(store));
case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS:
case DICTIONARY_ELEMENTS:
case NO_ELEMENTS:
#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
case TYPE##_ELEMENTS: \
@ -16439,7 +16470,7 @@ void JSObject::CollectOwnPropertyNames(KeyAccumulator* keys,
}
Name* key = descs->GetKey(i);
if (key->FilterKey(filter)) continue;
keys->AddKey(key);
keys->AddKey(key, DO_NOT_CONVERT);
}
} else if (IsJSGlobalObject()) {
GlobalDictionary::CollectKeysTo(handle(global_dictionary()), keys, filter);
@ -16468,21 +16499,6 @@ void JSObject::CollectOwnElementKeys(Handle<JSObject> object,
KeyAccumulator* keys,
PropertyFilter filter) {
if (filter & SKIP_STRINGS) return;
uint32_t string_keys = 0;
// If this is a String wrapper, add the string indices first,
// as they're guaranteed to precede the elements in numerical order
// and ascending order is required by ECMA-262, 6th, 9.1.12.
if (object->IsJSValue()) {
Object* val = JSValue::cast(*object)->value();
if (val->IsString() && (filter & ONLY_ALL_CAN_READ) == 0) {
String* str = String::cast(val);
string_keys = str->length();
for (uint32_t i = 0; i < string_keys; i++) {
keys->AddKey(i);
}
}
}
ElementsAccessor* accessor = object->GetElementsAccessor();
accessor->CollectElementIndices(object, keys, kMaxUInt32, filter, 0);
}
@ -16511,7 +16527,8 @@ int JSObject::GetOwnElementKeys(FixedArray* storage, PropertyFilter filter) {
case FAST_SMI_ELEMENTS:
case FAST_ELEMENTS:
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS: {
case FAST_HOLEY_ELEMENTS:
case FAST_STRING_WRAPPER_ELEMENTS: {
int length = IsJSArray() ?
Smi::cast(JSArray::cast(this)->length())->value() :
FixedArray::cast(elements())->length();
@ -16560,7 +16577,8 @@ int JSObject::GetOwnElementKeys(FixedArray* storage, PropertyFilter filter) {
break;
}
case DICTIONARY_ELEMENTS: {
case DICTIONARY_ELEMENTS:
case SLOW_STRING_WRAPPER_ELEMENTS: {
if (storage != NULL) {
element_dictionary()->CopyKeysTo(storage, counter, filter,
SeededNumberDictionary::SORTED);
@ -16610,6 +16628,8 @@ int JSObject::GetOwnElementKeys(FixedArray* storage, PropertyFilter filter) {
}
break;
}
case NO_ELEMENTS:
break;
}
DCHECK(!storage || storage->length() == counter);
@ -18507,7 +18527,7 @@ void Dictionary<Derived, Shape, Key>::CollectKeysTo(
for (int i = 0; i < array_size; i++) {
int index = Smi::cast(array->get(i))->value();
keys->AddKey(dictionary->KeyAt(index));
keys->AddKey(dictionary->KeyAt(index), DO_NOT_CONVERT);
}
}

View File

@ -1351,10 +1351,6 @@ class Object {
// allow kMaxUInt32.
inline bool ToArrayIndex(uint32_t* index);
// Returns true if this is a JSValue containing a string and the index is
// < the length of the string. Used to implement [] on strings.
inline bool IsStringObjectWithCharacterAt(uint32_t index);
DECLARE_VERIFIER(Object)
#ifdef VERIFY_HEAP
// Verify a pointer is a valid object pointer.
@ -2030,6 +2026,7 @@ class JSObject: public JSReceiver {
// ElementsKind.
inline bool HasFastHoleyElements();
inline bool HasSloppyArgumentsElements();
inline bool HasStringWrapperElements();
inline bool HasDictionaryElements();
inline bool HasFixedTypedArrayElements();
@ -2047,6 +2044,8 @@ class JSObject: public JSReceiver {
inline bool HasFastArgumentsElements();
inline bool HasSlowArgumentsElements();
inline bool HasFastStringWrapperElements();
inline bool HasSlowStringWrapperElements();
inline SeededNumberDictionary* element_dictionary(); // Gets slow elements.
// Requires: HasFastElements().
@ -2634,7 +2633,8 @@ class FixedArray: public FixedArrayBase {
public:
// Setter and getter for elements.
inline Object* get(int index) const;
static inline Handle<Object> get(Handle<FixedArray> array, int index);
static inline Handle<Object> get(FixedArray* array, int index,
Isolate* isolate);
// Setter that uses write barrier.
inline void set(int index, Object* value);
inline bool is_the_hole(int index);
@ -2721,7 +2721,8 @@ class FixedDoubleArray: public FixedArrayBase {
// Setter and getter for elements.
inline double get_scalar(int index);
inline uint64_t get_representation(int index);
static inline Handle<Object> get(Handle<FixedDoubleArray> array, int index);
static inline Handle<Object> get(FixedDoubleArray* array, int index,
Isolate* isolate);
inline void set(int index, double value);
inline void set_the_hole(int index);
@ -4559,7 +4560,7 @@ class FixedTypedArray: public FixedTypedArrayBase {
DECLARE_CAST(FixedTypedArray<Traits>)
inline ElementType get_scalar(int index);
static inline Handle<Object> get(Handle<FixedTypedArray> array, int index);
static inline Handle<Object> get(FixedTypedArray* array, int index);
inline void set(int index, ElementType value);
static inline ElementType from_int(int value);
@ -5675,6 +5676,7 @@ class Map: public HeapObject {
inline bool has_fast_double_elements();
inline bool has_fast_elements();
inline bool has_sloppy_arguments_elements();
inline bool has_fast_string_wrapper_elements();
inline bool has_fixed_typed_array_elements();
inline bool has_dictionary_elements();

View File

@ -58,9 +58,8 @@ RUNTIME_FUNCTION(Runtime_JSProxyCall) {
ElementsAccessor* accessor = arg_array->GetElementsAccessor();
{
DisallowHeapAllocation no_gc;
FixedArrayBase* elements = arg_array->elements();
for (int i = 0; i < arguments_length; i++) {
accessor->Set(elements, i, args[i + 1]);
accessor->Set(arg_array, i, args[i + 1]);
}
}
// 8. Return Call(trap, handler, «target, thisArgument, argArray»).
@ -119,9 +118,8 @@ RUNTIME_FUNCTION(Runtime_JSProxyConstruct) {
ElementsAccessor* accessor = arg_array->GetElementsAccessor();
{
DisallowHeapAllocation no_gc;
FixedArrayBase* elements = arg_array->elements();
for (int i = 0; i < arguments_length; i++) {
accessor->Set(elements, i, args[i + 1]);
accessor->Set(arg_array, i, args[i + 1]);
}
}
// 8. Let newObj be ? Call(trap, handler, «target, argArray, newTarget »).

View File

@ -1477,7 +1477,7 @@ TEST(InterpreterTestIn) {
i::Factory* factory = handles.main_isolate()->factory();
// Allocate an array
Handle<i::JSArray> array =
factory->NewJSArray(i::ElementsKind::FAST_SMI_ELEMENTS);
factory->NewJSArray(0, i::ElementsKind::FAST_SMI_ELEMENTS);
// Check for these properties on the array object
const char* properties[] = {"length", "fuzzle", "x", "0"};
for (size_t i = 0; i < arraysize(properties); i++) {

View File

@ -61,9 +61,9 @@ Handle<T> GetLexical(const char* name) {
ScriptContextTable::LookupResult lookup_result;
if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
Handle<Object> result =
FixedArray::get(ScriptContextTable::GetContext(
FixedArray::get(*ScriptContextTable::GetContext(
script_contexts, lookup_result.context_index),
lookup_result.slot_index);
lookup_result.slot_index, isolate);
return Handle<T>::cast(result);
}
return Handle<T>();

View File

@ -1060,7 +1060,7 @@ TEST(DoScavenge) {
CcTest::heap()->CollectGarbage(i::NEW_SPACE);
// Create temp object in the new space.
Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS);
Handle<JSArray> temp = factory->NewJSArray(0, FAST_ELEMENTS);
CHECK(isolate->heap()->new_space()->Contains(*temp));
// Construct a double value that looks like a pointer to the new space object
@ -1399,7 +1399,7 @@ TEST(StoreBufferScanOnScavenge) {
CHECK(isolate->heap()->old_space()->Contains(*obj));
// Create temp object in the new space.
Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS);
Handle<JSArray> temp = factory->NewJSArray(0, FAST_ELEMENTS);
CHECK(isolate->heap()->new_space()->Contains(*temp));
// Construct a double value that looks like a pointer to the new space object