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,
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
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> result =
i::JSObject::SetHiddenProperty(self, key_obj, value_obj);
i::JSObject::SetHiddenProperty(self, key_symbol, value_obj);
return *result == *self;
}
......@@ -3317,7 +3318,8 @@ v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String> key) {
ENTER_V8(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
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>();
return Utils::ToLocal(result);
}
......@@ -3330,7 +3332,8 @@ bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
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;
}
......
......@@ -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(
isolate(),
object->SetIdentityHash(hash, ALLOW_CREATION));
......
......@@ -297,7 +297,7 @@ class Factory {
void BecomeJSObject(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<Object> prototype);
......
This diff is collapsed.
......@@ -1731,7 +1731,7 @@ class JSObject: public JSReceiver {
static int GetIdentityHash(Handle<JSObject> obj);
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,
Handle<String> name);
......@@ -2235,16 +2235,22 @@ class JSObject: public JSReceiver {
Object* setter,
PropertyAttributes attributes);
// Returns the hidden properties backing store object, currently
// a StringDictionary, stored on this object.
// If no hidden properties object has been put on this object,
// return undefined, unless create_if_absent is true, in which case
// a new dictionary is created, added to this object, and returned.
MUST_USE_RESULT MaybeObject* GetHiddenPropertiesDictionary(
bool create_if_absent);
// Updates the existing hidden properties dictionary.
MUST_USE_RESULT MaybeObject* SetHiddenPropertiesDictionary(
StringDictionary* dictionary);
enum InitializeHiddenProperties {
CREATE_NEW_IF_ABSENT,
ONLY_RETURN_INLINE_VALUE
};
// If create_if_absent is true, return the hash table backing store
// for hidden properties. If there is no backing store, allocate one.
// If create_if_absent is false, return the hash table backing store
// 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);
};
......@@ -2747,6 +2753,11 @@ class BaseShape {
template<typename Shape, typename Key>
class HashTable: public FixedArray {
public:
enum MinimumCapacity {
USE_DEFAULT_MINIMUM_CAPACITY,
USE_CUSTOM_MINIMUM_CAPACITY
};
// Wrapper methods
inline uint32_t Hash(Key key) {
if (Shape::UsesSeed) {
......@@ -2799,6 +2810,7 @@ class HashTable: public FixedArray {
// Returns a new HashTable object. Might return Failure.
MUST_USE_RESULT static MaybeObject* Allocate(
int at_least_space_for,
MinimumCapacity capacity_option = USE_DEFAULT_MINIMUM_CAPACITY,
PretenureFlag pretenure = NOT_TENURED);
// Computes the required capacity for a table holding the given
......
......@@ -105,6 +105,12 @@ TEST(ObjectHashSetCausesGC) {
LocalContext context;
Handle<ObjectHashSet> table = FACTORY->NewObjectHashSet(1);
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
// in subsequent calls will request GC.
......@@ -128,6 +134,12 @@ TEST(ObjectHashTableCausesGC) {
LocalContext context;
Handle<ObjectHashTable> table = FACTORY->NewObjectHashTable(1);
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
// in subsequent calls will request GC.
......
......@@ -1468,7 +1468,7 @@ TEST(HiddenPropertiesFastCase) {
v8::Handle<v8::Value> cHandle = env->Global()->Get(v8::String::New("c"));
CHECK(!cHandle.IsEmpty() && cHandle->IsObject());
cHandle->ToObject()->GetIdentityHash();
cHandle->ToObject()->SetHiddenValue(v8_str("key"), v8_str("val"));
snapshot = v8::HeapProfiler::TakeSnapshot(
v8_str("HiddenPropertiesFastCase2"));
......
......@@ -1985,3 +1985,39 @@ TEST(PrintSharedFunctionInfo) {
g->shared()->PrintLn();
}
#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