From 309a1e7fdbef40481e67868f506238a06467ff18 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 3 Jul 2012 17:25:15 -0700 Subject: [PATCH] Bug 687724 (part 2) - Make JSCompartment::global() fallible. r=luke. --HG-- extra : rebase_source : 68a5558772d643ab9f3b32b60a89fdbaf9b5e6ad --- js/src/gc/Marking.cpp | 5 ++++- js/src/jsapi.cpp | 4 ++-- js/src/jscntxtinlines.h | 2 +- js/src/jscompartment.cpp | 3 +++ js/src/jscompartment.h | 17 ++++++++++++++--- js/src/jsobj.cpp | 2 +- js/src/jsobjinlines.h | 2 +- js/src/jstypedarray.cpp | 10 +++++----- 8 files changed, 31 insertions(+), 14 deletions(-) diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 8831b92d2fe..6f1d47335ed 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -634,8 +634,11 @@ ScanBaseShape(GCMarker *gcmarker, BaseShape *base) if (base->hasSetterObject()) PushMarkStack(gcmarker, base->setterObject()); - if (JSObject *parent = base->getObjectParent()) + if (JSObject *parent = base->getObjectParent()) { PushMarkStack(gcmarker, parent); + } else if (GlobalObject *global = base->compartment()->maybeGlobal()) { + PushMarkStack(gcmarker, global); + } /* * All children of the owned base shape are consistent with its diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 9525436180b..c086e99491c 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1388,8 +1388,8 @@ JS_EnterCrossCompartmentCallScript(JSContext *cx, JSScript *target) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - GlobalObject &global = target->compartment()->global(); - return JS_EnterCrossCompartmentCall(cx, &global); + GlobalObject *global = target->compartment()->maybeGlobal(); + return global ? JS_EnterCrossCompartmentCall(cx, global) : NULL; } JS_PUBLIC_API(JSCrossCompartmentCall *) diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index a796c9ff554..40bf3f5eb37 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -229,7 +229,7 @@ class CompartmentChecker { if (cx->compartment) { GlobalObject *global = GetGlobalForScopeChain(cx); - JS_ASSERT(cx->compartment->global() == *global); + JS_ASSERT(cx->compartment->maybeGlobal() == global); } } diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index c973c3bccfb..f6cb31cff5b 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -491,6 +491,9 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes) discardJitCode(fop); } + if (global_ && !IsObjectMarked(&global_)) + global_ = NULL; + /* JIT code can hold references on RegExpShared, so sweep regexps after clearing code. */ regExps.sweep(rt); diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 8330e2d3bcd..7e2da78d20c 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -119,12 +119,23 @@ struct JSCompartment private: js::GlobalObject *global_; public: - js::GlobalObject &global() const { - JS_ASSERT(global_->compartment() == this); - return *global_; + // Nb: global_ might be NULL, if (a) it's the atoms compartment, or (b) the + // compartment's global has been collected. The latter can happen if e.g. + // 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) { + JS_ASSERT(global.compartment() == this); JS_ASSERT(!global_); global_ = &global; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 2da48c46bcd..24e899fb76a 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2348,7 +2348,7 @@ NewObject(JSContext *cx, Class *clasp, types::TypeObject *type_, JSObject *paren JS_ASSERT(clasp != &ArrayClass); JS_ASSERT_IF(clasp == &FunctionClass, 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_); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 94bf32aac9f..97fd410e054 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -1234,7 +1234,7 @@ JSObject::global() const JSObject *obj = const_cast(this); while (JSObject *parent = obj->getParent()) obj = parent; - JS_ASSERT(obj->asGlobal() == compartment()->global()); + JS_ASSERT(&obj->asGlobal() == compartment()->maybeGlobal()); return obj->asGlobal(); } diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index b959b95c403..0b7672777ea 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -1521,7 +1521,7 @@ class TypedArrayTemplate RootedId id(cx, NameToId(name)); unsigned flags = JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED | JSPROP_GETTER; - Rooted global(cx, &cx->compartment->global()); + Rooted global(cx, cx->compartment->maybeGlobal()); JSObject *getter = js_NewFunction(cx, NULL, Getter, 0, 0, global, NULL); if (!getter) return false; @@ -3008,7 +3008,7 @@ template static inline JSObject * InitTypedArrayClass(JSContext *cx) { - Rooted global(cx, &cx->compartment->global()); + Rooted global(cx, cx->compartment->maybeGlobal()); RootedObject proto(cx, global->createBlankPrototype(cx, ArrayType::protoClass())); if (!proto) return NULL; @@ -3085,7 +3085,7 @@ Class TypedArray::protoClasses[TYPE_MAX] = { static JSObject * InitArrayBufferClass(JSContext *cx) { - Rooted global(cx, &cx->compartment->global()); + Rooted global(cx, cx->compartment->maybeGlobal()); RootedObject arrayBufferProto(cx, global->createBlankPrototype(cx, &ArrayBufferObject::protoClass)); if (!arrayBufferProto) return NULL; @@ -3198,7 +3198,7 @@ DefineDataViewGetter(JSContext *cx, PropertyName *name, HandleObject proto) RootedId id(cx, NameToId(name)); unsigned flags = JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED | JSPROP_GETTER; - Rooted global(cx, &cx->compartment->global()); + Rooted global(cx, cx->compartment->maybeGlobal()); JSObject *getter = js_NewFunction(cx, NULL, DataViewGetter, 0, 0, global, NULL); if (!getter) return false; @@ -3211,7 +3211,7 @@ DefineDataViewGetter(JSContext *cx, PropertyName *name, HandleObject proto) JSObject * DataViewObject::initClass(JSContext *cx) { - Rooted global(cx, &cx->compartment->global()); + Rooted global(cx, cx->compartment->maybeGlobal()); RootedObject proto(cx, global->createBlankPrototype(cx, &DataViewObject::protoClass)); if (!proto) return NULL;