Bug 934419 - Split CompartmentOptions off from ContextOptions; r=bholley
authorEddy Bruel <ejpbruel@mozilla.com>
Mon, 11 Nov 2013 21:44:33 +0100
changeset 169023 6a9e00928bb8d8fddaa06641e66adf3200eed661
parent 169022 ed845769c3273401ceca4f0628372c49ff26db77
child 169024 fcc73e099a0cbfb1085b9486acdf236608f10dbd
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs934419
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 934419 - Split CompartmentOptions off from ContextOptions; r=bholley
js/jsd/jsd_xpc.cpp
js/src/jit/AsmJS.cpp
js/src/jit/BaselineJIT.h
js/src/jit/Ion.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscompartment.h
js/src/vm/Debugger.cpp
js/src/vm/Debugger.h
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -1661,19 +1661,19 @@ jsdContext::GetOptions(uint32_t *_rval)
     *_rval = (JS::ContextOptionsRef(mJSCx).extraWarnings() ? JSOPTION_EXTRA_WARNINGS : 0)
            | (JS::ContextOptionsRef(mJSCx).werror() ? JSOPTION_WERROR : 0)
            | (JS::ContextOptionsRef(mJSCx).varObjFix() ? JSOPTION_VAROBJFIX : 0)
            | (JS::ContextOptionsRef(mJSCx).privateIsNSISupports() ? JSOPTION_PRIVATE_IS_NSISUPPORTS : 0)
            | (JS::ContextOptionsRef(mJSCx).compileAndGo() ? JSOPTION_COMPILE_N_GO : 0)
            | (JS::ContextOptionsRef(mJSCx).dontReportUncaught() ? JSOPTION_DONT_REPORT_UNCAUGHT : 0)
            | (JS::ContextOptionsRef(mJSCx).noDefaultCompartmentObject() ? JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT : 0)
            | (JS::ContextOptionsRef(mJSCx).noScriptRval() ? JSOPTION_NO_SCRIPT_RVAL : 0)
+           | (JS::ContextOptionsRef(mJSCx).strictMode() ? JSOPTION_STRICT_MODE : 0)
            | (JS::ContextOptionsRef(mJSCx).baseline() ? JSOPTION_BASELINE : 0)
            | (JS::ContextOptionsRef(mJSCx).typeInference() ? JSOPTION_TYPE_INFERENCE : 0)
