Commit 514fc74a authored by yangguo@chromium.org's avatar yangguo@chromium.org

Limit initial size of hidden properties and store identity hashes inline.

BUG=v8:2211
TEST=test-heap/Regress2211

Review URL: https://chromiumcodereview.appspot.com/10827040

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12230 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 249f29f2
...@@ -3303,9 +3303,10 @@ bool v8::Object::SetHiddenValue(v8::Handle<v8::String> key, ...@@ -3303,9 +3303,10 @@ bool v8::Object::SetHiddenValue(v8::Handle<v8::String> key,
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this); i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key); i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
i::Handle<i::String> key_symbol = FACTORY->LookupSymbol(key_obj);
i::Handle<i::Object> value_obj = Utils::OpenHandle(*value); i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
i::Handle<i::Object> result = i::Handle<i::Object> result =
i::JSObject::SetHiddenProperty(self, key_obj, value_obj); i::JSObject::SetHiddenProperty(self, key_symbol, value_obj);
return *result == *self; return *result == *self;
} }
...@@ -3317,7 +3318,8 @@ v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String> key) { ...@@ -3317,7 +3318,8 @@ v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String> key) {
ENTER_V8(isolate); ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this); i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key); i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
i::Handle<i::Object> result(self->GetHiddenProperty(*key_obj)); i::Handle<i::String> key_symbol = FACTORY->LookupSymbol(key_obj);
i::Handle<i::Object> result(self->GetHiddenProperty(*key_symbol));
if (result->IsUndefined()) return v8::Local<v8::Value>(); if (result->IsUndefined()) return v8::Local<v8::Value>();
return Utils::ToLocal(result); return Utils::ToLocal(result);
} }
...@@ -3330,7 +3332,8 @@ bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) { ...@@ -3330,7 +3332,8 @@ bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this); i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::String> key_obj = Utils::OpenHandle(*key); i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
self->DeleteHiddenProperty(*key_obj); i::Handle<i::String> key_symbol = FACTORY->LookupSymbol(key_obj);
self->DeleteHiddenProperty(*key_symbol);
return true; return true;
} }
......
...@@ -1011,7 +1011,7 @@ void Factory::BecomeJSFunction(Handle<JSReceiver> object) { ...@@ -1011,7 +1011,7 @@ void Factory::BecomeJSFunction(Handle<JSReceiver> object) {
} }
void Factory::SetIdentityHash(Handle<JSObject> object, Object* hash) { void Factory::SetIdentityHash(Handle<JSObject> object, Smi* hash) {
CALL_HEAP_FUNCTION_VOID( CALL_HEAP_FUNCTION_VOID(
isolate(), isolate(),
object->SetIdentityHash(hash, ALLOW_CREATION)); object->SetIdentityHash(hash, ALLOW_CREATION));
......
...@@ -297,7 +297,7 @@ class Factory { ...@@ -297,7 +297,7 @@ class Factory {
void BecomeJSObject(Handle<JSReceiver> object); void BecomeJSObject(Handle<JSReceiver> object);
void BecomeJSFunction(Handle<JSReceiver> object); void BecomeJSFunction(Handle<JSReceiver> object);
void SetIdentityHash(Handle<JSObject> object, Object* hash); void SetIdentityHash(Handle<JSObject> object, Smi* hash);
Handle<JSFunction> NewFunction(Handle<String> name, Handle<JSFunction> NewFunction(Handle<String> name,
Handle<Object> prototype); Handle<Object> prototype);
......
This diff is collapsed.
...@@ -1731,7 +1731,7 @@ class JSObject: public JSReceiver { ...@@ -1731,7 +1731,7 @@ class JSObject: public JSReceiver {
static int GetIdentityHash(Handle<JSObject> obj); static int GetIdentityHash(Handle<JSObject> obj);
MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag); MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag);
MUST_USE_RESULT MaybeObject* SetIdentityHash(Object* hash, CreationFlag flag); MUST_USE_RESULT MaybeObject* SetIdentityHash(Smi* hash, CreationFlag flag);
static Handle<Object> DeleteProperty(Handle<JSObject> obj, static Handle<Object> DeleteProperty(Handle<JSObject> obj,
Handle<String> name); Handle<String> name);
...@@ -2235,16 +2235,22 @@ class JSObject: public JSReceiver { ...@@ -2235,16 +2235,22 @@ class JSObject: public JSReceiver {
Object* setter, Object* setter,
PropertyAttributes attributes); PropertyAttributes attributes);
// Returns the hidden properties backing store object, currently
// a StringDictionary, stored on this object. enum InitializeHiddenProperties {
// If no hidden properties object has been put on this object, CREATE_NEW_IF_ABSENT,
// return undefined, unless create_if_absent is true, in which case ONLY_RETURN_INLINE_VALUE
// a new dictionary is created, added to this object, and returned. };
MUST_USE_RESULT MaybeObject* GetHiddenPropertiesDictionary(
bool create_if_absent); // If create_if_absent is true, return the hash table backing store
// Updates the existing hidden properties dictionary. // for hidden properties. If there is no backing store, allocate one.
MUST_USE_RESULT MaybeObject* SetHiddenPropertiesDictionary( // If create_if_absent is false, return the hash table backing store
StringDictionary* dictionary); // or the inline stored identity hash, whatever is found.
MUST_USE_RESULT MaybeObject* GetHiddenPropertiesHashTable(
InitializeHiddenProperties init_option);
// Set the hidden property backing store to either a hash table or
// the inline-stored identity hash.
MUST_USE_RESULT MaybeObject* SetHiddenPropertiesHashTable(
Object* value);
DISALLOW_IMPLICIT_CONSTRUCTORS(JSObject); DISALLOW_IMPLICIT_CONSTRUCTORS(JSObject);
}; };
...@@ -2747,6 +2753,11 @@ class BaseShape { ...@@ -2747,6 +2753,11 @@ class BaseShape {
template<typename Shape, typename Key> template<typename Shape, typename Key>
class HashTable: public FixedArray { class HashTable: public FixedArray {
public: public:
enum MinimumCapacity {
USE_DEFAULT_MINIMUM_CAPACITY,
USE_CUSTOM_MINIMUM_CAPACITY
};
// Wrapper methods // Wrapper methods
inline uint32_t Hash(Key key) { inline uint32_t Hash(Key key) {
if (Shape::UsesSeed) { if (Shape::UsesSeed) {
...@@ -2799,6 +2810,7 @@ class HashTable: public FixedArray { ...@@ -2799,6 +2810,7 @@ class HashTable: public FixedArray {
// Returns a new HashTable object. Might return Failure. // Returns a new HashTable object. Might return Failure.
MUST_USE_RESULT static MaybeObject* Allocate( MUST_USE_RESULT static MaybeObject* Allocate(
int at_least_space_for, int at_least_space_for,
MinimumCapacity capacity_option = USE_DEFAULT_MINIMUM_CAPACITY,
PretenureFlag pretenure = NOT_TENURED); PretenureFlag pretenure = NOT_TENURED);
// Computes the required capacity for a table holding the given // Computes the required capacity for a table holding the given
......
...@@ -105,6 +105,12 @@ TEST(ObjectHashSetCausesGC) { ...@@ -105,6 +105,12 @@ TEST(ObjectHashSetCausesGC) {
LocalContext context; LocalContext context;
Handle<ObjectHashSet> table = FACTORY->NewObjectHashSet(1); Handle<ObjectHashSet> table = FACTORY->NewObjectHashSet(1);
Handle<JSObject> key = FACTORY->NewJSArray(0); Handle<JSObject> key = FACTORY->NewJSArray(0);
v8::Handle<v8::Object> key_obj = v8::Utils::ToLocal(key);
// Force allocation of hash table backing store for hidden properties.
key_obj->SetHiddenValue(v8_str("key 1"), v8_str("val 1"));
key_obj->SetHiddenValue(v8_str("key 2"), v8_str("val 2"));
key_obj->SetHiddenValue(v8_str("key 3"), v8_str("val 3"));
// Simulate a full heap so that generating an identity hash code // Simulate a full heap so that generating an identity hash code
// in subsequent calls will request GC. // in subsequent calls will request GC.
...@@ -128,6 +134,12 @@ TEST(ObjectHashTableCausesGC) { ...@@ -128,6 +134,12 @@ TEST(ObjectHashTableCausesGC) {
LocalContext context; LocalContext context;
Handle<ObjectHashTable> table = FACTORY->NewObjectHashTable(1); Handle<ObjectHashTable> table = FACTORY->NewObjectHashTable(1);
Handle<JSObject> key = FACTORY->NewJSArray(0); Handle<JSObject> key = FACTORY->NewJSArray(0);
v8::Handle<v8::Object> key_obj = v8::Utils::ToLocal(key);
// Force allocation of hash table backing store for hidden properties.
key_obj->SetHiddenValue(v8_str("key 1"), v8_str("val 1"));
key_obj->SetHiddenValue(v8_str("key 2"), v8_str("val 2"));
key_obj->SetHiddenValue(v8_str("key 3"), v8_str("val 3"));
// Simulate a full heap so that generating an identity hash code // Simulate a full heap so that generating an identity hash code
// in subsequent calls will request GC. // in subsequent calls will request GC.
......
...@@ -1468,7 +1468,7 @@ TEST(HiddenPropertiesFastCase) { ...@@ -1468,7 +1468,7 @@ TEST(HiddenPropertiesFastCase) {
v8::Handle<v8::Value> cHandle = env->Global()->Get(v8::String::New("c")); v8::Handle<v8::Value> cHandle = env->Global()->Get(v8::String::New("c"));
CHECK(!cHandle.IsEmpty() && cHandle->IsObject()); CHECK(!cHandle.IsEmpty() && cHandle->IsObject());
cHandle->ToObject()->GetIdentityHash(); cHandle->ToObject()->SetHiddenValue(v8_str("key"), v8_str("val"));
snapshot = v8::HeapProfiler::TakeSnapshot( snapshot = v8::HeapProfiler::TakeSnapshot(
v8_str("HiddenPropertiesFastCase2")); v8_str("HiddenPropertiesFastCase2"));
......
...@@ -1985,3 +1985,39 @@ TEST(PrintSharedFunctionInfo) { ...@@ -1985,3 +1985,39 @@ TEST(PrintSharedFunctionInfo) {
g->shared()->PrintLn(); g->shared()->PrintLn();
} }
#endif // OBJECT_PRINT #endif // OBJECT_PRINT
TEST(Regress2211) {
InitializeVM();
v8::HandleScope scope;
v8::Handle<v8::String> value = v8_str("val string");
Smi* hash = Smi::FromInt(321);
Heap* heap = Isolate::Current()->heap();
for (int i = 0; i < 2; i++) {
// Store identity hash first and common hidden property second.
v8::Handle<v8::Object> obj = v8::Object::New();
Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
CHECK(internal_obj->HasFastProperties());
// In the first iteration, set hidden value first and identity hash second.
// In the second iteration, reverse the order.
if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
ALLOW_CREATION);
CHECK(!maybe_obj->IsFailure());
if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
// Check values.
CHECK_EQ(hash,
internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
// Check size.
DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
ObjectHashTable* hashtable = ObjectHashTable::cast(
internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
CHECK_LE(hashtable->SizeFor(hashtable->length()), 52);
}
}
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