Bug 687724 (part 2) - Make JSCompartment::global() fallible. r=luke.

--HG--
extra : rebase_source : 68a5558772d643ab9f3b32b60a89fdbaf9b5e6ad
This commit is contained in:
Nicholas Nethercote 2012-07-03 17:25:15 -07:00
parent 452ba219a1
commit 309a1e7fdb
8 changed files with 31 additions and 14 deletions

View File

@ -634,8 +634,11 @@ ScanBaseShape(GCMarker *gcmarker, BaseShape *base)
if (base->hasSetterObject()) if (base->hasSetterObject())
PushMarkStack(gcmarker, base->setterObject()); PushMarkStack(gcmarker, base->setterObject());
if (JSObject *parent = base->getObjectParent()) if (JSObject *parent = base->getObjectParent()) {
PushMarkStack(gcmarker, parent); PushMarkStack(gcmarker, parent);
} else if (GlobalObject *global = base->compartment()->maybeGlobal()) {
PushMarkStack(gcmarker, global);
}
/* /*
* All children of the owned base shape are consistent with its * All children of the owned base shape are consistent with its

View File

@ -1388,8 +1388,8 @@ JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target)
{ {
AssertHeapIsIdle(cx); AssertHeapIsIdle(cx);
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
GlobalObject &global = target->compartment()->global(); GlobalObject *global = target->compartment()->maybeGlobal();
return JS_EnterCrossCompartmentCall(cx, &global); return global ? JS_EnterCrossCompartmentCall(cx, global) : NULL;
} }
JS_PUBLIC_API(JSCrossCompartmentCall *) JS_PUBLIC_API(JSCrossCompartmentCall *)

View File

@ -229,7 +229,7 @@ class CompartmentChecker
{ {
if (cx->compartment) { if (cx->compartment) {
GlobalObject *global = GetGlobalForScopeChain(cx); GlobalObject *global = GetGlobalForScopeChain(cx);
JS_ASSERT(cx->compartment->global() == *global); JS_ASSERT(cx->compartment->maybeGlobal() == global);
} }
} }

View File

@ -491,6 +491,9 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
discardJitCode(fop); discardJitCode(fop);
} }
if (global_ && !IsObjectMarked(&global_))
global_ = NULL;
/* JIT code can hold references on RegExpShared, so sweep regexps after clearing code. */ /* JIT code can hold references on RegExpShared, so sweep regexps after clearing code. */
regExps.sweep(rt); regExps.sweep(rt);

View File

@ -119,12 +119,23 @@ struct JSCompartment
private: private:
js::GlobalObject *global_; js::GlobalObject *global_;
public: public:
js::GlobalObject &global() const { // Nb: global_ might be NULL, if (a) it's the atoms compartment, or (b) the
JS_ASSERT(global_->compartment() == this); // compartment's global has been collected. The latter can happen if e.g.
return *global_; // a string in a compartment is rooted but no object is, and thus the
// global isn't rooted, and thus the global can be finalized while the
// compartment lives on.
//
// In contrast, JSObject::global() is infallible because marking a JSObject
// always marks its global as well.
// TODO: add infallible JSScript::global() and JSContext::global()
//
js::GlobalObject *maybeGlobal() const {
JS_ASSERT_IF(global_, global_->compartment() == this);
return global_;
} }
void initGlobal(js::GlobalObject &global) { void initGlobal(js::GlobalObject &global) {
JS_ASSERT(global.compartment() == this);
JS_ASSERT(!global_); JS_ASSERT(!global_);
global_ = &global; global_ = &global;
} }

View File

@ -2348,7 +2348,7 @@ NewObject(JSContext *cx, Class *clasp, types::TypeObject *type_, JSObject *paren
JS_ASSERT(clasp != &ArrayClass); JS_ASSERT(clasp != &ArrayClass);
JS_ASSERT_IF(clasp == &FunctionClass, JS_ASSERT_IF(clasp == &FunctionClass,
kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind); kind == JSFunction::FinalizeKind || kind == JSFunction::ExtendedFinalizeKind);
JS_ASSERT_IF(parent, parent->global() == cx->compartment->global()); JS_ASSERT_IF(parent, &parent->global() == cx->compartment->maybeGlobal());
RootedTypeObject type(cx, type_); RootedTypeObject type(cx, type_);

View File

@ -1234,7 +1234,7 @@ JSObject::global() const
JSObject *obj = const_cast<JSObject *>(this); JSObject *obj = const_cast<JSObject *>(this);
while (JSObject *parent = obj->getParent()) while (JSObject *parent = obj->getParent())
obj = parent; obj = parent;
JS_ASSERT(obj->asGlobal() == compartment()->global()); JS_ASSERT(&obj->asGlobal() == compartment()->maybeGlobal());
return obj->asGlobal(); return obj->asGlobal();
} }

