Commit 4608bdec authored by jarin@chromium.org's avatar jarin@chromium.org

With this fix, we only create the enum cache for own property descriptors...

With this fix, we only create the enum cache for own property descriptors (originally we cached all descriptors in the map).  The problem was that the size of all descriptors could be trimmed during GC triggered by allocating the storage for the cache, so we could have ended up with a wrong storage size.

This is really Toon's fix, I have only created a small repro case.

BUG=
R=verwaest@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20308 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 1110f4fc
...@@ -627,20 +627,21 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, ...@@ -627,20 +627,21 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
bool cache_result) { bool cache_result) {
Isolate* isolate = object->GetIsolate(); Isolate* isolate = object->GetIsolate();
if (object->HasFastProperties()) { if (object->HasFastProperties()) {
if (object->map()->instance_descriptors()->HasEnumCache()) { int own_property_count = object->map()->EnumLength();
int own_property_count = object->map()->EnumLength(); // If the enum length of the given map is set to kInvalidEnumCache, this
// If we have an enum cache, but the enum length of the given map is set // means that the map itself has never used the present enum cache. The
// to kInvalidEnumCache, this means that the map itself has never used the // first step to using the cache is to set the enum length of the map by
// present enum cache. The first step to using the cache is to set the // counting the number of own descriptors that are not DONT_ENUM or
// enum length of the map by counting the number of own descriptors that // SYMBOLIC.
// are not DONT_ENUM or SYMBOLIC. if (own_property_count == kInvalidEnumCacheSentinel) {
if (own_property_count == kInvalidEnumCacheSentinel) { own_property_count = object->map()->NumberOfDescribedProperties(
own_property_count = object->map()->NumberOfDescribedProperties( OWN_DESCRIPTORS, DONT_SHOW);
OWN_DESCRIPTORS, DONT_SHOW); } else {
ASSERT(own_property_count == object->map()->NumberOfDescribedProperties(
if (cache_result) object->map()->SetEnumLength(own_property_count); OWN_DESCRIPTORS, DONT_SHOW));
} }
if (object->map()->instance_descriptors()->HasEnumCache()) {
DescriptorArray* desc = object->map()->instance_descriptors(); DescriptorArray* desc = object->map()->instance_descriptors();
Handle<FixedArray> keys(desc->GetEnumCache(), isolate); Handle<FixedArray> keys(desc->GetEnumCache(), isolate);
...@@ -649,6 +650,7 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, ...@@ -649,6 +650,7 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
// enum cache was generated for a previous (smaller) version of the // enum cache was generated for a previous (smaller) version of the
// Descriptor Array. In that case we regenerate the enum cache. // Descriptor Array. In that case we regenerate the enum cache.
if (own_property_count <= keys->length()) { if (own_property_count <= keys->length()) {
if (cache_result) object->map()->SetEnumLength(own_property_count);
isolate->counters()->enum_cache_hits()->Increment(); isolate->counters()->enum_cache_hits()->Increment();
return ReduceFixedArrayTo(keys, own_property_count); return ReduceFixedArrayTo(keys, own_property_count);
} }
...@@ -663,23 +665,22 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, ...@@ -663,23 +665,22 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
} }
isolate->counters()->enum_cache_misses()->Increment(); isolate->counters()->enum_cache_misses()->Increment();
int num_enum = map->NumberOfDescribedProperties(ALL_DESCRIPTORS, DONT_SHOW);
Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum); Handle<FixedArray> storage = isolate->factory()->NewFixedArray(
Handle<FixedArray> indices = isolate->factory()->NewFixedArray(num_enum); own_property_count);
Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
own_property_count);
Handle<DescriptorArray> descs = Handle<DescriptorArray> descs =
Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate); Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
int real_size = map->NumberOfOwnDescriptors(); int size = map->NumberOfOwnDescriptors();
int enum_size = 0;
int index = 0; int index = 0;
for (int i = 0; i < descs->number_of_descriptors(); i++) { for (int i = 0; i < size; i++) {
PropertyDetails details = descs->GetDetails(i); PropertyDetails details = descs->GetDetails(i);
Object* key = descs->GetKey(i); Object* key = descs->GetKey(i);
if (!(details.IsDontEnum() || key->IsSymbol())) { if (!(details.IsDontEnum() || key->IsSymbol())) {
if (i < real_size) ++enum_size;
storage->set(index, key); storage->set(index, key);
if (!indices.is_null()) { if (!indices.is_null()) {
if (details.type() != FIELD) { if (details.type() != FIELD) {
...@@ -706,10 +707,9 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, ...@@ -706,10 +707,9 @@ Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
indices.is_null() ? Object::cast(Smi::FromInt(0)) indices.is_null() ? Object::cast(Smi::FromInt(0))
: Object::cast(*indices)); : Object::cast(*indices));
if (cache_result) { if (cache_result) {
object->map()->SetEnumLength(enum_size); object->map()->SetEnumLength(own_property_count);
} }
return storage;
return ReduceFixedArrayTo(storage, enum_size);
} else { } else {
Handle<NameDictionary> dictionary(object->property_dictionary()); Handle<NameDictionary> dictionary(object->property_dictionary());
int length = dictionary->NumberOfEnumElements(); int length = dictionary->NumberOfEnumElements();
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --stress-compaction
%SetAllocationTimeout(100000, 100000);
var x = {};
x.a = 1;
x.b = 2;
x = {};
var y = {};
y.a = 1;
%SetAllocationTimeout(100000, 0);
for (var z in y) { }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment