Bug 929151 - Disable GGC when object metadata is used, r=terrence

This commit is contained in:
Steve Fink 2013-10-21 13:53:37 -07:00
parent 28eb8d7130
commit e059de18e1
9 changed files with 39 additions and 14 deletions

View File

@ -639,7 +639,7 @@ MacroAssembler::newGCThing(const Register &result, gc::AllocKind allocKind, Labe
// Don't execute the inline path if the compartment has an object metadata callback,
// as the metadata to use for the object may vary between executions of the op.
if (GetIonContext()->compartment->objectMetadataCallback)
if (GetIonContext()->compartment->hasObjectMetadataCallback())
jump(fail);
#ifdef JSGC_GENERATIONAL

View File

@ -3125,7 +3125,7 @@ NewArray(ExclusiveContext *cxArg, uint32_t length,
if (JSContext *cx = cxArg->maybeJSContext()) {
NewObjectCache &cache = cx->runtime()->newObjectCache;
if (newKind == GenericObject &&
!cx->compartment()->objectMetadataCallback &&
!cx->compartment()->hasObjectMetadataCallback() &&
cache.lookupGlobal(&ArrayObject::class_, cx->global(), allocKind, &entry))
{
RootedObject obj(cx, cache.newObjectFromHit(cx, entry,

View File

@ -10,6 +10,7 @@
#include "mozilla/MemoryReporting.h"
#include "jscntxt.h"
#include "jsfriendapi.h"
#include "jsgc.h"
#include "jsiter.h"
#include "jsproxy.h"
@ -622,6 +623,24 @@ JSCompartment::clearTables()
lazyTypeObjects.clear();
}
void
JSCompartment::setObjectMetadataCallback(js::ObjectMetadataCallback callback)
{
// Clear any jitcode in the runtime, which behaves differently depending on
// whether there is a creation callback.
ReleaseAllJITCode(runtime_->defaultFreeOp());
// Turn off GGC while the metadata hook is present, to prevent
// nursery-allocated metadata from being used as a lookup key in
// InitialShapeTable entries.
if (callback)
JS::DisableGenerationalGC(runtime_);
else
JS::EnableGenerationalGC(runtime_);
objectMetadataCallback = callback;
}
bool
JSCompartment::hasScriptsOnStack()
{

View File

@ -196,9 +196,9 @@ struct JSCompartment
void *data;
private:
js::ObjectMetadataCallback objectMetadataCallback;
private:
js::WrapperMap crossCompartmentWrappers;
public:
@ -326,6 +326,12 @@ struct JSCompartment
void purge();
void clearTables();
bool hasObjectMetadataCallback() const { return objectMetadataCallback; }
void setObjectMetadataCallback(js::ObjectMetadataCallback callback);
bool callObjectMetadataCallback(JSContext *cx, JSObject **obj) const {
return objectMetadataCallback(cx, obj);
}
void findOutgoingEdges(js::gc::ComponentFinder<JS::Zone> &finder);
js::DtoaCache dtoaCache;

View File

@ -1120,11 +1120,7 @@ js::AutoCTypesActivityCallback::AutoCTypesActivityCallback(JSContext *cx,
JS_FRIEND_API(void)
js::SetObjectMetadataCallback(JSContext *cx, ObjectMetadataCallback callback)
{
// Clear any jitcode in the runtime, which behaves differently depending on
// whether there is a creation callback.
ReleaseAllJITCode(cx->runtime()->defaultFreeOp());
cx->compartment()->objectMetadataCallback = callback;
cx->compartment()->setObjectMetadataCallback(callback);
}
JS_FRIEND_API(bool)

View File

@ -1338,7 +1338,7 @@ js::NewObjectWithGivenProto(ExclusiveContext *cxArg, const js::Class *clasp,
NewObjectCache &cache = cx->runtime()->newObjectCache;
if (proto.isObject() &&
newKind == GenericObject &&
!cx->compartment()->objectMetadataCallback &&
!cx->compartment()->hasObjectMetadataCallback() &&
(!parent || parent == proto.toObject()->getParent()) &&
!proto.toObject()->is<GlobalObject>())
{
@ -1404,7 +1404,7 @@ js::NewObjectWithClassProtoCommon(ExclusiveContext *cxArg,
if (parentArg->is<GlobalObject>() &&
protoKey != JSProto_Null &&
newKind == GenericObject &&
!cx->compartment()->objectMetadataCallback)
!cx->compartment()->hasObjectMetadataCallback())
{
if (cache.lookupGlobal(clasp, &parentArg->as<GlobalObject>(), allocKind, &entry)) {
JSObject *obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
@ -1457,7 +1457,7 @@ NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc::Al
NewObjectCache::EntryIndex entry = -1;
if (parent == type->proto->getParent() &&
newKind == GenericObject &&
!cx->compartment()->objectMetadataCallback)
!cx->compartment()->hasObjectMetadataCallback())
{
if (cache.lookupType(&JSObject::class_, type, allocKind, &entry)) {
JSObject *obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, &JSObject::class_));

View File

@ -1008,12 +1008,12 @@ NewObjectMetadata(ExclusiveContext *cxArg, JSObject **pmetadata)
// analysis/compilation/parsing is active as the callback may reenter JS.
JS_ASSERT(!*pmetadata);
if (JSContext *cx = cxArg->maybeJSContext()) {
if (JS_UNLIKELY((size_t)cx->compartment()->objectMetadataCallback) &&
if (JS_UNLIKELY((size_t)cx->compartment()->hasObjectMetadataCallback()) &&
!cx->compartment()->activeAnalysis &&
!cx->runtime()->mainThread.activeCompilations)
{
gc::AutoSuppressGC suppress(cx);
return cx->compartment()->objectMetadataCallback(cx, pmetadata);
return cx->compartment()->callObjectMetadataCallback(cx, pmetadata);
}
}
return true;

View File

@ -41,7 +41,7 @@ inline JSObject *
NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::InitialHeap heap)
{
// The new object cache does not account for metadata attached via callbacks.
JS_ASSERT(!cx->compartment()->objectMetadataCallback);
JS_ASSERT(!cx->compartment()->hasObjectMetadataCallback());
JS_ASSERT(unsigned(entry_) < mozilla::ArrayLength(entries));
Entry *entry = &entries[entry_];

View File

@ -1618,6 +1618,10 @@ EmptyShape::insertInitialShape(ExclusiveContext *cx, HandleShape shape, HandleOb
shape->getObjectParent(), shape->getObjectMetadata(),
shape->numFixedSlots(), shape->getObjectFlags());
/* Bug 929547 - we do not rekey based on metadata object moves */
JSObject *metadata = shape->getObjectMetadata();
JS_ASSERT_IF(metadata, gc::IsInsideNursery(cx->compartment()->runtimeFromAnyThread(), metadata));
InitialShapeSet::Ptr p = cx->compartment()->initialShapes.lookup(lookup);
JS_ASSERT(p);