-           | (JS::ContextOptionsRef(mJSCx).strictMode() ? JSOPTION_STRICT_MODE : 0)
            | (JS::ContextOptionsRef(mJSCx).ion() ? JSOPTION_ION : 0)
            | (JS::ContextOptionsRef(mJSCx).asmJS() ? JSOPTION_ASMJS : 0);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 jsdContext::SetOptions(uint32_t options)
 {
@@ -1687,19 +1687,19 @@ jsdContext::SetOptions(uint32_t options)
 
     JS::ContextOptionsRef(mJSCx).setExtraWarnings(options & JSOPTION_EXTRA_WARNINGS)
                                 .setWerror(options & JSOPTION_WERROR)
                                 .setVarObjFix(options & JSOPTION_VAROBJFIX)
                                 .setCompileAndGo(options & JSOPTION_COMPILE_N_GO)
                                 .setDontReportUncaught(options & JSOPTION_DONT_REPORT_UNCAUGHT)
                                 .setNoDefaultCompartmentObject(options & JSOPTION_NO_DEFAULT_COMPARTMENT_OBJECT)
                                 .setNoScriptRval(options & JSOPTION_NO_SCRIPT_RVAL)
+                                .setStrictMode(options & JSOPTION_STRICT_MODE)
                                 .setBaseline(options & JSOPTION_BASELINE)
                                 .setTypeInference(options & JSOPTION_TYPE_INFERENCE)
-                                .setStrictMode(options & JSOPTION_STRICT_MODE)
                                 .setIon(options & JSOPTION_ION)
                                 .setAsmJS(options & JSOPTION_ASMJS);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 jsdContext::GetPrivateData(nsISupports **_rval)
 {
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -6532,13 +6532,13 @@ bool
 js::IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // See EstablishPreconditions.
     bool available = JSC::MacroAssembler::supportsFloatingPoint() &&
                      cx->gcSystemPageSize() == AsmJSPageSize &&
                      !cx->compartment()->debugMode() &&
-                     cx->options().asmJS();
+                     cx->compartment()->options().asmJS(cx);
 
     args.rval().set(BooleanValue(available));
     return true;
 }
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -291,17 +291,17 @@ struct BaselineScript
         JS_ASSERT(bytecodeTypeMapOffset_);
         return reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(this) + bytecodeTypeMapOffset_);
     }
 };
 
 inline bool
 IsBaselineEnabled(JSContext *cx)
 {
-    return cx->options().baseline();
+    return cx->compartment()->options().baseline(cx);
 }
 
 MethodStatus
 CanEnterBaselineMethod(JSContext *cx, RunState &state);
 
 MethodStatus
 CanEnterBaselineAtBranch(JSContext *cx, StackFrame *fp, bool newType);
 
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -366,18 +366,18 @@ CodeGenerator *GenerateCode(MIRGenerator
 CodeGenerator *CompileBackEnd(MIRGenerator *mir, MacroAssembler *maybeMasm = nullptr);
 
 void AttachFinishedCompilations(JSContext *cx);
 void FinishOffThreadBuilder(IonBuilder *builder);
 
 static inline bool
 IsIonEnabled(JSContext *cx)
 {
-    return cx->options().ion() &&
-        cx->options().baseline() &&
+    return cx->compartment()->options().ion(cx) &&
+        cx->compartment()->options().baseline(cx) &&
         cx->typeInferenceEnabled();
 }
 
 inline bool
 IsIonInlinablePC(jsbytecode *pc) {
     // CALL, FUNCALL, FUNAPPLY, EVAL, NEW (Normal Callsites)
     // GETPROP, CALLPROP, and LENGTH. (Inlined Getters)
     // SETPROP, SETNAME, SETGNAME (Inlined Setters)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2501,30 +2501,72 @@ class AutoHoldZone
 
   private:
     bool *holdp;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 } /* anonymous namespace */
 
+bool
+JS::CompartmentOptions::baseline(JSContext *cx) const
+{
+    return baselineOverride_.get(cx->options().baseline());
+}
+
+bool
+JS::CompartmentOptions::typeInference(const ExclusiveContext *cx) const
+{
+    /* Unlike the other options that can be overriden on a per compartment
+     * basis, the default value for the typeInference option is stored on the
+     * compartment's type zone, rather than the current JSContext. Type zones
+     * copy this default value over from the current JSContext when they are
+     * created.
+     */
+    return typeInferenceOverride_.get(cx->compartment()->zone()->types.inferenceEnabled);
+}
+
+bool
+JS::CompartmentOptions::ion(JSContext *cx) const
+{
+    return ionOverride_.get(cx->options().ion());
+}
+
+bool
+JS::CompartmentOptions::asmJS(JSContext *cx) const
+{
+    return asmJSOverride_.get(cx->options().asmJS());
+}
+
 JS::CompartmentOptions &
 JS::CompartmentOptions::setZone(ZoneSpecifier spec)
 {
     zone_.spec = spec;
     return *this;
 }
 
 JS::CompartmentOptions &
 JS::CompartmentOptions::setSameZoneAs(JSObject *obj)
 {
     zone_.pointer = static_cast<void *>(obj->zone());
     return *this;
 }
 
+JS::CompartmentOptions &
+JS::CompartmentOptionsRef(JSCompartment *compartment)
+{
+    return compartment->options();
+}
+
+JS::CompartmentOptions &
+JS::CompartmentOptionsRef(JSContext *cx)
+{
+    return cx->compartment()->options();
+}
+
 JS_PUBLIC_API(JSObject *)
 JS_NewGlobalObject(JSContext *cx, const JSClass *clasp, JSPrincipals *principals,
                    JS::OnNewGlobalHookOption hookOption,
                    const JS::CompartmentOptions &options /* = JS::CompartmentOptions() */)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1435,19 +1435,19 @@ class JS_PUBLIC_API(ContextOptions) {
       : extraWarnings_(false),
         werror_(false),
         varObjFix_(false),
         privateIsNSISupports_(false),
         compileAndGo_(false),
         dontReportUncaught_(false),
         noDefaultCompartmentObject_(false),
         noScriptRval_(false),
+        strictMode_(false),
         baseline_(false),
         typeInference_(false),
-        strictMode_(false),
         ion_(false),
         asmJS_(false)
     {
     }
 
     bool extraWarnings() const { return extraWarnings_; }
     ContextOptions &setExtraWarnings(bool flag) {
         extraWarnings_ = flag;
@@ -1523,16 +1523,26 @@ class JS_PUBLIC_API(ContextOptions) {
         noScriptRval_ = flag;
         return *this;
     }
     ContextOptions &toggleNoScriptRval() {
         noScriptRval_ = !noScriptRval_;
         return *this;
     }
 
+    bool strictMode() const { return strictMode_; }
+    ContextOptions &setStrictMode(bool flag) {
+        strictMode_ = flag;
+        return *this;
+    }
+    ContextOptions &toggleStrictMode() {
+        strictMode_ = !strictMode_;
+        return *this;
+    }
+
     bool baseline() const { return baseline_; }
     ContextOptions &setBaseline(bool flag) {
         baseline_ = flag;
         return *this;
     }
     ContextOptions &toggleBaseline() {
         baseline_ = !baseline_;
         return *this;
@@ -1543,26 +1553,16 @@ class JS_PUBLIC_API(ContextOptions) {
         typeInference_ = flag;
         return *this;
     }
     ContextOptions &toggleTypeInference() {
         typeInference_ = !typeInference_;
         return *this;
     }
 
-    bool strictMode() const { return strictMode_; }
-    ContextOptions &setStrictMode(bool flag) {
-        strictMode_ = flag;
-        return *this;
-    }
-    ContextOptions &toggleStrictMode() {
-        strictMode_ = !strictMode_;
-        return *this;
-    }
-
     bool ion() const { return ion_; }
     ContextOptions &setIon(bool flag) {
         ion_ = flag;
         return *this;
     }
     ContextOptions &toggleIon() {
         ion_ = !ion_;
         return *this;
@@ -1582,19 +1582,19 @@ class JS_PUBLIC_API(ContextOptions) {
     bool extraWarnings_ : 1;
     bool werror_ : 1;
     bool varObjFix_ : 1;
     bool privateIsNSISupports_ : 1;
     bool compileAndGo_ : 1;
     bool dontReportUncaught_ : 1;
     bool noDefaultCompartmentObject_ : 1;
     bool noScriptRval_ : 1;
+    bool strictMode_ : 1;
     bool baseline_ : 1;
     bool typeInference_ : 1;
-    bool strictMode_ : 1;
     bool ion_ : 1;
     bool asmJS_ : 1;
 };
 
 JS_PUBLIC_API(ContextOptions &)
 ContextOptionsRef(JSContext *cx);
 
 class JS_PUBLIC_API(AutoSaveContextOptions) {
@@ -2541,61 +2541,108 @@ namespace JS {
 
 enum ZoneSpecifier {
     FreshZone = 0,
     SystemZone = 1
 };
 
 class JS_PUBLIC_API(CompartmentOptions)
 {
-    union {
-        ZoneSpecifier spec;
-        void *pointer; // js::Zone* is not exposed in the API.
-    } zone_;
-    JSVersion version_;
-
   public:
-    bool invisibleToDebugger;
+    class Override {
+      public:
+        Override() : mode_(Default) {}
+
+        bool get(bool defaultValue) const {
+            if (mode_ == Default)
+                return defaultValue;
+            return mode_ == ForceTrue;
+        };
+
+        void set(bool overrideValue) {
+            mode_ = overrideValue ? ForceTrue : ForceFalse;
+        };
+
+        void reset() {
+            mode_ = Default;
+        }
+
+      private:
+        enum Mode {
+            Default,
+            ForceTrue,
+            ForceFalse
+        };
+
+        Mode mode_;
+    };
 
     explicit CompartmentOptions()
       : version_(JSVERSION_UNKNOWN)
-      , invisibleToDebugger(false)
+      , invisibleToDebugger_(false)
     {
         zone_.spec = JS::FreshZone;
     }
 
-    CompartmentOptions &setZone(ZoneSpecifier spec);
-
-    CompartmentOptions &setSameZoneAs(JSObject *obj);
-
+    JSVersion version() const { return version_; }
     CompartmentOptions &setVersion(JSVersion aVersion) {
         MOZ_ASSERT(aVersion != JSVERSION_UNKNOWN);
         version_ = aVersion;
         return *this;
     }
 
     // Certain scopes (i.e. XBL compilation scopes) are implementation details
     // of the embedding, and references to them should never leak out to script.
     // This flag causes the this compartment to skip firing onNewGlobalObject
     // and makes addDebuggee a no-op for this global.
-    CompartmentOptions &setInvisibleToDebugger(bool invisible) {
-        invisibleToDebugger = invisible;
+    bool invisibleToDebugger() { return invisibleToDebugger_; }
+    CompartmentOptions &setInvisibleToDebugger(bool flag) {
+        invisibleToDebugger_ = flag;
         return *this;
     }
 
-    ZoneSpecifier zoneSpecifier() const { return zone_.spec; }
-
-    JSVersion version() const { return version_; }
+    bool baseline(JSContext *cx) const;
+    Override &baselineOverride() { return baselineOverride_; }
+
+    bool typeInference(const js::ExclusiveContext *cx) const;
+    Override &typeInferenceOverride() { return typeInferenceOverride_; }
+
+    bool ion(JSContext *cx) const;
+    Override &ionOverride() { return ionOverride_; }
+
+    bool asmJS(JSContext *cx) const;
+    Override &asmJSOverride() { return asmJSOverride_; }
 
     void *zonePointer() const {
         JS_ASSERT(uintptr_t(zone_.pointer) > uintptr_t(JS::SystemZone));
         return zone_.pointer;
     }
+    ZoneSpecifier zoneSpecifier() const { return zone_.spec; }
+    CompartmentOptions &setZone(ZoneSpecifier spec);
+    CompartmentOptions &setSameZoneAs(JSObject *obj);
+
+  private:
+    JSVersion version_;
+    bool invisibleToDebugger_;
+    Override baselineOverride_;
+    Override typeInferenceOverride_;
+    Override ionOverride_;
+    Override asmJSOverride_;
+    union {
+        ZoneSpecifier spec;
+        void *pointer; // js::Zone* is not exposed in the API.
+    } zone_;
 };
 
+JS_PUBLIC_API(CompartmentOptions &)
+CompartmentOptionsRef(JSCompartment *compartment);
+
+JS_PUBLIC_API(CompartmentOptions &)
+CompartmentOptionsRef(JSContext *cx);
+
 // During global creation, we fire notifications to callbacks registered
 // via the Debugger API. These callbacks are arbitrary script, and can touch
 // the global in arbitrary ways. When that happens, the global should not be
 // in a half-baked state. But this creates a problem for consumers that need
 // to set slots on the global to put it in a consistent state.
 //
 // This API provides a way for consumers to set slots atomically (immediately
 // after the global is created), before any debugger hooks are fired. It's
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -448,17 +448,17 @@ class js::AutoDebugModeGC
     }
 };
 
 namespace js {
 
 inline bool
 ExclusiveContext::typeInferenceEnabled() const
 {
-    return compartment_->zone()->types.inferenceEnabled;
+    return compartment_->options().typeInference(this);
 }
 
 inline js::Handle<js::GlobalObject*>
 ExclusiveContext::global() const
 {
     /*
      * It's safe to use |unsafeGet()| here because any compartment that is
      * on-stack will be marked automatically, so there's no need for a read
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1328,17 +1328,17 @@ Debugger::fireNewGlobalObject(JSContext 
     JS_ASSERT(!cx->isExceptionPending());
     return status;
 }
 
 void
 Debugger::slowPathOnNewGlobalObject(JSContext *cx, Handle<GlobalObject *> global)
 {
     JS_ASSERT(!JS_CLIST_IS_EMPTY(&cx->runtime()->onNewGlobalObjectWatchers));
-    if (global->compartment()->options().invisibleToDebugger)
+    if (global->compartment()->options().invisibleToDebugger())
         return;
 
     /*
      * Make a copy of the runtime's onNewGlobalObjectWatchers before running the
      * handlers. Since one Debugger's handler can disable another's, the list
      * can be mutated while we're walking it.
      */
     AutoObjectVector watchers(cx);
@@ -1946,17 +1946,17 @@ Debugger::addDebuggee(JSContext *cx, uns
 }
 
 bool
 Debugger::addAllGlobalsAsDebuggees(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGGER(cx, argc, vp, "addAllGlobalsAsDebuggees", args, dbg);
     AutoDebugModeGC dmgc(cx->runtime());
     for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
-        if (c == dbg->object->compartment() || c->options().invisibleToDebugger)
+        if (c == dbg->object->compartment() || c->options().invisibleToDebugger())
             continue;
         c->zone()->scheduledForDestruction = false;
         GlobalObject *global = c->maybeGlobal();
         if (global) {
             Rooted<GlobalObject*> rg(cx, global);
             if (!dbg->addDebuggeeGlobal(cx, rg, dmgc))
                 return false;
         }
@@ -2129,17 +2129,17 @@ Debugger::addDebuggeeGlobal(JSContext *c
     if (debuggees.has(global))
         return true;
 
     // Callers should generally be unable to get a reference to a debugger-
     // invisible global in order to pass it to addDebuggee. But this is possible
     // with certain testing aides we expose in the shell, so just make addDebuggee
     // throw in that case.
     JSCompartment *debuggeeCompartment = global->compartment();
-    if (debuggeeCompartment->options().invisibleToDebugger) {
+    if (debuggeeCompartment->options().invisibleToDebugger()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                              JSMSG_DEBUG_CANT_DEBUG_GLOBAL);
         return false;
     }
 
     /*
      * Check for cycles. If global's compartment is reachable from this
      * Debugger object's compartment by following debuggee-to-debugger links,
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -696,17 +696,17 @@ Debugger::onExceptionUnwind(JSContext *c
 
 void
 Debugger::onNewScript(JSContext *cx, HandleScript script, GlobalObject *compileAndGoGlobal)
 {
     JS_ASSERT_IF(script->compileAndGo, compileAndGoGlobal);
     JS_ASSERT_IF(script->compileAndGo, compileAndGoGlobal == &script->uninlinedGlobal());
     // We early return in slowPathOnNewScript for self-hosted scripts, so we can
     // ignore those in our assertion here.
-    JS_ASSERT_IF(!script->compartment()->options().invisibleToDebugger &&
+    JS_ASSERT_IF(!script->compartment()->options().invisibleToDebugger() &&
                  !script->selfHosted,
                  script->compartment()->firedOnNewGlobalObject);
     JS_ASSERT_IF(!script->compileAndGo, !compileAndGoGlobal);
     if (!script->compartment()->getDebuggees().empty())
         slowPathOnNewScript(cx, script, compileAndGoGlobal);
 }
 
 void