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:
parent
0e2854585b
commit
f4872f7477
@ -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>(
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
451
src/elements.cc
451
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,
|
||||
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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
118
src/objects.cc
118
src/objects.cc
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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 »).
|
||||
|
@ -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++) {
|
||||
|
@ -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>();
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user