Bug 1132706 - Lazify hashing for insertions into the NewObjectCache; r=jonco

--HG--
extra : rebase_source : 9435fdbada6cc43d6e59cddef93d17572f423cba
This commit is contained in:
Terrence Cole 2015-02-13 11:36:40 -08:00
parent 847508c681
commit d2a24551f7
2 changed files with 90 additions and 75 deletions

View File

@ -3329,6 +3329,14 @@ EnsureNewArrayElements(ExclusiveContext *cx, ArrayObject *obj, uint32_t length)
return true;
}
static bool
NewArrayIsCachable(ExclusiveContext *cxArg, NewObjectKind newKind)
{
return cxArg->isJSContext() &&
newKind == GenericObject &&
!cxArg->asJSContext()->compartment()->hasObjectMetadataCallback();
}
template <uint32_t maxLength>
static MOZ_ALWAYS_INLINE ArrayObject *
NewArray(ExclusiveContext *cxArg, uint32_t length,
@ -3338,15 +3346,13 @@ NewArray(ExclusiveContext *cxArg, uint32_t length,
MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, &ArrayObject::class_));
allocKind = GetBackgroundAllocKind(allocKind);
NewObjectCache::EntryIndex entry = -1;
uint64_t gcNumber = 0;
if (JSContext *cx = cxArg->maybeJSContext()) {
bool isCachable = NewArrayIsCachable(cxArg, newKind);
if (isCachable) {
JSContext *cx = cxArg->asJSContext();
JSRuntime *rt = cx->runtime();
NewObjectCache &cache = rt->newObjectCache;
if (newKind == GenericObject &&
!cx->compartment()->hasObjectMetadataCallback() &&
cache.lookupGlobal(&ArrayObject::class_, cx->global(), allocKind, &entry))
{
NewObjectCache::EntryIndex entry = -1;
if (cache.lookupGlobal(&ArrayObject::class_, cx->global(), allocKind, &entry)) {
gc::InitialHeap heap = GetInitialHeap(newKind, &ArrayObject::class_);
JSObject *obj = cache.newObjectFromHit(cx, entry, heap);
if (obj) {
@ -3361,8 +3367,6 @@ NewArray(ExclusiveContext *cxArg, uint32_t length,
}
return arr;
}
} else {
gcNumber = rt->gc.gcNumber();
}
}
@ -3405,11 +3409,11 @@ NewArray(ExclusiveContext *cxArg, uint32_t length,
if (newKind == SingletonObject && !JSObject::setSingleton(cxArg, arr))
return nullptr;
if (entry != -1 &&
cxArg->asJSContext()->runtime()->gc.gcNumber() == gcNumber)
{
cxArg->asJSContext()->runtime()->newObjectCache.fillGlobal(entry, &ArrayObject::class_,
cxArg->global(), allocKind, arr);
if (isCachable) {
NewObjectCache &cache = cxArg->asJSContext()->runtime()->newObjectCache;
NewObjectCache::EntryIndex entry = -1;
cache.lookupGlobal(&ArrayObject::class_, cxArg->global(), allocKind, &entry);
cache.fillGlobal(entry, &ArrayObject::class_, cxArg->global(), allocKind, arr);
}
if (maxLength > 0 && !EnsureNewArrayElements(cxArg, arr, std::min(maxLength, length)))

View File

@ -1218,6 +1218,20 @@ NewObjectCache::fillProto(EntryIndex entry, const Class *clasp, js::TaggedProto
return fill(entry, clasp, proto.raw(), kind, obj);
}
static bool
NewObjectWithTaggedProtoIsCachable(ExclusiveContext *cxArg, Handle<TaggedProto> proto,
NewObjectKind newKind, const Class *clasp,
HandleObject parentArg)
{
return cxArg->isJSContext() &&
proto.isObject() &&
newKind == GenericObject &&
clasp->isNative() &&
!cxArg->asJSContext()->compartment()->hasObjectMetadataCallback() &&
(!parentArg || parentArg == proto.toObject()->getParent()) &&
!proto.toObject()->is<GlobalObject>();
}
JSObject *
js::NewObjectWithGivenTaggedProto(ExclusiveContext *cxArg, const Class *clasp,
Handle<TaggedProto> proto, HandleObject parentArg,
@ -1226,25 +1240,16 @@ js::NewObjectWithGivenTaggedProto(ExclusiveContext *cxArg, const Class *clasp,
if (CanBeFinalizedInBackground(allocKind, clasp))
allocKind = GetBackgroundAllocKind(allocKind);
NewObjectCache::EntryIndex entry = -1;
uint64_t gcNumber = 0;
if (JSContext *cx = cxArg->maybeJSContext()) {
bool isCachable = NewObjectWithTaggedProtoIsCachable(cxArg, proto, newKind, clasp, parentArg);
if (isCachable) {
JSContext *cx = cxArg->asJSContext();
JSRuntime *rt = cx->runtime();
NewObjectCache &cache = rt->newObjectCache;
if (proto.isObject() &&
newKind == GenericObject &&
clasp->isNative() &&
!cx->compartment()->hasObjectMetadataCallback() &&
(!parentArg || parentArg == proto.toObject()->getParent()) &&
!proto.toObject()->is<GlobalObject>())
{
if (cache.lookupProto(clasp, proto.toObject(), allocKind, &entry)) {
JSObject *obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
if (obj)
return obj;
} else {
gcNumber = rt->gc.gcNumber();
}
NewObjectCache::EntryIndex entry = -1;
if (cache.lookupProto(clasp, proto.toObject(), allocKind, &entry)) {
JSObject *obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
if (obj)
return obj;
}
}
@ -1264,12 +1269,11 @@ js::NewObjectWithGivenTaggedProto(ExclusiveContext *cxArg, const Class *clasp,
if (!obj)
return nullptr;
if (entry != -1 && !obj->as<NativeObject>().hasDynamicSlots() &&
cxArg->asJSContext()->runtime()->gc.gcNumber() == gcNumber)
{
cxArg->asJSContext()->runtime()->newObjectCache.fillProto(entry, clasp,
proto, allocKind,
&obj->as<NativeObject>());
if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
NewObjectCache &cache = cxArg->asJSContext()->runtime()->newObjectCache;
NewObjectCache::EntryIndex entry = -1;
cache.lookupProto(clasp, proto.toObject(), allocKind, &entry);
cache.fillProto(entry, clasp, proto, allocKind, &obj->as<NativeObject>());
}
return obj;
@ -1369,6 +1373,17 @@ FindProto(ExclusiveContext *cx, const js::Class *clasp, MutableHandleObject prot
return true;
}
static bool
NewObjectWithClassProtoIsCachable(ExclusiveContext *cxArg, HandleObject parent,
JSProtoKey protoKey, NewObjectKind newKind, const Class *clasp)
{
return cxArg->isJSContext() &&
parent->is<GlobalObject>() &&
protoKey != JSProto_Null &&
newKind == GenericObject &&
clasp->isNative() &&
!cxArg->asJSContext()->compartment()->hasObjectMetadataCallback();
}
JSObject *
js::NewObjectWithClassProtoCommon(ExclusiveContext *cxArg, const Class *clasp,
@ -1396,24 +1411,16 @@ js::NewObjectWithClassProtoCommon(ExclusiveContext *cxArg, const Class *clasp,
*/
JSProtoKey protoKey = ClassProtoKeyOrAnonymousOrNull(clasp);
NewObjectCache::EntryIndex entry = -1;
uint64_t gcNumber = 0;
if (JSContext *cx = cxArg->maybeJSContext()) {
bool isCachable = NewObjectWithClassProtoIsCachable(cxArg, parent, protoKey, newKind, clasp);
if (isCachable) {
JSContext *cx = cxArg->asJSContext();
JSRuntime *rt = cx->runtime();
NewObjectCache &cache = rt->newObjectCache;
if (parent->is<GlobalObject>() &&
protoKey != JSProto_Null &&
newKind == GenericObject &&
clasp->isNative() &&
!cx->compartment()->hasObjectMetadataCallback())
{
if (cache.lookupGlobal(clasp, &parent->as<GlobalObject>(), allocKind, &entry)) {
JSObject *obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
if (obj)
return obj;
} else {
gcNumber = rt->gc.gcNumber();
}
NewObjectCache::EntryIndex entry = -1;
if (cache.lookupGlobal(clasp, &parent->as<GlobalObject>(), allocKind, &entry)) {
JSObject *obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
if (obj)
return obj;
}
}
@ -1430,17 +1437,29 @@ js::NewObjectWithClassProtoCommon(ExclusiveContext *cxArg, const Class *clasp,
if (!obj)
return nullptr;
if (entry != -1 && !obj->as<NativeObject>().hasDynamicSlots() &&
cxArg->asJSContext()->runtime()->gc.gcNumber() == gcNumber)
{
cxArg->asJSContext()->runtime()->newObjectCache.fillGlobal(entry, clasp,
&parent->as<GlobalObject>(),
allocKind, &obj->as<NativeObject>());
if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
NewObjectCache &cache = cxArg->asJSContext()->runtime()->newObjectCache;
NewObjectCache::EntryIndex entry = -1;
cache.lookupGlobal(clasp, &parent->as<GlobalObject>(), allocKind, &entry);
cache.fillGlobal(entry, clasp, &parent->as<GlobalObject>(), allocKind,
&obj->as<NativeObject>());
}
return obj;
}
static bool
NewObjectWithGroupIsCachable(JSContext *cx, HandleObjectGroup group, HandleObject parent,
NewObjectKind newKind)
{
return group->proto().isObject() &&
parent == group->proto().toObject()->getParent() &&
newKind == GenericObject &&
group->clasp()->isNative() &&
(!group->newScript() || group->newScript()->analyzed()) &&
!cx->compartment()->hasObjectMetadataCallback();
}
/*
* Create a plain object with the specified group. This bypasses getNewGroup to
* avoid losing creation site information for objects made by scripted 'new'.
@ -1455,24 +1474,15 @@ js::NewObjectWithGroupCommon(JSContext *cx, HandleObjectGroup group, HandleObjec
if (CanBeFinalizedInBackground(allocKind, group->clasp()))
allocKind = GetBackgroundAllocKind(allocKind);
NewObjectCache &cache = cx->runtime()->newObjectCache;
NewObjectCache::EntryIndex entry = -1;
uint64_t gcNumber = 0;
if (group->proto().isObject() &&
parent == group->proto().toObject()->getParent() &&
newKind == GenericObject &&
group->clasp()->isNative() &&
(!group->newScript() || group->newScript()->analyzed()) &&
!cx->compartment()->hasObjectMetadataCallback())
{
bool isCachable = NewObjectWithGroupIsCachable(cx, group, parent, newKind);
if (isCachable) {
NewObjectCache &cache = cx->runtime()->newObjectCache;
NewObjectCache::EntryIndex entry = -1;
if (cache.lookupGroup(group, allocKind, &entry)) {
JSObject *obj = cache.newObjectFromHit(cx, entry,
GetInitialHeap(newKind, group->clasp()));
if (obj)
return obj;
} else {
gcNumber = cx->runtime()->gc.gcNumber();
}
}
@ -1480,9 +1490,10 @@ js::NewObjectWithGroupCommon(JSContext *cx, HandleObjectGroup group, HandleObjec
if (!obj)
return nullptr;
if (entry != -1 && !obj->as<NativeObject>().hasDynamicSlots() &&
cx->runtime()->gc.gcNumber() == gcNumber)
{
if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
NewObjectCache &cache = cx->runtime()->newObjectCache;
NewObjectCache::EntryIndex entry = -1;
cache.lookupGroup(group, allocKind, &entry);
cache.fillGroup(entry, group, allocKind, &obj->as<NativeObject>());
}