[cleanup] Unify enum cache handling.
Introduce a proper empty_descriptor_array, which has the proper layout (length is 2 and the two fields are set properly). Also add a special EnumCache class and a matching empty_enum_cache. The contract now is that we only need to check the EnumLength on the map to know whether we are allowed to use the enum cache. This greatly simplifies the handling of the enum cache (and also the descriptor arrays), especially for the future work on optimizing keyed access via the enum cache indices. Bug: v8:6702 Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng Change-Id: I5ef517a3041163cd65ef003f691139ea52233e83 Reviewed-on: https://chromium-review.googlesource.com/641030 Commit-Queue: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/master@{#47697}
This commit is contained in:
parent
e84eceabbe
commit
562663d545
@ -4683,7 +4683,7 @@ MaybeLocal<Array> v8::Object::GetPropertyNames(Local<Context> context,
|
||||
value = accumulator.GetKeys(i::GetKeysConversion::kKeepNumbers);
|
||||
DCHECK(self->map()->EnumLength() == i::kInvalidEnumCacheSentinel ||
|
||||
self->map()->EnumLength() == 0 ||
|
||||
self->map()->instance_descriptors()->GetEnumCache() != *value);
|
||||
self->map()->instance_descriptors()->GetEnumCache()->keys() != *value);
|
||||
auto result = isolate->factory()->NewJSArrayWithElements(value);
|
||||
RETURN_ESCAPED(Utils::ToLocal(result));
|
||||
}
|
||||
|
@ -48,14 +48,12 @@ std::tuple<Node*, Node*, Node*> ForInBuiltinsAssembler::EmitForInPrepare(
|
||||
BIND(&use_cache);
|
||||
Node* map = LoadMap(object);
|
||||
Node* enum_length = EnumLength(map);
|
||||
GotoIf(WordEqual(enum_length, SmiConstant(0)), nothing_to_iterate);
|
||||
Node* descriptors = LoadMapDescriptors(map);
|
||||
Node* cache_offset =
|
||||
LoadObjectField(descriptors, DescriptorArray::kEnumCacheBridgeOffset);
|
||||
Node* enum_cache = LoadObjectField(
|
||||
cache_offset, DescriptorArray::kEnumCacheBridgeCacheOffset);
|
||||
Node* enum_cache =
|
||||
LoadObjectField(descriptors, DescriptorArray::kEnumCacheOffset);
|
||||
Node* enum_keys = LoadObjectField(enum_cache, EnumCache::kKeysOffset);
|
||||
|
||||
return std::make_tuple(map, enum_cache, enum_length);
|
||||
return std::make_tuple(map, enum_keys, enum_length);
|
||||
}
|
||||
|
||||
Node* ForInBuiltinsAssembler::EnumLength(Node* map) {
|
||||
|
@ -134,12 +134,12 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
|
||||
{
|
||||
// The {object} has a usable enum cache, use that.
|
||||
Node* object_descriptors = LoadMapDescriptors(object_map);
|
||||
Node* object_enum_cache_bridge = LoadObjectField(
|
||||
object_descriptors, DescriptorArray::kEnumCacheBridgeOffset);
|
||||
Node* object_enum_cache = LoadObjectField(
|
||||
object_enum_cache_bridge, DescriptorArray::kEnumCacheBridgeCacheOffset);
|
||||
Node* object_enum_cache =
|
||||
LoadObjectField(object_descriptors, DescriptorArray::kEnumCacheOffset);
|
||||
Node* object_enum_keys =
|
||||
LoadObjectField(object_enum_cache, EnumCache::kKeysOffset);
|
||||
|
||||
// Allocate a JSArray and copy the elements from the {object_enum_cache}.
|
||||
// Allocate a JSArray and copy the elements from the {object_enum_keys}.
|
||||
Node* array = nullptr;
|
||||
Node* elements = nullptr;
|
||||
Node* native_context = LoadNativeContext(context);
|
||||
@ -148,7 +148,7 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
|
||||
std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
|
||||
PACKED_ELEMENTS, array_map, array_length, nullptr, object_enum_length,
|
||||
INTPTR_PARAMETERS);
|
||||
CopyFixedArrayElements(PACKED_ELEMENTS, object_enum_cache, elements,
|
||||
CopyFixedArrayElements(PACKED_ELEMENTS, object_enum_keys, elements,
|
||||
object_enum_length, SKIP_WRITE_BARRIER);
|
||||
Return(array);
|
||||
}
|
||||
|
@ -509,20 +509,9 @@ FieldAccess AccessBuilder::ForFixedTypedArrayBaseExternalPointer() {
|
||||
}
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForDescriptorArrayEnumCacheBridge() {
|
||||
FieldAccess AccessBuilder::ForDescriptorArrayEnumCache() {
|
||||
FieldAccess access = {
|
||||
kTaggedBase, DescriptorArray::kEnumCacheBridgeOffset,
|
||||
Handle<Name>(), MaybeHandle<Map>(),
|
||||
Type::OtherInternal(), MachineType::TaggedPointer(),
|
||||
kPointerWriteBarrier};
|
||||
return access;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForDescriptorArrayEnumCacheBridgeCache() {
|
||||
FieldAccess access = {
|
||||
kTaggedBase, DescriptorArray::kEnumCacheBridgeCacheOffset,
|
||||
kTaggedBase, DescriptorArray::kEnumCacheOffset,
|
||||
Handle<Name>(), MaybeHandle<Map>(),
|
||||
Type::OtherInternal(), MachineType::TaggedPointer(),
|
||||
kPointerWriteBarrier};
|
||||
@ -940,7 +929,7 @@ ElementAccess AccessBuilder::ForFixedDoubleArrayElement() {
|
||||
}
|
||||
|
||||
// static
|
||||
ElementAccess AccessBuilder::ForDescriptorArrayEnumCacheBridgeCacheElement() {
|
||||
ElementAccess AccessBuilder::ForEnumCacheKeysElement() {
|
||||
ElementAccess access = {kTaggedBase, FixedArray::kHeaderSize,
|
||||
Type::InternalizedString(),
|
||||
MachineType::TaggedPointer(), kPointerWriteBarrier};
|
||||
|
@ -169,11 +169,8 @@ class V8_EXPORT_PRIVATE AccessBuilder final
|
||||
// Provides access to FixedTypedArrayBase::external_pointer() field.
|
||||
static FieldAccess ForFixedTypedArrayBaseExternalPointer();
|
||||
|
||||
// Provides access to DescriptorArray::enum_cache_bridge() field.
|
||||
static FieldAccess ForDescriptorArrayEnumCacheBridge();
|
||||
|
||||
// Provides access to DescriptorArray::enum_cache_bridge_cache() field.
|
||||
static FieldAccess ForDescriptorArrayEnumCacheBridgeCache();
|
||||
// Provides access to DescriptorArray::enum_cache() field.
|
||||
static FieldAccess ForDescriptorArrayEnumCache();
|
||||
|
||||
// Provides access to Map::bit_field() byte.
|
||||
static FieldAccess ForMapBitField();
|
||||
@ -285,8 +282,8 @@ class V8_EXPORT_PRIVATE AccessBuilder final
|
||||
// Provides access to FixedDoubleArray elements.
|
||||
static ElementAccess ForFixedDoubleArrayElement();
|
||||
|
||||
// Provides access to EnumCache elements.
|
||||
static ElementAccess ForDescriptorArrayEnumCacheBridgeCacheElement();
|
||||
// Provides access to EnumCache::keys elements.
|
||||
static ElementAccess ForEnumCacheKeysElement();
|
||||
|
||||
// Provides access to Fixed{type}TypedArray and External{type}Array elements.
|
||||
static ElementAccess ForTypedArrayElement(ExternalArrayType type,
|
||||
|
@ -270,7 +270,7 @@ Reduction JSTypeHintLowering::ReduceForInNextOperation(
|
||||
receiver, cache_type, effect, control);
|
||||
Node* node = jsgraph()->graph()->NewNode(
|
||||
jsgraph()->simplified()->LoadElement(
|
||||
AccessBuilder::ForDescriptorArrayEnumCacheBridgeCacheElement()),
|
||||
AccessBuilder::ForEnumCacheKeysElement()),
|
||||
cache_array, index, effect, control);
|
||||
return Reduction(node);
|
||||
}
|
||||
|
@ -102,6 +102,11 @@ Handle<PrototypeInfo> Factory::NewPrototypeInfo() {
|
||||
return result;
|
||||
}
|
||||
|
||||
Handle<EnumCache> Factory::NewEnumCache(Handle<FixedArray> keys,
|
||||
Handle<FixedArray> indices) {
|
||||
return Handle<EnumCache>::cast(NewTuple2(keys, indices));
|
||||
}
|
||||
|
||||
Handle<Tuple2> Factory::NewTuple2(Handle<Object> value1,
|
||||
Handle<Object> value2) {
|
||||
Handle<Tuple2> result = Handle<Tuple2>::cast(NewStruct(TUPLE2_TYPE));
|
||||
|
@ -126,6 +126,10 @@ class V8_EXPORT_PRIVATE Factory final {
|
||||
// Create a new PrototypeInfo struct.
|
||||
Handle<PrototypeInfo> NewPrototypeInfo();
|
||||
|
||||
// Create a new EnumCache struct.
|
||||
Handle<EnumCache> NewEnumCache(Handle<FixedArray> keys,
|
||||
Handle<FixedArray> indices);
|
||||
|
||||
// Create a new Tuple2 struct.
|
||||
Handle<Tuple2> NewTuple2(Handle<Object> value1, Handle<Object> value2);
|
||||
|
||||
|
@ -2426,6 +2426,11 @@ bool Heap::CreateInitialMaps() {
|
||||
|
||||
ALLOCATE_PARTIAL_MAP(FIXED_ARRAY_TYPE, kVariableSizeSentinel, fixed_array);
|
||||
fixed_array_map()->set_elements_kind(HOLEY_ELEMENTS);
|
||||
ALLOCATE_PARTIAL_MAP(FIXED_ARRAY_TYPE, kVariableSizeSentinel,
|
||||
fixed_cow_array)
|
||||
fixed_cow_array_map()->set_elements_kind(HOLEY_ELEMENTS);
|
||||
DCHECK_NE(fixed_array_map(), fixed_cow_array_map());
|
||||
|
||||
ALLOCATE_PARTIAL_MAP(ODDBALL_TYPE, Oddball::kSize, undefined);
|
||||
ALLOCATE_PARTIAL_MAP(ODDBALL_TYPE, Oddball::kSize, null);
|
||||
ALLOCATE_PARTIAL_MAP(ODDBALL_TYPE, Oddball::kSize, the_hole);
|
||||
@ -2464,21 +2469,48 @@ bool Heap::CreateInitialMaps() {
|
||||
// Set preliminary exception sentinel value before actually initializing it.
|
||||
set_exception(null_value());
|
||||
|
||||
// Setup the struct maps first (needed for the EnumCache).
|
||||
for (unsigned i = 0; i < arraysize(struct_table); i++) {
|
||||
const StructTable& entry = struct_table[i];
|
||||
Map* map;
|
||||
if (!AllocatePartialMap(entry.type, entry.size).To(&map)) return false;
|
||||
roots_[entry.index] = map;
|
||||
}
|
||||
|
||||
// Allocate the empty enum cache.
|
||||
{
|
||||
AllocationResult allocation = Allocate(tuple2_map(), OLD_SPACE);
|
||||
if (!allocation.To(&obj)) return false;
|
||||
}
|
||||
set_empty_enum_cache(EnumCache::cast(obj));
|
||||
EnumCache::cast(obj)->set_keys(empty_fixed_array());
|
||||
EnumCache::cast(obj)->set_indices(empty_fixed_array());
|
||||
|
||||
// Allocate the empty descriptor array.
|
||||
{
|
||||
AllocationResult allocation = AllocateEmptyFixedArray();
|
||||
AllocationResult allocation =
|
||||
AllocateUninitializedFixedArray(DescriptorArray::kFirstIndex, TENURED);
|
||||
if (!allocation.To(&obj)) return false;
|
||||
}
|
||||
set_empty_descriptor_array(DescriptorArray::cast(obj));
|
||||
DescriptorArray::cast(obj)->set(DescriptorArray::kDescriptorLengthIndex,
|
||||
Smi::kZero);
|
||||
DescriptorArray::cast(obj)->set(DescriptorArray::kEnumCacheIndex,
|
||||
empty_enum_cache());
|
||||
|
||||
// Fix the instance_descriptors for the existing maps.
|
||||
FinalizePartialMap(this, meta_map());
|
||||
FinalizePartialMap(this, fixed_array_map());
|
||||
FinalizePartialMap(this, fixed_cow_array_map());
|
||||
FinalizePartialMap(this, undefined_map());
|
||||
undefined_map()->set_is_undetectable();
|
||||
FinalizePartialMap(this, null_map());
|
||||
null_map()->set_is_undetectable();
|
||||
FinalizePartialMap(this, the_hole_map());
|
||||
for (unsigned i = 0; i < arraysize(struct_table); ++i) {
|
||||
const StructTable& entry = struct_table[i];
|
||||
FinalizePartialMap(this, Map::cast(roots_[entry.index]));
|
||||
}
|
||||
|
||||
{ // Map allocation
|
||||
#define ALLOCATE_MAP(instance_type, size, field_name) \
|
||||
@ -2499,10 +2531,6 @@ bool Heap::CreateInitialMaps() {
|
||||
(constructor_function_index)); \
|
||||
}
|
||||
|
||||
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, fixed_cow_array)
|
||||
fixed_cow_array_map()->set_elements_kind(HOLEY_ELEMENTS);
|
||||
DCHECK_NE(fixed_array_map(), fixed_cow_array_map());
|
||||
|
||||
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, scope_info)
|
||||
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, module_info)
|
||||
ALLOCATE_VARSIZE_MAP(FEEDBACK_VECTOR_TYPE, feedback_vector)
|
||||
@ -2580,13 +2608,6 @@ bool Heap::CreateInitialMaps() {
|
||||
|
||||
ALLOCATE_VARSIZE_MAP(TRANSITION_ARRAY_TYPE, transition_array)
|
||||
|
||||
for (unsigned i = 0; i < arraysize(struct_table); i++) {
|
||||
const StructTable& entry = struct_table[i];
|
||||
Map* map;
|
||||
if (!AllocateMap(entry.type, entry.size).To(&map)) return false;
|
||||
roots_[entry.index] = map;
|
||||
}
|
||||
|
||||
ALLOCATE_VARSIZE_MAP(HASH_TABLE_TYPE, hash_table)
|
||||
ALLOCATE_VARSIZE_MAP(HASH_TABLE_TYPE, ordered_hash_table)
|
||||
ALLOCATE_VARSIZE_MAP(HASH_TABLE_TYPE, unseeded_number_dictionary)
|
||||
@ -4275,12 +4296,13 @@ AllocationResult Heap::AllocatePropertyArray(int length,
|
||||
return result;
|
||||
}
|
||||
|
||||
AllocationResult Heap::AllocateUninitializedFixedArray(int length) {
|
||||
AllocationResult Heap::AllocateUninitializedFixedArray(
|
||||
int length, PretenureFlag pretenure) {
|
||||
if (length == 0) return empty_fixed_array();
|
||||
|
||||
HeapObject* obj = nullptr;
|
||||
{
|
||||
AllocationResult allocation = AllocateRawFixedArray(length, NOT_TENURED);
|
||||
AllocationResult allocation = AllocateRawFixedArray(length, pretenure);
|
||||
if (!allocation.To(&obj)) return allocation;
|
||||
}
|
||||
|
||||
|
@ -162,6 +162,7 @@ using v8::MemoryPressureLevel;
|
||||
V(Map, optimized_out_map, OptimizedOutMap) \
|
||||
V(Map, stale_register_map, StaleRegisterMap) \
|
||||
/* Canonical empty values */ \
|
||||
V(EnumCache, empty_enum_cache, EmptyEnumCache) \
|
||||
V(PropertyArray, empty_property_array, EmptyPropertyArray) \
|
||||
V(ByteArray, empty_byte_array, EmptyByteArray) \
|
||||
V(FixedTypedArrayBase, empty_fixed_uint8_array, EmptyFixedUint8Array) \
|
||||
@ -2082,7 +2083,8 @@ class Heap {
|
||||
T t, int chars, uint32_t hash_field);
|
||||
|
||||
// Allocates an uninitialized fixed array. It must be filled by the caller.
|
||||
MUST_USE_RESULT AllocationResult AllocateUninitializedFixedArray(int length);
|
||||
MUST_USE_RESULT AllocationResult AllocateUninitializedFixedArray(
|
||||
int length, PretenureFlag pretenure = NOT_TENURED);
|
||||
|
||||
// Make a copy of src and return it.
|
||||
MUST_USE_RESULT inline AllocationResult CopyFixedArray(FixedArray* src);
|
||||
|
@ -2920,7 +2920,7 @@ void MarkCompactCollector::TrimDescriptorArray(Map* map,
|
||||
to_trim * DescriptorArray::kEntrySize);
|
||||
descriptors->SetNumberOfDescriptors(number_of_own_descriptors);
|
||||
|
||||
if (descriptors->HasEnumCache()) TrimEnumCache(map, descriptors);
|
||||
TrimEnumCache(map, descriptors);
|
||||
descriptors->Sort();
|
||||
|
||||
if (FLAG_unbox_double_fields) {
|
||||
@ -2942,16 +2942,17 @@ void MarkCompactCollector::TrimEnumCache(Map* map,
|
||||
live_enum = map->NumberOfEnumerableProperties();
|
||||
}
|
||||
if (live_enum == 0) return descriptors->ClearEnumCache();
|
||||
EnumCache* enum_cache = descriptors->GetEnumCache();
|
||||
|
||||
FixedArray* enum_cache = descriptors->GetEnumCache();
|
||||
|
||||
int to_trim = enum_cache->length() - live_enum;
|
||||
FixedArray* keys = enum_cache->keys();
|
||||
int to_trim = keys->length() - live_enum;
|
||||
if (to_trim <= 0) return;
|
||||
heap_->RightTrimFixedArray(descriptors->GetEnumCache(), to_trim);
|
||||
heap_->RightTrimFixedArray(keys, to_trim);
|
||||
|
||||
if (!descriptors->HasEnumIndicesCache()) return;
|
||||
FixedArray* enum_indices_cache = descriptors->GetEnumIndicesCache();
|
||||
heap_->RightTrimFixedArray(enum_indices_cache, to_trim);
|
||||
FixedArray* indices = enum_cache->indices();
|
||||
to_trim = indices->length() - live_enum;
|
||||
if (to_trim <= 0) return;
|
||||
heap_->RightTrimFixedArray(indices, to_trim);
|
||||
}
|
||||
|
||||
|
||||
|
@ -432,15 +432,11 @@ void ObjectStatsCollector::RecordMapDetails(Map* map_obj) {
|
||||
if (map_obj->owns_descriptors() && array != heap_->empty_descriptor_array() &&
|
||||
SameLiveness(map_obj, array)) {
|
||||
RecordFixedArrayHelper(map_obj, array, DESCRIPTOR_ARRAY_SUB_TYPE, 0);
|
||||
if (array->HasEnumCache()) {
|
||||
RecordFixedArrayHelper(array, array->GetEnumCache(), ENUM_CACHE_SUB_TYPE,
|
||||
0);
|
||||
}
|
||||
if (array->HasEnumIndicesCache()) {
|
||||
RecordFixedArrayHelper(array, array->GetEnumIndicesCache(),
|
||||
EnumCache* enum_cache = array->GetEnumCache();
|
||||
RecordFixedArrayHelper(array, enum_cache->keys(), ENUM_CACHE_SUB_TYPE, 0);
|
||||
RecordFixedArrayHelper(array, enum_cache->indices(),
|
||||
ENUM_INDICES_CACHE_SUB_TYPE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
FixedArray* code_cache = map_obj->code_cache();
|
||||
if (code_cache->length() > 0) {
|
||||
|
125
src/keys.cc
125
src/keys.cc
@ -259,9 +259,9 @@ void FastKeyAccumulator::Prepare() {
|
||||
}
|
||||
|
||||
namespace {
|
||||
static Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
|
||||
Handle<FixedArray> array,
|
||||
int length) {
|
||||
|
||||
Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
|
||||
Handle<FixedArray> array, int length) {
|
||||
DCHECK_LE(length, array->length());
|
||||
if (array->length() == length) return array;
|
||||
return isolate->factory()->CopyFixedArrayUpTo(array, length);
|
||||
@ -271,76 +271,77 @@ static Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
|
||||
// have to make sure to never directly leak the enum cache.
|
||||
Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
|
||||
Handle<JSObject> object) {
|
||||
Handle<Map> map(object->map());
|
||||
bool cache_enum_length = map->OnlyHasSimpleProperties();
|
||||
Handle<Map> map(object->map(), isolate);
|
||||
Handle<FixedArray> keys(map->instance_descriptors()->GetEnumCache()->keys(),
|
||||
isolate);
|
||||
|
||||
Handle<DescriptorArray> descs =
|
||||
// Check if the {map} has a valid enum length, which implies that it
|
||||
// must have a valid enum cache as well.
|
||||
int enum_length = map->EnumLength();
|
||||
if (enum_length != kInvalidEnumCacheSentinel) {
|
||||
DCHECK(map->OnlyHasSimpleProperties());
|
||||
DCHECK_LE(enum_length, keys->length());
|
||||
DCHECK_EQ(enum_length, map->NumberOfEnumerableProperties());
|
||||
isolate->counters()->enum_cache_hits()->Increment();
|
||||
return ReduceFixedArrayTo(isolate, keys, enum_length);
|
||||
}
|
||||
|
||||
// Determine the actual number of enumerable properties of the {map}.
|
||||
enum_length = map->NumberOfEnumerableProperties();
|
||||
|
||||
// Check if there's already a shared enum cache on the {map}s
|
||||
// DescriptorArray with sufficient number of entries.
|
||||
if (enum_length <= keys->length()) {
|
||||
if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
|
||||
isolate->counters()->enum_cache_hits()->Increment();
|
||||
return ReduceFixedArrayTo(isolate, keys, enum_length);
|
||||
}
|
||||
|
||||
Handle<DescriptorArray> descriptors =
|
||||
Handle<DescriptorArray>(map->instance_descriptors(), isolate);
|
||||
int own_property_count = map->EnumLength();
|
||||
// If the enum length of the given map is set to kInvalidEnumCache, this
|
||||
// means that the map itself has never used the present enum cache. The
|
||||
// first step to using the cache is to set the enum length of the map by
|
||||
// counting the number of own descriptors that are ENUMERABLE_STRINGS.
|
||||
if (own_property_count == kInvalidEnumCacheSentinel) {
|
||||
own_property_count = map->NumberOfEnumerableProperties();
|
||||
} else {
|
||||
DCHECK_EQ(own_property_count, map->NumberOfEnumerableProperties());
|
||||
}
|
||||
|
||||
if (descs->HasEnumCache()) {
|
||||
Handle<FixedArray> keys(descs->GetEnumCache(), isolate);
|
||||
// In case the number of properties required in the enum are actually
|
||||
// present, we can reuse the enum cache. Otherwise, this means that the
|
||||
// enum cache was generated for a previous (smaller) version of the
|
||||
// Descriptor Array. In that case we regenerate the enum cache.
|
||||
if (own_property_count <= keys->length()) {
|
||||
isolate->counters()->enum_cache_hits()->Increment();
|
||||
if (cache_enum_length) map->SetEnumLength(own_property_count);
|
||||
return ReduceFixedArrayTo(isolate, keys, own_property_count);
|
||||
}
|
||||
}
|
||||
|
||||
if (descs->IsEmpty()) {
|
||||
isolate->counters()->enum_cache_hits()->Increment();
|
||||
if (cache_enum_length) map->SetEnumLength(0);
|
||||
return isolate->factory()->empty_fixed_array();
|
||||
}
|
||||
|
||||
isolate->counters()->enum_cache_misses()->Increment();
|
||||
int nod = map->NumberOfOwnDescriptors();
|
||||
|
||||
Handle<FixedArray> storage =
|
||||
isolate->factory()->NewFixedArray(own_property_count);
|
||||
Handle<FixedArray> indices =
|
||||
isolate->factory()->NewFixedArray(own_property_count);
|
||||
|
||||
int size = map->NumberOfOwnDescriptors();
|
||||
// Create the keys array.
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
PropertyDetails details = descs->GetDetails(i);
|
||||
bool fields_only = true;
|
||||
keys = isolate->factory()->NewFixedArray(enum_length);
|
||||
for (int i = 0; i < nod; i++) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
if (details.IsDontEnum()) continue;
|
||||
Object* key = descs->GetKey(i);
|
||||
Object* key = descriptors->GetKey(i);
|
||||
if (key->IsSymbol()) continue;
|
||||
storage->set(index, key);
|
||||
if (!indices.is_null()) {
|
||||
if (details.location() == kField) {
|
||||
DCHECK_EQ(kData, details.kind());
|
||||
FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
|
||||
int load_by_field_index = field_index.GetLoadByFieldIndex();
|
||||
indices->set(index, Smi::FromInt(load_by_field_index));
|
||||
} else {
|
||||
indices = Handle<FixedArray>();
|
||||
}
|
||||
}
|
||||
keys->set(index, key);
|
||||
if (details.location() != kField) fields_only = false;
|
||||
index++;
|
||||
}
|
||||
DCHECK(index == storage->length());
|
||||
DCHECK_EQ(index, keys->length());
|
||||
|
||||
DescriptorArray::SetEnumCache(descs, isolate, storage, indices);
|
||||
if (cache_enum_length) {
|
||||
map->SetEnumLength(own_property_count);
|
||||
// Optionally also create the indices array.
|
||||
Handle<FixedArray> indices = isolate->factory()->empty_fixed_array();
|
||||
if (fields_only) {
|
||||
indices = isolate->factory()->NewFixedArray(enum_length);
|
||||
index = 0;
|
||||
for (int i = 0; i < nod; i++) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
PropertyDetails details = descriptors->GetDetails(i);
|
||||
if (details.IsDontEnum()) continue;
|
||||
Object* key = descriptors->GetKey(i);
|
||||
if (key->IsSymbol()) continue;
|
||||
DCHECK_EQ(kData, details.kind());
|
||||
DCHECK_EQ(kField, details.location());
|
||||
FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
|
||||
indices->set(index, Smi::FromInt(field_index.GetLoadByFieldIndex()));
|
||||
index++;
|
||||
}
|
||||
return storage;
|
||||
DCHECK_EQ(index, indices->length());
|
||||
}
|
||||
|
||||
DescriptorArray::SetEnumCache(descriptors, isolate, keys, indices);
|
||||
if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
template <bool fast_properties>
|
||||
|
@ -370,6 +370,15 @@ void JSObject::JSObjectVerify() {
|
||||
field_type));
|
||||
}
|
||||
}
|
||||
|
||||
if (map()->EnumLength() != kInvalidEnumCacheSentinel) {
|
||||
EnumCache* enum_cache = descriptors->GetEnumCache();
|
||||
FixedArray* keys = enum_cache->keys();
|
||||
FixedArray* indices = enum_cache->indices();
|
||||
DCHECK_LE(map()->EnumLength(), keys->length());
|
||||
DCHECK_IMPLIES(indices != isolate->heap()->empty_fixed_array(),
|
||||
keys->length() == indices->length());
|
||||
}
|
||||
}
|
||||
|
||||
// If a GC was caused while constructing this object, the elements
|
||||
@ -420,7 +429,8 @@ void Map::MapVerify() {
|
||||
void Map::DictionaryMapVerify() {
|
||||
MapVerify();
|
||||
CHECK(is_dictionary_map());
|
||||
CHECK(instance_descriptors()->IsEmpty());
|
||||
CHECK_EQ(kInvalidEnumCacheSentinel, EnumLength());
|
||||
CHECK_EQ(GetHeap()->empty_descriptor_array(), instance_descriptors());
|
||||
CHECK_EQ(0, unused_property_fields());
|
||||
CHECK_EQ(Map::GetVisitorId(this), visitor_id());
|
||||
}
|
||||
@ -435,6 +445,13 @@ void FixedArray::FixedArrayVerify() {
|
||||
Object* e = get(i);
|
||||
VerifyPointer(e);
|
||||
}
|
||||
Heap* heap = GetHeap();
|
||||
if (this == heap->empty_descriptor_array()) {
|
||||
DescriptorArray* descriptors = DescriptorArray::cast(this);
|
||||
CHECK_EQ(2, length());
|
||||
CHECK_EQ(0, descriptors->number_of_descriptors());
|
||||
CHECK_EQ(heap->empty_enum_cache(), descriptors->GetEnumCache());
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyArray::PropertyArrayVerify() {
|
||||
@ -1266,8 +1283,14 @@ void PrototypeInfo::PrototypeInfoVerify() {
|
||||
|
||||
void Tuple2::Tuple2Verify() {
|
||||
CHECK(IsTuple2());
|
||||
Heap* heap = GetHeap();
|
||||
if (this == heap->empty_enum_cache()) {
|
||||
CHECK_EQ(heap->empty_fixed_array(), EnumCache::cast(this)->keys());
|
||||
CHECK_EQ(heap->empty_fixed_array(), EnumCache::cast(this)->indices());
|
||||
} else {
|
||||
VerifyObjectField(kValue1Offset);
|
||||
VerifyObjectField(kValue2Offset);
|
||||
}
|
||||
}
|
||||
|
||||
void Tuple3::Tuple3Verify() {
|
||||
|
@ -314,6 +314,8 @@ bool HeapObject::IsJSCollection() const { return IsJSMap() || IsJSSet(); }
|
||||
|
||||
bool HeapObject::IsDescriptorArray() const { return IsFixedArray(); }
|
||||
|
||||
bool HeapObject::IsEnumCache() const { return IsTuple2(); }
|
||||
|
||||
bool HeapObject::IsFrameArray() const { return IsFixedArray(); }
|
||||
|
||||
bool HeapObject::IsArrayList() const { return IsFixedArray(); }
|
||||
@ -551,6 +553,7 @@ CAST_ACCESSOR(ContextExtension)
|
||||
CAST_ACCESSOR(DeoptimizationInputData)
|
||||
CAST_ACCESSOR(DependentCode)
|
||||
CAST_ACCESSOR(DescriptorArray)
|
||||
CAST_ACCESSOR(EnumCache)
|
||||
CAST_ACCESSOR(FixedArray)
|
||||
CAST_ACCESSOR(FixedArrayBase)
|
||||
CAST_ACCESSOR(FixedDoubleArray)
|
||||
@ -2024,23 +2027,16 @@ Object** FixedArray::RawFieldOfElementAt(int index) {
|
||||
return HeapObject::RawField(this, OffsetOfElementAt(index));
|
||||
}
|
||||
|
||||
bool DescriptorArray::IsEmpty() {
|
||||
DCHECK(length() >= kFirstIndex ||
|
||||
this == GetHeap()->empty_descriptor_array());
|
||||
return length() < kFirstIndex;
|
||||
}
|
||||
|
||||
ACCESSORS(EnumCache, keys, FixedArray, kKeysOffset)
|
||||
ACCESSORS(EnumCache, indices, FixedArray, kIndicesOffset)
|
||||
|
||||
int DescriptorArray::number_of_descriptors() {
|
||||
DCHECK(length() >= kFirstIndex || IsEmpty());
|
||||
int len = length();
|
||||
return len == 0 ? 0 : Smi::ToInt(get(kDescriptorLengthIndex));
|
||||
return Smi::ToInt(get(kDescriptorLengthIndex));
|
||||
}
|
||||
|
||||
|
||||
int DescriptorArray::number_of_descriptors_storage() {
|
||||
int len = length();
|
||||
return len == 0 ? 0 : (len - kFirstIndex) / kEntrySize;
|
||||
return (length() - kFirstIndex) / kEntrySize;
|
||||
}
|
||||
|
||||
|
||||
@ -2050,8 +2046,7 @@ int DescriptorArray::NumberOfSlackDescriptors() {
|
||||
|
||||
|
||||
void DescriptorArray::SetNumberOfDescriptors(int number_of_descriptors) {
|
||||
WRITE_FIELD(
|
||||
this, kDescriptorLengthOffset, Smi::FromInt(number_of_descriptors));
|
||||
set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
|
||||
}
|
||||
|
||||
|
||||
@ -2059,40 +2054,14 @@ inline int DescriptorArray::number_of_entries() {
|
||||
return number_of_descriptors();
|
||||
}
|
||||
|
||||
|
||||
bool DescriptorArray::HasEnumCache() {
|
||||
return !IsEmpty() && !get(kEnumCacheBridgeIndex)->IsSmi();
|
||||
}
|
||||
|
||||
|
||||
void DescriptorArray::CopyEnumCacheFrom(DescriptorArray* array) {
|
||||
set(kEnumCacheBridgeIndex, array->get(kEnumCacheBridgeIndex));
|
||||
set(kEnumCacheIndex, array->get(kEnumCacheIndex));
|
||||
}
|
||||
|
||||
|
||||
FixedArray* DescriptorArray::GetEnumCache() {
|
||||
DCHECK(HasEnumCache());
|
||||
FixedArray* bridge = FixedArray::cast(get(kEnumCacheBridgeIndex));
|
||||
return FixedArray::cast(bridge->get(kEnumCacheBridgeCacheIndex));
|
||||
EnumCache* DescriptorArray::GetEnumCache() {
|
||||
return EnumCache::cast(get(kEnumCacheIndex));
|
||||
}
|
||||
|
||||
|
||||
bool DescriptorArray::HasEnumIndicesCache() {
|
||||
if (IsEmpty()) return false;
|
||||
Object* object = get(kEnumCacheBridgeIndex);
|
||||
if (object->IsSmi()) return false;
|
||||
FixedArray* bridge = FixedArray::cast(object);
|
||||
return !bridge->get(kEnumCacheBridgeIndicesCacheIndex)->IsSmi();
|
||||
}
|
||||
|
||||
|
||||
FixedArray* DescriptorArray::GetEnumIndicesCache() {
|
||||
DCHECK(HasEnumIndicesCache());
|
||||
FixedArray* bridge = FixedArray::cast(get(kEnumCacheBridgeIndex));
|
||||
return FixedArray::cast(bridge->get(kEnumCacheBridgeIndicesCacheIndex));
|
||||
}
|
||||
|
||||
|
||||
// Perform a binary search in a fixed array.
|
||||
template <SearchMode search_mode, typename T>
|
||||
int BinarySearch(T* array, Name* name, int valid_entries,
|
||||
@ -2243,7 +2212,6 @@ int Map::EnumLength() const { return EnumLengthBits::decode(bit_field3()); }
|
||||
void Map::SetEnumLength(int length) {
|
||||
if (length != kInvalidEnumCacheSentinel) {
|
||||
DCHECK(length >= 0);
|
||||
DCHECK(length == 0 || instance_descriptors()->HasEnumCache());
|
||||
DCHECK(length <= NumberOfOwnDescriptors());
|
||||
}
|
||||
set_bit_field3(EnumLengthBits::update(bit_field3(), length));
|
||||
|
@ -5045,9 +5045,7 @@ void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
|
||||
// on a cache always being available once it is set. If the map has more
|
||||
// enumerated descriptors than available in the original cache, the cache
|
||||
// will be lazily replaced by the extended cache when needed.
|
||||
if (descriptors->HasEnumCache()) {
|
||||
new_descriptors->CopyEnumCacheFrom(*descriptors);
|
||||
}
|
||||
|
||||
Isolate* isolate = map->GetIsolate();
|
||||
// Replace descriptors by new_descriptors in all maps that share it. The old
|
||||
@ -10413,12 +10411,12 @@ Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
|
||||
factory->NewFixedArray(LengthFor(size), pretenure);
|
||||
|
||||
result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
|
||||
result->set(kEnumCacheBridgeIndex, Smi::kZero);
|
||||
result->set(kEnumCacheIndex, isolate->heap()->empty_enum_cache());
|
||||
return Handle<DescriptorArray>::cast(result);
|
||||
}
|
||||
|
||||
void DescriptorArray::ClearEnumCache() {
|
||||
set(kEnumCacheBridgeIndex, Smi::kZero);
|
||||
set(kEnumCacheIndex, GetHeap()->empty_enum_cache());
|
||||
}
|
||||
|
||||
void DescriptorArray::Replace(int index, Descriptor* descriptor) {
|
||||
@ -10426,27 +10424,17 @@ void DescriptorArray::Replace(int index, Descriptor* descriptor) {
|
||||
Set(index, descriptor);
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void DescriptorArray::SetEnumCache(Handle<DescriptorArray> descriptors,
|
||||
Isolate* isolate,
|
||||
Handle<FixedArray> new_cache,
|
||||
Handle<FixedArray> new_index_cache) {
|
||||
DCHECK(!descriptors->IsEmpty());
|
||||
FixedArray* bridge_storage;
|
||||
bool needs_new_enum_cache = !descriptors->HasEnumCache();
|
||||
if (needs_new_enum_cache) {
|
||||
bridge_storage = *isolate->factory()->NewFixedArray(
|
||||
DescriptorArray::kEnumCacheBridgeLength);
|
||||
Isolate* isolate, Handle<FixedArray> keys,
|
||||
Handle<FixedArray> indices) {
|
||||
EnumCache* enum_cache = descriptors->GetEnumCache();
|
||||
if (enum_cache == isolate->heap()->empty_enum_cache()) {
|
||||
enum_cache = *isolate->factory()->NewEnumCache(keys, indices);
|
||||
descriptors->set(kEnumCacheIndex, enum_cache);
|
||||
} else {
|
||||
bridge_storage = FixedArray::cast(descriptors->get(kEnumCacheBridgeIndex));
|
||||
}
|
||||
bridge_storage->set(kEnumCacheBridgeCacheIndex, *new_cache);
|
||||
bridge_storage->set(
|
||||
kEnumCacheBridgeIndicesCacheIndex,
|
||||
new_index_cache.is_null() ? Object::cast(Smi::kZero) : *new_index_cache);
|
||||
if (needs_new_enum_cache) {
|
||||
descriptors->set(kEnumCacheBridgeIndex, bridge_storage);
|
||||
enum_cache->set_keys(*keys);
|
||||
enum_cache->set_indices(*indices);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10595,8 +10583,6 @@ int HandlerTable::LookupReturn(int pc_offset) {
|
||||
|
||||
#ifdef DEBUG
|
||||
bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
|
||||
if (IsEmpty()) return other->IsEmpty();
|
||||
if (other->IsEmpty()) return false;
|
||||
if (length() != other->length()) return false;
|
||||
for (int i = 0; i < length(); ++i) {
|
||||
if (get(i) != other->get(i)) return false;
|
||||
|
@ -146,6 +146,7 @@
|
||||
// - AccessCheckInfo
|
||||
// - InterceptorInfo
|
||||
// - CallHandlerInfo
|
||||
// - EnumCache
|
||||
// - TemplateInfo
|
||||
// - FunctionTemplateInfo
|
||||
// - ObjectTemplateInfo
|
||||
@ -920,6 +921,7 @@ class AllocationSite;
|
||||
class Cell;
|
||||
class ConsString;
|
||||
class ElementsAccessor;
|
||||
class EnumCache;
|
||||
class FindAndReplacePattern;
|
||||
class FixedArrayBase;
|
||||
class PropertyArray;
|
||||
@ -988,6 +990,7 @@ template <class C> inline bool Is(Object* obj);
|
||||
V(DeoptimizationInputData) \
|
||||
V(DependentCode) \
|
||||
V(DescriptorArray) \
|
||||
V(EnumCache) \
|
||||
V(External) \
|
||||
V(ExternalOneByteString) \
|
||||
V(ExternalString) \
|
||||
|
@ -18,13 +18,26 @@ class Handle;
|
||||
|
||||
class Isolate;
|
||||
|
||||
// An EnumCache is a pair used to hold keys and indices caches.
|
||||
class EnumCache : public Tuple2 {
|
||||
public:
|
||||
DECL_ACCESSORS(keys, FixedArray)
|
||||
DECL_ACCESSORS(indices, FixedArray)
|
||||
|
||||
DECL_CAST(EnumCache)
|
||||
|
||||
// Layout description.
|
||||
static const int kKeysOffset = kValue1Offset;
|
||||
static const int kIndicesOffset = kValue2Offset;
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(EnumCache);
|
||||
};
|
||||
|
||||
// A DescriptorArray is a fixed array used to hold instance descriptors.
|
||||
// The format of the these objects is:
|
||||
// The format of these objects is:
|
||||
// [0]: Number of descriptors
|
||||
// [1]: Either Smi(0) if uninitialized,
|
||||
// or enum cache bridge (FixedArray[2]):
|
||||
// [0]: enum cache: FixedArray containing all own enumerable keys
|
||||
// [1]: either Smi(0) or pointer to fixed array with indices
|
||||
// [1]: Enum cache.
|
||||
// [2]: first key (and internalized String)
|
||||
// [3]: first descriptor details (see PropertyDetails)
|
||||
// [4]: first value for constants | Smi(1) when not usedA
|
||||
@ -32,11 +45,6 @@ class Isolate;
|
||||
// [2 + number of descriptors * 3]: start of slack
|
||||
class DescriptorArray : public FixedArray {
|
||||
public:
|
||||
// Returns true for both shared empty_descriptor_array and for smis, which the
|
||||
// map uses to encode additional bit fields when the descriptor array is not
|
||||
// yet used.
|
||||
inline bool IsEmpty();
|
||||
|
||||
// Returns the number of descriptors in the array.
|
||||
inline int number_of_descriptors();
|
||||
inline int number_of_descriptors_storage();
|
||||
@ -45,18 +53,14 @@ class DescriptorArray : public FixedArray {
|
||||
inline void SetNumberOfDescriptors(int number_of_descriptors);
|
||||
inline int number_of_entries();
|
||||
|
||||
inline bool HasEnumCache();
|
||||
inline bool HasEnumIndicesCache();
|
||||
inline FixedArray* GetEnumCache();
|
||||
inline FixedArray* GetEnumIndicesCache();
|
||||
inline EnumCache* GetEnumCache();
|
||||
|
||||
void ClearEnumCache();
|
||||
inline void CopyEnumCacheFrom(DescriptorArray* array);
|
||||
// Initialize or change the enum cache,
|
||||
// using the supplied storage for the small "bridge".
|
||||
static void SetEnumCache(Handle<DescriptorArray> descriptors,
|
||||
Isolate* isolate, Handle<FixedArray> new_cache,
|
||||
Handle<FixedArray> new_index_cache);
|
||||
Isolate* isolate, Handle<FixedArray> keys,
|
||||
Handle<FixedArray> indices);
|
||||
|
||||
// Accessors for fetching instance descriptor at descriptor number.
|
||||
inline Name* GetKey(int descriptor_number);
|
||||
@ -122,22 +126,13 @@ class DescriptorArray : public FixedArray {
|
||||
static const int kNotFound = -1;
|
||||
|
||||
static const int kDescriptorLengthIndex = 0;
|
||||
static const int kEnumCacheBridgeIndex = 1;
|
||||
static const int kEnumCacheIndex = 1;
|
||||
static const int kFirstIndex = 2;
|
||||
|
||||
// The length of the "bridge" to the enum cache.
|
||||
static const int kEnumCacheBridgeLength = 2;
|
||||
static const int kEnumCacheBridgeCacheIndex = 0;
|
||||
static const int kEnumCacheBridgeIndicesCacheIndex = 1;
|
||||
|
||||
// Layout description.
|
||||
static const int kDescriptorLengthOffset = FixedArray::kHeaderSize;
|
||||
static const int kEnumCacheBridgeOffset =
|
||||
kDescriptorLengthOffset + kPointerSize;
|
||||
static const int kFirstOffset = kEnumCacheBridgeOffset + kPointerSize;
|
||||
|
||||
// Layout description for the bridge array.
|
||||
static const int kEnumCacheBridgeCacheOffset = FixedArray::kHeaderSize;
|
||||
static const int kEnumCacheOffset = kDescriptorLengthOffset + kPointerSize;
|
||||
static const int kFirstOffset = kEnumCacheOffset + kPointerSize;
|
||||
|
||||
// Layout of descriptor.
|
||||
// Naming is consistent with Dictionary classes for easy templating.
|
||||
|
@ -126,12 +126,7 @@ RUNTIME_FUNCTION_RETURN_TRIPLE(Runtime_ForInPrepare) {
|
||||
Handle<DescriptorArray> descriptors(cache_map->instance_descriptors(),
|
||||
isolate);
|
||||
cache_length = cache_map->EnumLength();
|
||||
if (cache_length && descriptors->HasEnumCache()) {
|
||||
cache_array = handle(descriptors->GetEnumCache(), isolate);
|
||||
} else {
|
||||
cache_array = isolate->factory()->empty_fixed_array();
|
||||
cache_length = 0;
|
||||
}
|
||||
cache_array = handle(descriptors->GetEnumCache()->keys(), isolate);
|
||||
} else {
|
||||
cache_array = Handle<FixedArray>::cast(cache_type);
|
||||
cache_length = cache_array->length();
|
||||
|
@ -1754,7 +1754,7 @@ Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
|
||||
bool transitioning = true;
|
||||
Handle<Map> map(object->map(), isolate_);
|
||||
DCHECK(!map->is_dictionary_map());
|
||||
DCHECK(map->instance_descriptors()->IsEmpty());
|
||||
DCHECK_EQ(0, map->instance_descriptors()->number_of_descriptors());
|
||||
std::vector<Handle<Object>> properties;
|
||||
properties.reserve(8);
|
||||
|
||||
|
@ -150,7 +150,7 @@ TEST(StressJS) {
|
||||
// Patch the map to have an accessor for "get".
|
||||
Handle<Map> map(function->initial_map());
|
||||
Handle<DescriptorArray> instance_descriptors(map->instance_descriptors());
|
||||
CHECK(instance_descriptors->IsEmpty());
|
||||
CHECK_EQ(0, instance_descriptors->number_of_descriptors());
|
||||
|
||||
PropertyAttributes attrs = NONE;
|
||||
Handle<AccessorInfo> foreign = TestAccessorInfo(isolate, attrs);
|
||||
|
@ -2536,10 +2536,9 @@ THREADED_TEST(AccessorIsPreservedOnAttributeChange) {
|
||||
LocalContext env;
|
||||
v8::Local<v8::Value> res = CompileRun("var a = []; a;");
|
||||
i::Handle<i::JSReceiver> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
|
||||
CHECK(a->map()->instance_descriptors()->IsFixedArray());
|
||||
CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
|
||||
CHECK_EQ(1, a->map()->instance_descriptors()->number_of_descriptors());
|
||||
CompileRun("Object.defineProperty(a, 'length', { writable: false });");
|
||||
CHECK_EQ(0, i::FixedArray::cast(a->map()->instance_descriptors())->length());
|
||||
CHECK_EQ(0, a->map()->instance_descriptors()->number_of_descriptors());
|
||||
// But we should still have an AccessorInfo.
|
||||
i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
|
||||
i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
|
@ -247,22 +247,22 @@ KNOWN_MAPS = {
|
||||
0x03ee1: (171, "UnseededNumberDictionaryMap"),
|
||||
0x03f39: (190, "ExternalMap"),
|
||||
0x03f91: (106, "NativeSourceStringMap"),
|
||||
0x03fe9: (152, "InterceptorInfoMap"),
|
||||
0x04041: (208, "JSPromiseCapabilityMap"),
|
||||
0x04099: (149, "AccessorInfoMap"),
|
||||
0x040f1: (150, "AccessorPairMap"),
|
||||
0x04149: (151, "AccessCheckInfoMap"),
|
||||
0x041a1: (153, "FunctionTemplateInfoMap"),
|
||||
0x041f9: (154, "ObjectTemplateInfoMap"),
|
||||
0x04251: (155, "AllocationSiteMap"),
|
||||
0x042a9: (156, "AllocationMementoMap"),
|
||||
0x04301: (158, "AliasedArgumentsEntryMap"),
|
||||
0x04359: (159, "PromiseResolveThenableJobInfoMap"),
|
||||
0x043b1: (160, "PromiseReactionJobInfoMap"),
|
||||
0x04409: (161, "DebugInfoMap"),
|
||||
0x04461: (162, "StackFrameInfoMap"),
|
||||
0x044b9: (163, "PrototypeInfoMap"),
|
||||
0x04511: (164, "Tuple2Map"),
|
||||
0x03fe9: (164, "Tuple2Map"),
|
||||
0x04041: (152, "InterceptorInfoMap"),
|
||||
0x04099: (208, "JSPromiseCapabilityMap"),
|
||||
0x040f1: (149, "AccessorInfoMap"),
|
||||
0x04149: (150, "AccessorPairMap"),
|
||||
0x041a1: (151, "AccessCheckInfoMap"),
|
||||
0x041f9: (153, "FunctionTemplateInfoMap"),
|
||||
0x04251: (154, "ObjectTemplateInfoMap"),
|
||||
0x042a9: (155, "AllocationSiteMap"),
|
||||
0x04301: (156, "AllocationMementoMap"),
|
||||
0x04359: (158, "AliasedArgumentsEntryMap"),
|
||||
0x043b1: (159, "PromiseResolveThenableJobInfoMap"),
|
||||
0x04409: (160, "PromiseReactionJobInfoMap"),
|
||||
0x04461: (161, "DebugInfoMap"),
|
||||
0x044b9: (162, "StackFrameInfoMap"),
|
||||
0x04511: (163, "PrototypeInfoMap"),
|
||||
0x04569: (165, "Tuple3Map"),
|
||||
0x045c1: (166, "ContextExtensionMap"),
|
||||
0x04619: (167, "ModuleMap"),
|
||||
@ -274,47 +274,47 @@ KNOWN_MAPS = {
|
||||
KNOWN_OBJECTS = {
|
||||
("OLD_SPACE", 0x02201): "NullValue",
|
||||
("OLD_SPACE", 0x02231): "EmptyDescriptorArray",
|
||||
("OLD_SPACE", 0x02241): "EmptyFixedArray",
|
||||
("OLD_SPACE", 0x02251): "UninitializedValue",
|
||||
("OLD_SPACE", 0x022d1): "UndefinedValue",
|
||||
("OLD_SPACE", 0x02301): "NanValue",
|
||||
("OLD_SPACE", 0x02311): "TheHoleValue",
|
||||
("OLD_SPACE", 0x02361): "HoleNanValue",
|
||||
("OLD_SPACE", 0x02371): "TrueValue",
|
||||
("OLD_SPACE", 0x023e1): "FalseValue",
|
||||
("OLD_SPACE", 0x02431): "empty_string",
|
||||
("OLD_SPACE", 0x02449): "EmptyScopeInfo",
|
||||
("OLD_SPACE", 0x02459): "ArgumentsMarker",
|
||||
("OLD_SPACE", 0x024b1): "Exception",
|
||||
("OLD_SPACE", 0x02509): "TerminationException",
|
||||
("OLD_SPACE", 0x02569): "OptimizedOut",
|
||||
("OLD_SPACE", 0x025c1): "StaleRegister",
|
||||
("OLD_SPACE", 0x02619): "EmptyByteArray",
|
||||
("OLD_SPACE", 0x02629): "EmptyFixedUint8Array",
|
||||
("OLD_SPACE", 0x02649): "EmptyFixedInt8Array",
|
||||
("OLD_SPACE", 0x02669): "EmptyFixedUint16Array",
|
||||
("OLD_SPACE", 0x02689): "EmptyFixedInt16Array",
|
||||
("OLD_SPACE", 0x026a9): "EmptyFixedUint32Array",
|
||||
("OLD_SPACE", 0x026c9): "EmptyFixedInt32Array",
|
||||
("OLD_SPACE", 0x026e9): "EmptyFixedFloat32Array",
|
||||
("OLD_SPACE", 0x02709): "EmptyFixedFloat64Array",
|
||||
("OLD_SPACE", 0x02729): "EmptyFixedUint8ClampedArray",
|
||||
("OLD_SPACE", 0x02749): "EmptyScript",
|
||||
("OLD_SPACE", 0x027c9): "UndefinedCell",
|
||||
("OLD_SPACE", 0x027d9): "EmptySloppyArgumentsElements",
|
||||
("OLD_SPACE", 0x027f9): "EmptySlowElementDictionary",
|
||||
("OLD_SPACE", 0x02841): "EmptyPropertyCell",
|
||||
("OLD_SPACE", 0x02869): "EmptyWeakCell",
|
||||
("OLD_SPACE", 0x02879): "ArrayProtector",
|
||||
("OLD_SPACE", 0x028a1): "IsConcatSpreadableProtector",
|
||||
("OLD_SPACE", 0x028b1): "SpeciesProtector",
|
||||
("OLD_SPACE", 0x028d9): "StringLengthProtector",
|
||||
("OLD_SPACE", 0x028e9): "FastArrayIterationProtector",
|
||||
("OLD_SPACE", 0x028f9): "ArrayIteratorProtector",
|
||||
("OLD_SPACE", 0x02921): "ArrayBufferNeuteringProtector",
|
||||
("OLD_SPACE", 0x02949): "InfinityValue",
|
||||
("OLD_SPACE", 0x02959): "MinusZeroValue",
|
||||
("OLD_SPACE", 0x02969): "MinusInfinityValue",
|
||||
("OLD_SPACE", 0x02251): "EmptyFixedArray",
|
||||
("OLD_SPACE", 0x02261): "UninitializedValue",
|
||||
("OLD_SPACE", 0x022e1): "UndefinedValue",
|
||||
("OLD_SPACE", 0x02311): "NanValue",
|
||||
("OLD_SPACE", 0x02321): "TheHoleValue",
|
||||
("OLD_SPACE", 0x02371): "HoleNanValue",
|
||||
("OLD_SPACE", 0x02381): "TrueValue",
|
||||
("OLD_SPACE", 0x023f1): "FalseValue",
|
||||
("OLD_SPACE", 0x02441): "empty_string",
|
||||
("OLD_SPACE", 0x02459): "EmptyScopeInfo",
|
||||
("OLD_SPACE", 0x02469): "ArgumentsMarker",
|
||||
("OLD_SPACE", 0x024c1): "Exception",
|
||||
("OLD_SPACE", 0x02519): "TerminationException",
|
||||
("OLD_SPACE", 0x02579): "OptimizedOut",
|
||||
("OLD_SPACE", 0x025d1): "StaleRegister",
|
||||
("OLD_SPACE", 0x02629): "EmptyByteArray",
|
||||
("OLD_SPACE", 0x02639): "EmptyFixedUint8Array",
|
||||
("OLD_SPACE", 0x02659): "EmptyFixedInt8Array",
|
||||
("OLD_SPACE", 0x02679): "EmptyFixedUint16Array",
|
||||
("OLD_SPACE", 0x02699): "EmptyFixedInt16Array",
|
||||
("OLD_SPACE", 0x026b9): "EmptyFixedUint32Array",
|
||||
("OLD_SPACE", 0x026d9): "EmptyFixedInt32Array",
|
||||
("OLD_SPACE", 0x026f9): "EmptyFixedFloat32Array",
|
||||
("OLD_SPACE", 0x02719): "EmptyFixedFloat64Array",
|
||||
("OLD_SPACE", 0x02739): "EmptyFixedUint8ClampedArray",
|
||||
("OLD_SPACE", 0x02759): "EmptyScript",
|
||||
("OLD_SPACE", 0x027d9): "UndefinedCell",
|
||||
("OLD_SPACE", 0x027e9): "EmptySloppyArgumentsElements",
|
||||
("OLD_SPACE", 0x02809): "EmptySlowElementDictionary",
|
||||
("OLD_SPACE", 0x02851): "EmptyPropertyCell",
|
||||
("OLD_SPACE", 0x02879): "EmptyWeakCell",
|
||||
("OLD_SPACE", 0x02889): "ArrayProtector",
|
||||
("OLD_SPACE", 0x028b1): "IsConcatSpreadableProtector",
|
||||
("OLD_SPACE", 0x028c1): "SpeciesProtector",
|
||||
("OLD_SPACE", 0x028e9): "StringLengthProtector",
|
||||
("OLD_SPACE", 0x028f9): "FastArrayIterationProtector",
|
||||
("OLD_SPACE", 0x02909): "ArrayIteratorProtector",
|
||||
("OLD_SPACE", 0x02931): "ArrayBufferNeuteringProtector",
|
||||
("OLD_SPACE", 0x02959): "InfinityValue",
|
||||
("OLD_SPACE", 0x02969): "MinusZeroValue",
|
||||
("OLD_SPACE", 0x02979): "MinusInfinityValue",
|
||||
}
|
||||
|
||||
# List of known V8 Frame Markers.
|
||||
|
Loading…
Reference in New Issue
Block a user