View File

@ -1521,7 +1521,7 @@ class TypedArrayTemplate
RootedId id(cx, NameToId(name)); RootedId id(cx, NameToId(name));
unsigned flags = JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED | JSPROP_GETTER; unsigned flags = JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED | JSPROP_GETTER;
Rooted<GlobalObject*> global(cx, &cx->compartment->global()); Rooted<GlobalObject*> global(cx, cx->compartment->maybeGlobal());
JSObject *getter = js_NewFunction(cx, NULL, Getter<ValueGetter>, 0, 0, global, NULL); JSObject *getter = js_NewFunction(cx, NULL, Getter<ValueGetter>, 0, 0, global, NULL);
if (!getter) if (!getter)
return false; return false;
@ -3008,7 +3008,7 @@ template<class ArrayType>
static inline JSObject * static inline JSObject *
InitTypedArrayClass(JSContext *cx) InitTypedArrayClass(JSContext *cx)
{ {
Rooted<GlobalObject*> global(cx, &cx->compartment->global()); Rooted<GlobalObject*> global(cx, cx->compartment->maybeGlobal());
RootedObject proto(cx, global->createBlankPrototype(cx, ArrayType::protoClass())); RootedObject proto(cx, global->createBlankPrototype(cx, ArrayType::protoClass()));
if (!proto) if (!proto)
return NULL; return NULL;
@ -3085,7 +3085,7 @@ Class TypedArray::protoClasses[TYPE_MAX] = {
static JSObject * static JSObject *
InitArrayBufferClass(JSContext *cx) InitArrayBufferClass(JSContext *cx)
{ {
Rooted<GlobalObject*> global(cx, &cx->compartment->global()); Rooted<GlobalObject*> global(cx, cx->compartment->maybeGlobal());
RootedObject arrayBufferProto(cx, global->createBlankPrototype(cx, &ArrayBufferObject::protoClass)); RootedObject arrayBufferProto(cx, global->createBlankPrototype(cx, &ArrayBufferObject::protoClass));
if (!arrayBufferProto) if (!arrayBufferProto)
return NULL; return NULL;
@ -3198,7 +3198,7 @@ DefineDataViewGetter(JSContext *cx, PropertyName *name, HandleObject proto)
RootedId id(cx, NameToId(name)); RootedId id(cx, NameToId(name));
unsigned flags = JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED | JSPROP_GETTER; unsigned flags = JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED | JSPROP_GETTER;
Rooted<GlobalObject*> global(cx, &cx->compartment->global()); Rooted<GlobalObject*> global(cx, cx->compartment->maybeGlobal());
JSObject *getter = js_NewFunction(cx, NULL, DataViewGetter<ValueGetter>, 0, 0, global, NULL); JSObject *getter = js_NewFunction(cx, NULL, DataViewGetter<ValueGetter>, 0, 0, global, NULL);
if (!getter) if (!getter)
return false; return false;
@ -3211,7 +3211,7 @@ DefineDataViewGetter(JSContext *cx, PropertyName *name, HandleObject proto)
JSObject * JSObject *
DataViewObject::initClass(JSContext *cx) DataViewObject::initClass(JSContext *cx)
{ {
Rooted<GlobalObject*> global(cx, &cx->compartment->global()); Rooted<GlobalObject*> global(cx, cx->compartment->maybeGlobal());
RootedObject proto(cx, global->createBlankPrototype(cx, &DataViewObject::protoClass)); RootedObject proto(cx, global->createBlankPrototype(cx, &DataViewObject::protoClass));
if (!proto) if (!proto)
return NULL; return NULL;