Backed out 13 changesets (bug 880917) for Android and B2G test bustage on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 13 Jun 2013 15:19:50 -0400
changeset 146470 c0d176e71ce27c1d9cf1d7594293b6ff78bb9aba
parent 146469 1b40028e58910f95f9190420995b370abac2bf4a
child 146471 78fc466284839b15f0219ec950e1611d69a8f859
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs880917
milestone24.0a1
backs out71c1ce2cb0a41b5dd025a496e458c0840be3f379
cd240e19560f9fa099a31c96a1ec070cb3eaf3e1
93509a0001b5b7328f1034a0df19ea1ae257239f
fdbba20e4647cebad72200b554d7477892dd7fcf
d82060172367a662fcb80be685373f1542b1d1e7
709f0b6994892f48a6f35983b7108a263166baa5
421bdbccfa7cabd68b419ec9ed92cb22cd0fba78
962c656c7452485db6ee61359bf37fca8b4bb9b3
888a5690ccdf5991851948145a8c3bfd168c973f
57228f5fcd875a6acd6971c045b4747cdcfadc67
ce8c3e14c234cdec5cbf80eb30e9403d7675b875
08fe7b7774504712faf0ff5cf7dcfb8904a1af89
5192a9233d8389e211305dac1d5496e67a222b54
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
Backed out 13 changesets (bug 880917) for Android and B2G test bustage on a CLOSED TREE. Backed out changeset 71c1ce2cb0a4 (bug 880917) Backed out changeset cd240e19560f (bug 880917) Backed out changeset 93509a0001b5 (bug 880917) Backed out changeset fdbba20e4647 (bug 880917) Backed out changeset d82060172367 (bug 880917) Backed out changeset 709f0b699489 (bug 880917) Backed out changeset 421bdbccfa7c (bug 880917) Backed out changeset 962c656c7452 (bug 880917) Backed out changeset 888a5690ccdf (bug 880917) Backed out changeset 57228f5fcd87 (bug 880917) Backed out changeset ce8c3e14c234 (bug 880917) Backed out changeset 08fe7b777450 (bug 880917) Backed out changeset 5192a9233d83 (bug 880917)
content/base/src/nsFrameMessageManager.cpp
content/xbl/src/nsXBLDocumentInfo.cpp
content/xbl/src/nsXBLProtoImpl.cpp
content/xul/document/src/nsXULPrototypeDocument.cpp
dom/base/nsGlobalWindow.cpp
dom/workers/RuntimeService.cpp
dom/workers/WorkerScope.cpp
ipc/testshell/XPCShellEnvironment.cpp
js/jsd/idl/jsdIDebuggerService.idl
js/jsd/jsd_xpc.cpp
js/src/gdb/gdb-tests.cpp
js/src/jsapi-tests/moz.build
js/src/jsapi-tests/testVersion.cpp
js/src/jsapi-tests/tests.cpp
js/src/jsapi-tests/tests.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/shell/js.cpp
js/src/tests/js1_8/regress/regress-384412.js
js/src/vm/Stack.cpp
js/xpconnect/idl/nsIXPConnect.idl
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/shell/xpcshell.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCJSContextStack.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/tests/unit/bug596580_versioned.js
js/xpconnect/tests/unit/test_bug596580.js
js/xpconnect/tests/unit/xpcshell.ini
netwerk/base/src/ProxyAutoConfig.cpp
netwerk/test/httpserver/httpd.js
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1103,30 +1103,28 @@ nsFrameScriptExecutor::InitTabChildGloba
   NS_ENSURE_TRUE(cx_, false);
   AutoPushJSContext cx(cx_);
 
   mCx = cx;
 
   nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal));
 
   JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_PRIVATE_IS_NSISUPPORTS);
+  JS_SetVersion(cx, JSVERSION_LATEST);
   JS_SetErrorReporter(cx, ContentScriptErrorReporter);
 
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
   const uint32_t flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES;
 
 
   JS_SetContextPrivate(cx, aScope);
 
-  JS::CompartmentOptions options;
-  options.setZone(JS::SystemZone)
-         .setVersion(JSVERSION_LATEST);
   nsresult rv =
     xpc->InitClassesWithNewWrappedGlobal(cx, aScope, mPrincipal,
-                                         flags, options, getter_AddRefs(mGlobal));
+                                         flags, JS::SystemZone, getter_AddRefs(mGlobal));
   NS_ENSURE_SUCCESS(rv, false);
 
 
   JS::Rooted<JSObject*> global(cx, mGlobal->GetJSObject());
   NS_ENSURE_TRUE(global, false);
 
   JS_SetGlobalObject(cx, global);
 
--- a/content/xbl/src/nsXBLDocumentInfo.cpp
+++ b/content/xbl/src/nsXBLDocumentInfo.cpp
@@ -279,21 +279,19 @@ nsXBLDocGlobalObject::EnsureScriptEnviro
 
   AutoPushJSContext cx(mScriptContext->GetNativeContext());
 
   // nsJSEnvironment set the error reporter to NS_ScriptErrorReporter so
   // we must apparently override that with our own (although it isn't clear 
   // why - see bug 339647)
   JS_SetErrorReporter(cx, XBL_ProtoErrorReporter);
 
-  JS::CompartmentOptions options;
-  options.setZone(JS::SystemZone);
   mJSObject = JS_NewGlobalObject(cx, &gSharedGlobalClass,
                                  nsJSPrincipals::get(GetPrincipal()),
-                                 options);
+                                 JS::SystemZone);
   if (!mJSObject)
       return NS_OK;
 
   // Set the location information for the new global, so that tools like
   // about:memory may use that information
   nsIURI *ownerURI = mGlobalObjectOwner->DocumentURI();
   xpc::SetLocationForGlobal(mJSObject, ownerURI);
 
--- a/content/xbl/src/nsXBLProtoImpl.cpp
+++ b/content/xbl/src/nsXBLProtoImpl.cpp
@@ -16,16 +16,37 @@
 #include "nsIXPConnect.h"
 #include "nsIServiceManager.h"
 #include "nsIDOMNode.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsXBLProtoImplProperty.h"
 
 using namespace mozilla;
 
+// Checks that the version is not modified in a given scope.
+class AutoVersionChecker
+{
+  DebugOnly<JSContext *> const cx;
+  DebugOnly<JSVersion> versionBefore;
+
+public:
+  explicit AutoVersionChecker(JSContext *aCx) : cx(aCx) {
+#ifdef DEBUG
+    versionBefore = JS_GetVersion(cx);
+#endif
+  }
+
+  ~AutoVersionChecker() {
+#ifdef DEBUG
+    JSVersion versionAfter = JS_GetVersion(cx);
+    NS_ABORT_IF_FALSE(versionAfter == versionBefore, "version must not change");
+#endif
+  }
+};
+
 nsresult
 nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aPrototypeBinding,
                                       nsXBLBinding* aBinding)
 {
   // This function is called to install a concrete implementation on a bound element using
   // this prototype implementation as a guide.  The prototype implementation is compiled lazily,
   // so for the first bound element that needs a concrete implementation, we also build the
   // prototype implementation.
@@ -63,16 +84,17 @@ nsXBLProtoImpl::InstallImplementation(ns
   if (!targetObjectIsNew)
     return NS_OK;
 
   JS::Rooted<JSObject*> targetScriptObject(context->GetNativeContext(),
                                            holder->GetJSObject());
 
   AutoPushJSContext cx(context->GetNativeContext());
   JSAutoCompartment ac(cx, targetClassObject);
+  AutoVersionChecker avc(cx);
 
   // Walk our member list and install each one in turn.
   for (nsXBLProtoImplMember* curr = mMembers;
        curr;
        curr = curr->GetNext())
     curr->InstallMember(cx, targetClassObject);
 
   // If we're using a separate XBL scope, make a safe copy of the target class
@@ -202,16 +224,18 @@ nsXBLProtoImpl::CompilePrototypeMembers(
                                     &classObject, &classObjectIsNew);
   if (NS_FAILED(rv))
     return rv;
 
   MOZ_ASSERT(classObjectIsNew);
   MOZ_ASSERT(classObject);
   mClassObject = classObject;
 
+  AutoVersionChecker avc(cx);
+
   // Now that we have a class object installed, we walk our member list and compile each of our
   // properties and methods in turn.
   for (nsXBLProtoImplMember* curr = mMembers;
        curr;
        curr = curr->GetNext()) {
     nsresult rv = curr->CompileMember(context, mClassName, classObject);
     if (NS_FAILED(rv)) {
       DestroyMembers();
@@ -270,16 +294,17 @@ nsXBLProtoImpl::FindField(const nsString
   }
 
   return nullptr;
 }
 
 bool
 nsXBLProtoImpl::ResolveAllFields(JSContext *cx, JS::Handle<JSObject*> obj) const
 {
+  AutoVersionChecker avc(cx);
   for (nsXBLProtoImplField* f = mFields; f; f = f->GetNext()) {
     // Using OBJ_LOOKUP_PROPERTY is a pain, since what we have is a
     // PRUnichar* for the property name.  Let's just use the public API and
     // all.
     nsDependentString name(f->GetName());
     JS::Rooted<JS::Value> dummy(cx);
     if (!::JS_LookupUCProperty(cx, obj,
                                reinterpret_cast<const jschar*>(name.get()),
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -757,21 +757,19 @@ nsXULPDGlobalObject::EnsureScriptEnviron
   nsCOMPtr<nsIScriptContext> ctxNew = languageRuntime->CreateContext(false, nullptr);
   MOZ_ASSERT(ctxNew);
 
   // We have to setup a special global object.  We do this then
   // attach it as the global for this context.  Then, we
   // will re-fetch the global and set it up in our language globals array.
   {
     AutoPushJSContext cx(ctxNew->GetNativeContext());
-    JS::CompartmentOptions options;
-    options.setZone(JS::SystemZone);
     JS::Rooted<JSObject*> newGlob(cx,
       JS_NewGlobalObject(cx, &gSharedGlobalClass,
-                         nsJSPrincipals::get(GetPrincipal()), options));
+                         nsJSPrincipals::get(GetPrincipal()), JS::SystemZone));
     if (!newGlob)
         return NS_OK;
 
     ::JS_SetGlobalObject(cx, newGlob);
 
     // Add an owning reference from JS back to us. This'll be
     // released when the JSObject is finalized.
     ::JS_SetPrivate(newGlob, this);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2115,36 +2115,36 @@ CreateNativeGlobalForInner(JSContext* aC
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aNativeGlobal);
   MOZ_ASSERT(aHolder);
 
   nsGlobalWindow *top = NULL;
   if (aNewInner->GetOuterWindow()) {
     top = aNewInner->GetTop();
   }
-  JS::CompartmentOptions options;
+  JS::ZoneSpecifier zoneSpec = JS::FreshZone;
   if (top) {
     if (top->GetGlobalJSObject()) {
-      options.zoneSpec = JS::SameZoneAs(top->GetGlobalJSObject());
+      zoneSpec = JS::SameZoneAs(top->GetGlobalJSObject());
     }
   }
 
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
 
   // Determine if we need the Components object.
   bool componentsInContent = !Preferences::GetBool("dom.omit_components_in_content", true);
   bool needComponents = componentsInContent ||
                         nsContentUtils::IsSystemPrincipal(aPrincipal) ||
                         TreatAsRemoteXUL(aPrincipal);
   uint32_t flags = needComponents ? 0 : nsIXPConnect::OMIT_COMPONENTS_OBJECT;
 
   nsRefPtr<nsIXPConnectJSObjectHolder> jsholder;
   nsresult rv = xpc->InitClassesWithNewWrappedGlobal(
     aCx, ToSupports(aNewInner),
-    aPrincipal, flags, options, getter_AddRefs(jsholder));
+    aPrincipal, flags, zoneSpec, getter_AddRefs(jsholder));
   NS_ENSURE_SUCCESS(rv, rv);
 
   MOZ_ASSERT(jsholder);
   *aNativeGlobal = jsholder->GetJSObject();
   jsholder.forget(aHolder);
 
   // Set the location information for the new global, so that tools like
   // about:memory may use that information
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -824,16 +824,20 @@ CreateJSContextForWorker(WorkerPrivate* 
                                                    settings.content.options);
 
   JS_SetJitHardening(runtime, settings.jitHardening);
 
 #ifdef JS_GC_ZEAL
   JS_SetGCZeal(workerCx, settings.gcZeal, settings.gcZealFrequency);
 #endif
 
+  if (aWorkerPrivate->IsChromeWorker()) {
+    JS_SetVersion(workerCx, JSVERSION_LATEST);
+  }
+
   return workerCx;
 }
 
 class WorkerThreadRunnable : public nsRunnable
 {
   WorkerPrivate* mWorkerPrivate;
 
 public:
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -962,22 +962,19 @@ BEGIN_WORKERS_NAMESPACE
 JSObject*
 CreateDedicatedWorkerGlobalScope(JSContext* aCx)
 {
   using namespace mozilla::dom;
 
   WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
   JS_ASSERT(worker);
 
-  JS::CompartmentOptions options;
-  if (worker->IsChromeWorker())
-    options.setVersion(JSVERSION_LATEST);
   JS::Rooted<JSObject*> global(aCx,
     JS_NewGlobalObject(aCx, DedicatedWorkerGlobalScope::Class(),
-                       GetWorkerPrincipal(), options));
+                       GetWorkerPrincipal()));
   if (!global) {
     return NULL;
   }
 
   JSAutoCompartment ac(aCx, global);
 
   // Make the private slots now so that all our instance checks succeed.
   if (!DedicatedWorkerGlobalScope::InitPrivate(aCx, global, worker)) {
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -183,16 +183,17 @@ static JSBool
 ContextCallback(JSContext *cx,
                 unsigned contextOp)
 {
     if (gOldContextCallback && !gOldContextCallback(cx, contextOp))
         return JS_FALSE;
 
     if (contextOp == JSCONTEXT_NEW) {
         JS_SetErrorReporter(cx, ScriptErrorReporter);
+        JS_SetVersion(cx, JSVERSION_LATEST);
     }
     return JS_TRUE;
 }
 
 static JSBool
 Print(JSContext *cx,
       unsigned argc,
       JS::Value *vp)
@@ -300,20 +301,20 @@ Load(JSContext *cx,
 }
 
 static JSBool
 Version(JSContext *cx,
         unsigned argc,
         JS::Value *vp)
 {
     JS::Value *argv = JS_ARGV(cx, vp);
-    JS_SET_RVAL(cx, vp, INT_TO_JSVAL(JS_GetVersion(cx)));
     if (argc > 0 && JSVAL_IS_INT(argv[0]))
-        JS_SetVersionForCompartment(js::GetContextCompartment(cx),
-                                    JSVersion(JSVAL_TO_INT(argv[0])));
+        JS_SET_RVAL(cx, vp, INT_TO_JSVAL(JS_SetVersion(cx, JSVersion(JSVAL_TO_INT(argv[0])))));
+    else
+        JS_SET_RVAL(cx, vp, INT_TO_JSVAL(JS_GetVersion(cx)));
     return JS_TRUE;
 }
 
 static JSBool
 BuildDate(JSContext *cx, unsigned argc, JS::Value *vp)
 {
     fprintf(stdout, "built on %s at %s\n", __DATE__, __TIME__);
     return JS_TRUE;
@@ -777,24 +778,21 @@ XPCShellEnvironment::Init()
 
     nsRefPtr<BackstagePass> backstagePass;
     rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
     if (NS_FAILED(rv)) {
         NS_ERROR("Failed to create backstage pass!");
         return false;
     }
 
-    JS::CompartmentOptions options;
-    options.setZone(JS::SystemZone)
-           .setVersion(JSVERSION_LATEST);
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
     rv = xpc->InitClassesWithNewWrappedGlobal(cx,
                                               static_cast<nsIGlobalObject *>(backstagePass),
                                               principal, 0,
-                                              options,
+                                              JS::SystemZone,
                                               getter_AddRefs(holder));
     if (NS_FAILED(rv)) {
         NS_ERROR("InitClassesWithNewWrappedGlobal failed!");
         return false;
     }
 
     JS::Rooted<JSObject*> globalObj(cx, holder->GetJSObject());
     if (!globalObj) {
--- a/js/jsd/idl/jsdIDebuggerService.idl
+++ b/js/jsd/idl/jsdIDebuggerService.idl
@@ -40,17 +40,17 @@ interface jsdIValue;
 interface jsdIObject;
 interface jsdIProperty;
 interface jsdIActivationCallback;
 
 /**
  * Debugger service. It is not a good idea to have more than one active client
  * of the debugger service.
  */
-[scriptable, uuid(029b8f0a-aa84-47eb-a60f-1a4752b7ad06)]
+[scriptable, uuid(9be5b327-6818-464d-9695-f33885fd8377)]
 interface jsdIDebuggerService : nsISupports
 {
     /** Internal use only. */
     [noscript] readonly attribute JSDContext        JSDContext;
 
     /**
      * Called when an error or warning occurs.
      */
@@ -83,16 +83,39 @@ interface jsdIDebuggerService : nsISuppo
      * Called before and after a toplevel script is evaluated.
      */
     attribute jsdICallHook      topLevelHook;
     /**
      * Called before and after a function is called.
      */
     attribute jsdICallHook      functionHook;
 
+
+    /**
+     * VERSION_* values must be kept in sync with the JSVersion enumeration in
+     * jspubtd.h.
+     */
+
+    /**
+     * Possible values for jsdIScript::version and jsdIContext::version.
+     */
+    const long VERSION_1_0     = 100;
+    const long VERSION_1_1     = 110;
+    const long VERSION_1_2     = 120;
+    const long VERSION_1_3     = 130;
+    const long VERSION_1_4     = 140;
+    const long VERSION_1_5     = 150;
+    const long VERSION_DEFAULT = 0;
+    const long VERSION_UNKNOWN = -1;
+
+    /**
+     * These flags need to be kept in sync with the context flags defined in
+     * jsdebug.h
+     */
+
     /**
      * Link native frames in call stacks.
      */
     const unsigned long ENABLE_NATIVE_FRAMES     = 0x01;
     /**
      * Normally, if a script has a 0 in JSD_SCRIPT_PROFILE_BIT it is included in
      * profile data, otherwise it is not profiled. Setting the
      * PROFILE_WHEN_SET flag reverses this convention.
@@ -695,16 +718,23 @@ interface jsdIContext : jsdIEphemeral
      */
     const long OPT_ISUPPORTS   = 0x08;
     /**
      * OPT_* values above, OR'd together.
      */
     attribute unsigned long          options;
 
     /**
+     * Last version set on this context.
+     * Scripts typically select this with the "language" attribute.
+     * See the VERSION_* consts on jsdIDebuggerService.
+     */
+    attribute long                   version;
+
+    /**
      * Unique tag among all valid jsdIContext objects, useful as a hash key.
      */
     readonly attribute unsigned long tag;
 
     /**
      * Private data for this context, if it is an nsISupports, |null| otherwise.
      */
     readonly attribute nsISupports   privateData;
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -1689,16 +1689,33 @@ jsdContext::GetTag(uint32_t *_rval)
     if (!mTag)
         mTag = ++jsdContext::LastTag;
     
     *_rval = mTag;
     return NS_OK;
 }
 
 NS_IMETHODIMP
+jsdContext::GetVersion (int32_t *_rval)
+{
+    ASSERT_VALID_EPHEMERAL;
+    *_rval = static_cast<int32_t>(JS_GetVersion(mJSCx));
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+jsdContext::SetVersion (int32_t id)
+{
+    ASSERT_VALID_EPHEMERAL;
+    JSVersion ver = static_cast<JSVersion>(id);
+    JS_SetVersion(mJSCx, ver);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 jsdContext::GetGlobalObject (jsdIValue **_rval)
 {
     ASSERT_VALID_EPHEMERAL;
     JSObject *glob = js::GetDefaultGlobalForContext(mJSCx);
     JSDValue *jsdv = JSD_NewValue (mJSDCx, OBJECT_TO_JSVAL(glob));
     if (!jsdv)
         return NS_ERROR_FAILURE;
     *_rval = jsdValue::FromPtr (mJSDCx, jsdv);
--- a/js/src/gdb/gdb-tests.cpp
+++ b/js/src/gdb/gdb-tests.cpp
@@ -57,24 +57,23 @@ GDBFragment *GDBFragment::allFragments =
 int
 main (int argc, const char **argv)
 {
     JSRuntime *runtime = checkPtr(JS_NewRuntime(1024 * 1024, JS_USE_HELPER_THREADS));
     JS_SetGCParameter(runtime, JSGC_MAX_BYTES, 0xffffffff);
     JS_SetNativeStackQuota(runtime, 5000000);
 
     JSContext *cx = checkPtr(JS_NewContext(runtime, 8192));
+    JS_SetVersion(cx, JSVERSION_LATEST);
     JS_SetErrorReporter(cx, reportError);
 
     JSAutoRequest ar(cx);
 
     /* Create the global object. */
-    JS::CompartmentOptions options;
-    options.setVersion(JSVERSION_LATEST);
-    RootedObject global(cx, checkPtr(JS_NewGlobalObject(cx, &global_class, NULL, options)));
+    RootedObject global(cx, checkPtr(JS_NewGlobalObject(cx, &global_class, NULL)));
     JS_SetGlobalObject(cx, global);
 
     JSAutoCompartment ac(cx, global);
 
     /* Populate the global object with the standard globals,
        like Object and Array. */
     checkBool(JS_InitStandardClasses(cx, global));
 
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -59,11 +59,12 @@ CPP_SOURCES += [
     'testScriptObject.cpp',
     'testSetProperty.cpp',
     'testSourcePolicy.cpp',
     'testStringBuffer.cpp',
     'testToIntWidth.cpp',
     'testTrap.cpp',
     'testTypedArrays.cpp',
     'testUTF8.cpp',
+    'testVersion.cpp',
     'testXDR.cpp',
     'tests.cpp',
 ]
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testVersion.cpp
@@ -0,0 +1,171 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "tests.h"
+#include "jsscript.h"
+#include "jscntxt.h"
+
+#include "jscntxtinlines.h"
+#include "jsobjinlines.h"
+
+using namespace js;
+
+struct VersionFixture;
+
+/*
+ * Fast-native callbacks for use from JS.
+ * They set their results on the current fixture instance.
+ */
+
+static VersionFixture *callbackData = NULL;
+
+JSBool CallSetVersion17(JSContext *cx, unsigned argc, jsval *vp);
+JSBool OverrideVersion18(JSContext *cx, unsigned argc, jsval *vp);
+JSBool CaptureVersion(JSContext *cx, unsigned argc, jsval *vp);
+JSBool CheckOverride(JSContext *cx, unsigned argc, jsval *vp);
+JSBool EvalScriptVersion16(JSContext *cx, unsigned argc, jsval *vp);
+
+struct VersionFixture : public JSAPITest
+{
+    JSVersion captured;
+
+    virtual bool init() {
+        if (!JSAPITest::init())
+            return false;
+        JS_SetOptions(cx, JS_GetOptions(cx));
+        callbackData = this;
+        captured = JSVERSION_UNKNOWN;
+        JS::RootedObject global(cx, JS_GetGlobalForScopeChain(cx));
+        return JS_DefineFunction(cx, global, "callSetVersion17", CallSetVersion17, 0, 0) &&
+               JS_DefineFunction(cx, global, "overrideVersion18", OverrideVersion18, 0, 0) &&
+               JS_DefineFunction(cx, global, "captureVersion", CaptureVersion, 0, 0) &&
+               JS_DefineFunction(cx, global, "checkOverride", CheckOverride, 1, 0) &&
+               JS_DefineFunction(cx, global, "evalScriptVersion16",
+                                 EvalScriptVersion16, 0, 0);
+    }
+
+    JSScript *fakeScript(const char *contents, size_t length) {
+        JS::RootedObject global(cx, JS_GetGlobalForScopeChain(cx));
+        return JS_CompileScript(cx, global, contents, length, "<test>", 1);
+    }
+
+    bool checkVersionIsOverridden() {
+        CHECK(cx->isVersionOverridden());
+        return true;
+    }
+
+    bool setVersion(JSVersion version) {
+        CHECK(JS_GetVersion(cx) != version);
+        JS_SetVersion(cx, version);
+        return true;
+    }
+
+    bool evalVersion(const jschar *chars, size_t len, JSVersion version) {
+        CHECK(JS_GetVersion(cx) != version);
+        jsval rval;
+        JS::RootedObject global(cx, JS_GetGlobalForScopeChain(cx));
+        CHECK(JS_EvaluateUCScriptForPrincipalsVersion(
+                cx, global, NULL, chars, len, "<test>", 0, &rval, version));
+        return true;
+    }
+};
+
+/* Callbacks to throw into JS-land. */
+
+JSBool
+CallSetVersion17(JSContext *cx, unsigned argc, jsval *vp)
+{
+    return callbackData->setVersion(JSVERSION_1_7);
+}
+
+JSBool
+OverrideVersion18(JSContext *cx, unsigned argc, jsval *vp)
+{
+    if (!callbackData->setVersion(JSVERSION_1_8))
+        return false;
+    return callbackData->checkVersionIsOverridden();
+}
+
+JSBool
+EvalScriptVersion16(JSContext *cx, unsigned argc, jsval *vp)
+{
+    JS_ASSERT(argc == 1);
+    jsval *argv = JS_ARGV(cx, vp);
+    JS_ASSERT(JSVAL_IS_STRING(argv[0]));
+    JSStableString *str = JSVAL_TO_STRING(argv[0])->ensureStable(cx);
+    JS_ASSERT(str);
+    return callbackData->evalVersion(str->chars().get(), str->length(), JSVERSION_1_6);
+}
+
+JSBool
+CaptureVersion(JSContext *cx, unsigned argc, jsval *vp)
+{
+    callbackData->captured = JS_GetVersion(cx);
+    return true;
+}
+
+JSBool
+CheckOverride(JSContext *cx, unsigned argc, jsval *vp)
+{
+    JS_ASSERT(argc == 1);
+    jsval *argv = JS_ARGV(cx, vp);
+    JS_ASSERT(JSVAL_IS_BOOLEAN(argv[0]));
+    bool shouldHaveOverride = !!JSVAL_TO_BOOLEAN(argv[0]);
+    return shouldHaveOverride == cx->isVersionOverridden();
+}
+
+/*
+ * When re-entering the virtual machine through a *Version API the version
+ * is no longer forced -- it continues with its natural push/pop oriented
+ * version progression.  This is maintained by the |AutoVersionAPI| class in
+ * jsapi.cpp.
+ */
+BEGIN_FIXTURE_TEST(VersionFixture, testVersion_EntryLosesOverride)
+{
+    EXEC("overrideVersion18(); evalScriptVersion16('checkOverride(false); captureVersion()');");
+    CHECK_EQUAL(captured, JSVERSION_1_6);
+
+    /*
+     * Override gets propagated to default version as non-override when you leave the VM's execute
+     * call.
+     */
+    CHECK_EQUAL(JS_GetVersion(cx), JSVERSION_1_8);
+    CHECK(!cx->isVersionOverridden());
+    return true;
+}
+END_FIXTURE_TEST(VersionFixture, testVersion_EntryLosesOverride)
+
+/*
+ * EvalScriptVersion does not propagate overrides to its caller, it
+ * restores things exactly as they were before the call. This is as opposed to
+ * the normal (no Version suffix) API which propagates overrides
+ * to the caller.
+ */
+BEGIN_FIXTURE_TEST(VersionFixture, testVersion_ReturnLosesOverride)
+{
+    CHECK_EQUAL(JS_GetVersion(cx), JSVERSION_ECMA_5);
+    EXEC(
+        "checkOverride(false);"
+        "evalScriptVersion16('overrideVersion18();');"
+        "checkOverride(false);"
+        "captureVersion();"
+    );
+    CHECK_EQUAL(captured, JSVERSION_ECMA_5);
+    return true;
+}
+END_FIXTURE_TEST(VersionFixture, testVersion_ReturnLosesOverride)
+
+BEGIN_FIXTURE_TEST(VersionFixture, testVersion_EvalPropagatesOverride)
+{
+    CHECK_EQUAL(JS_GetVersion(cx), JSVERSION_ECMA_5);
+    EXEC(
+        "checkOverride(false);"
+        "eval('overrideVersion18();');"
+        "checkOverride(true);"
+        "captureVersion();"
+    );
+    CHECK_EQUAL(captured, JSVERSION_1_8);
+    return true;
+}
+END_FIXTURE_TEST(VersionFixture, testVersion_EvalPropagatesOverride)
--- a/js/src/jsapi-tests/tests.cpp
+++ b/js/src/jsapi-tests/tests.cpp
@@ -46,19 +46,17 @@ bool JSAPITest::definePrint()
 {
     JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&this->global);
     return JS_DefineFunction(cx, global, "print", (JSNative) print, 0, 0);
 }
 
 JSObject * JSAPITest::createGlobal(JSPrincipals *principals)
 {
     /* Create the global object. */
-    JS::CompartmentOptions options;
-    options.setVersion(JSVERSION_LATEST);
-    global = JS_NewGlobalObject(cx, getGlobalClass(), principals, options);
+    global = JS_NewGlobalObject(cx, getGlobalClass(), principals);
     if (!global)
         return NULL;
     JS_AddNamedObjectRoot(cx, &global, "test-global");
     JS::HandleObject globalHandle = JS::HandleObject::fromMarkedLocation(&global);
 
     JSAutoCompartment ac(cx, globalHandle);
 
     /* Populate the global object with the standard globals, like Object and
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -294,16 +294,17 @@ class JSAPITest
                 message);
     }
 
     virtual JSContext * createContext() {
         JSContext *cx = JS_NewContext(rt, 8192);
         if (!cx)
             return NULL;
         JS_SetOptions(cx, JSOPTION_VAROBJFIX);
+        JS_SetVersion(cx, JSVERSION_LATEST);
         JS_SetErrorReporter(cx, &reportError);
         return cx;
     }
 
     virtual JSClass * getGlobalClass() {
         return basicGlobalClass();
     }
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -117,16 +117,57 @@ JS::detail::CallMethodIfWrapped(JSContex
         if (thisObj.isProxy())
             return Proxy::nativeCall(cx, test, impl, args);
     }
 
     ReportIncompatible(cx, args);
     return false;
 }
 
+
+/*
+ * This class is a version-establishing barrier at the head of a VM entry or
+ * re-entry. It ensures that:
+ *
+ * - |newVersion| is the starting (default) version used for the context.
+ * - The starting version state is not an override.
+ * - Overrides in the VM session are not propagated to the caller.
+ */
+class AutoVersionAPI
+{
+    JSContext   * const cx;
+    JSVersion   oldDefaultVersion;
+    bool        oldHasVersionOverride;
+    JSVersion   oldVersionOverride;
+    JSVersion   newVersion;
+
+  public:
+    AutoVersionAPI(JSContext *cx, JSVersion newVersion)
+      : cx(cx),
+        oldDefaultVersion(cx->getDefaultVersion()),
+        oldHasVersionOverride(cx->isVersionOverridden()),
+        oldVersionOverride(oldHasVersionOverride ? cx->findVersion() : JSVERSION_UNKNOWN)
+    {
+        this->newVersion = newVersion;
+        cx->clearVersionOverride();
+        cx->setDefaultVersion(newVersion);
+    }
+
+    ~AutoVersionAPI() {
+        cx->setDefaultVersion(oldDefaultVersion);
+        if (oldHasVersionOverride)
+            cx->overrideVersion(oldVersionOverride);
+        else
+            cx->clearVersionOverride();
+    }
+
+    /* The version that this scoped-entity establishes. */
+    JSVersion version() const { return newVersion; }
+};
+
 #ifdef HAVE_VA_LIST_AS_ARRAY
 #define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
 #else
 #define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
 #endif
 
 #ifdef JS_USE_JSID_STRUCT_TYPES
 jsid JSID_VOID  = { size_t(JSID_TYPE_VOID) };
@@ -689,17 +730,16 @@ JSRuntime::JSRuntime(JSUseHelperThreads 
     operationCallbackOwner(NULL),
 #endif
 #endif
     atomsCompartment(NULL),
     systemZone(NULL),
     numCompartments(0),
     localeCallbacks(NULL),
     defaultLocale(NULL),
-    defaultVersion_(JSVERSION_DEFAULT),
 #ifdef JS_THREADSAFE
     ownerThread_(NULL),
 #endif
     tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
     freeLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
     execAlloc_(NULL),
     bumpAlloc_(NULL),
     ionRuntime_(NULL),
@@ -896,18 +936,17 @@ JSRuntime::init(uint32_t maxbytes)
     const char *size = getenv("JSGC_MARK_STACK_LIMIT");
     if (size)
         SetMarkStackLimit(this, atoi(size));
 
     ScopedJSDeletePtr<Zone> atomsZone(new_<Zone>(this));
     if (!atomsZone)
         return false;
 
-    JS::CompartmentOptions options;
-    ScopedJSDeletePtr<JSCompartment> atomsCompartment(new_<JSCompartment>(atomsZone.get(), options));
+    ScopedJSDeletePtr<JSCompartment> atomsCompartment(new_<JSCompartment>(atomsZone.get()));
     if (!atomsCompartment || !atomsCompartment->init(NULL))
         return false;
 
     zones.append(atomsZone.get());
     atomsZone->compartments.append(atomsCompartment.get());
 
     atomsCompartment->isSystem = true;
     atomsZone->isSystem = true;
@@ -1295,20 +1334,31 @@ JS_ContextIterator(JSRuntime *rt, JSCont
 }
 
 JS_PUBLIC_API(JSVersion)
 JS_GetVersion(JSContext *cx)
 {
     return VersionNumber(cx->findVersion());
 }
 
-JS_PUBLIC_API(void)
-JS_SetVersionForCompartment(JSCompartment *compartment, JSVersion version)
-{
-    compartment->options().setVersion(version);
+JS_PUBLIC_API(JSVersion)
+JS_SetVersion(JSContext *cx, JSVersion newVersion)
+{
+    JS_ASSERT(VersionIsKnown(newVersion));
+    JS_ASSERT(!VersionHasFlags(newVersion));
+    JSVersion newVersionNumber = newVersion;
+
+    JSVersion oldVersion = cx->findVersion();
+    JSVersion oldVersionNumber = VersionNumber(oldVersion);
+    if (oldVersionNumber == newVersionNumber)
+        return oldVersionNumber; /* No override actually occurs! */
+
+    VersionCopyFlags(&newVersion, oldVersion);
+    cx->maybeOverrideVersion(newVersion);
+    return oldVersionNumber;
 }
 
 static struct v2smap {
     JSVersion   version;
     const char  *string;
 } v2smap[] = {
     {JSVERSION_ECMA_3,  "ECMAv3"},
     {JSVERSION_1_6,     "1.6"},
@@ -3372,38 +3422,37 @@ class AutoHoldZone
     }
 
   private:
     bool *holdp;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 JS_PUBLIC_API(JSObject *)
-JS_NewGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals,
-                   const JS::CompartmentOptions &options)
+JS_NewGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals, JS::ZoneSpecifier zoneSpec)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
 
     JSRuntime *rt = cx->runtime();
 
     Zone *zone;
-    if (options.zoneSpec == JS::SystemZone)
+    if (zoneSpec == JS::SystemZone)
         zone = rt->systemZone;
-    else if (options.zoneSpec == JS::FreshZone)
+    else if (zoneSpec == JS::FreshZone)
         zone = NULL;
     else
-        zone = ((JSObject *)options.zoneSpec)->zone();
-
-    JSCompartment *compartment = NewCompartment(cx, zone, principals, options);
+        zone = ((JSObject *)zoneSpec)->zone();
+
+    JSCompartment *compartment = NewCompartment(cx, zone, principals);
     if (!compartment)
         return NULL;
 
-    if (options.zoneSpec == JS::SystemZone) {
+    if (zoneSpec == JS::SystemZone) {
         rt->systemZone = compartment->zone();
         rt->systemZone->isSystem = true;
     }
 
     AutoHoldZone hold(compartment->zone());
 
     JSCompartment *saved = cx->compartment();
     cx->setCompartment(compartment);
@@ -5258,16 +5307,23 @@ JS::CompileOptions::CompileOptions(JSCon
       sourcePolicy(SAVE_SOURCE)
 {
 }
 
 JSScript *
 JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options,
             const jschar *chars, size_t length)
 {
+    Maybe<AutoVersionAPI> mava;
+    if (options.versionSet) {
+        mava.construct(cx, options.version);
+        // AutoVersionAPI propagates some compilation flags through.
+        options.version = mava.ref().version();
+    }
+
     JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JS_ASSERT_IF(options.principals, cx->compartment()->principals == options.principals);
     AutoLastFrameCheck lfc(cx);
 
     return frontend::CompileScript(cx, obj, NullPtr(), options, chars, length);
@@ -5410,16 +5466,23 @@ JS_GetGlobalFromScript(JSScript *script)
     return &script->global();
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS::CompileFunction(JSContext *cx, HandleObject obj, CompileOptions options,
                     const char *name, unsigned nargs, const char **argnames,
                     const jschar *chars, size_t length)
 {
+    Maybe<AutoVersionAPI> mava;
+    if (options.versionSet) {
+        mava.construct(cx, options.version);
+        // AutoVersionAPI propagates some compilation flags through.
+        options.version = mava.ref().version();
+    }
+
     JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JS_ASSERT_IF(options.principals, cx->compartment()->principals == options.principals);
     AutoLastFrameCheck lfc(cx);
 
     RootedAtom funAtom(cx);
@@ -5584,25 +5647,33 @@ JS_ExecuteScript(JSContext *cx, JSObject
     return Execute(cx, script, *obj, rval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ExecuteScriptVersion(JSContext *cx, JSObject *objArg, JSScript *script, jsval *rval,
                         JSVersion version)
 {
     RootedObject obj(cx, objArg);
+    AutoVersionAPI ava(cx, version);
     return JS_ExecuteScript(cx, obj, script, rval);
 }
 
 static const unsigned LARGE_SCRIPT_LENGTH = 500*1024;
 
 extern JS_PUBLIC_API(bool)
 JS::Evaluate(JSContext *cx, HandleObject obj, CompileOptions options,
              const jschar *chars, size_t length, jsval *rval)
 {
+    Maybe<AutoVersionAPI> mava;
+    if (options.versionSet) {
+        mava.construct(cx, options.version);
+        // AutoVersionAPI propagates some compilation flags through.
+        options.version = mava.ref().version();
+    }
+
     JS_THREADSAFE_ASSERT(cx->compartment() != cx->runtime()->atomsCompartment);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JS_ASSERT_IF(options.principals, cx->compartment()->principals == options.principals);
 
     AutoLastFrameCheck lfc(cx);
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1885,24 +1885,18 @@ extern JS_PUBLIC_API(JSRuntime *)
 JS_GetRuntime(JSContext *cx);
 
 extern JS_PUBLIC_API(JSContext *)
 JS_ContextIterator(JSRuntime *rt, JSContext **iterp);
 
 extern JS_PUBLIC_API(JSVersion)
 JS_GetVersion(JSContext *cx);
 
-// Mutate the version on the compartment. This is generally discouraged, but
-// necessary to support the version mutation in the js and xpc shell command
-// set.
-//
-// It would be nice to put this in jsfriendapi, but the linkage requirements
-// of the shells make that impossible.
-JS_PUBLIC_API(void)
-JS_SetVersionForCompartment(JSCompartment *compartment, JSVersion version);
+extern JS_PUBLIC_API(JSVersion)
+JS_SetVersion(JSContext *cx, JSVersion version);
 
 extern JS_PUBLIC_API(const char *)
 JS_VersionToString(JSVersion version);
 
 extern JS_PUBLIC_API(JSVersion)
 JS_StringToVersion(const char *string);
 
 /*
@@ -3145,35 +3139,21 @@ typedef uintptr_t ZoneSpecifier;
 
 inline ZoneSpecifier
 SameZoneAs(JSObject *obj)
 {
     JS_ASSERT(uintptr_t(obj) > SpecificZones);
     return ZoneSpecifier(obj);
 }
 
-struct JS_PUBLIC_API(CompartmentOptions) {
-    ZoneSpecifier zoneSpec;
-    bool hasVersion;
-    JSVersion version;
-
-    explicit CompartmentOptions() : zoneSpec(JS::FreshZone)
-                                  , hasVersion(false)
-                                  , version(JSVERSION_UNKNOWN)
-    {}
-
-    CompartmentOptions &setZone(ZoneSpecifier spec) { zoneSpec = spec; return *this; }
-    CompartmentOptions &setVersion(JSVersion version_) { hasVersion = true; version = version_; return *this; }
-};
-
 } /* namespace JS */
 
 extern JS_PUBLIC_API(JSObject *)
 JS_NewGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals,
-                   const JS::CompartmentOptions &options = JS::CompartmentOptions());
+                   JS::ZoneSpecifier zoneSpec = JS::FreshZone);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent);
 
 /* Queries the [[Extensible]] property of the object. */
 extern JS_PUBLIC_API(JSBool)
 JS_IsExtensible(JSObject *obj);
 
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -275,16 +275,18 @@ JSContext *
 js::NewContext(JSRuntime *rt, size_t stackChunkSize)
 {
     JS_AbortIfWrongThread(rt);
 
     JSContext *cx = js_new<JSContext>(rt);
     if (!cx)
         return NULL;
 
+    JS_ASSERT(cx->findVersion() == JSVERSION_DEFAULT);
+
     if (!cx->cycleDetectorSet.init()) {
         js_delete(cx);
         return NULL;
     }
 
     /*
      * Here the GC lock is still held after js_InitContextThreadAndLockGC took it and
      * the GC is not running on another thread.
@@ -1113,16 +1115,18 @@ js_HandleExecutionInterrupt(JSContext *c
     JSBool result = JS_TRUE;
     if (cx->runtime()->interrupt)
         result = js_InvokeOperationCallback(cx) && result;
     return result;
 }
 
 JSContext::JSContext(JSRuntime *rt)
   : ContextFriendFields(rt),
+    defaultVersion(JSVERSION_DEFAULT),
+    hasVersionOverride(false),
     throwing(false),
     exception(UndefinedValue()),
     options_(0),
     reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
     resolvingList(NULL),
     generatingError(false),
     enterCompartmentDepth_(0),
     savedFrameChains_(),
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -714,19 +714,16 @@ struct JSRuntime : public JS::shadow::Ru
     size_t              numCompartments;
 
     /* Locale-specific callbacks for string conversion. */
     JSLocaleCallbacks *localeCallbacks;
 
     /* Default locale for Internationalization API */
     char *defaultLocale;
 
-    /* Default JSVersion. */
-    JSVersion defaultVersion_;
-
     /* See comment for JS_AbortIfWrongThread in jsapi.h. */
 #ifdef JS_THREADSAFE
   public:
     void *ownerThread() const { return ownerThread_; }
     void clearOwnerThread();
     void setOwnerThread();
     JS_FRIEND_API(void) abortIfWrongThread() const;
 #ifdef DEBUG
@@ -826,19 +823,16 @@ struct JSRuntime : public JS::shadow::Ru
     bool setDefaultLocale(const char *locale);
 
     /* Reset the default locale to OS defaults. */
     void resetDefaultLocale();
 
     /* Gets current default locale. String remains owned by context. */
     const char *getDefaultLocale();
 
-    JSVersion defaultVersion() { return defaultVersion_; }
-    void setDefaultVersion(JSVersion v) { defaultVersion_ = v; }
-
     /* Base address of the native stack for the current thread. */
     uintptr_t           nativeStackBase;
 
     /* The native stack size limit that runtime should not exceed. */
     size_t              nativeStackQuota;
 
     /*
      * Frames currently running in js::Interpret. See InterpreterFrames for
@@ -1534,16 +1528,21 @@ struct JSContext : js::ContextFriendFiel
 
     JSRuntime *runtime() const { return runtime_; }
     JSCompartment *compartment() const { return compartment_; }
 
     inline JS::Zone *zone() const;
     js::PerThreadData &mainThread() { return runtime()->mainThread; }
 
   private:
+    /* See JSContext::findVersion. */
+    JSVersion           defaultVersion;      /* script compilation version */
+    JSVersion           versionOverride;     /* supercedes defaultVersion when valid */
+    bool                hasVersionOverride;
+
     /* Exception state -- the exception member is a GC root by definition. */
     bool                throwing;            /* is there a pending exception? */
     js::Value           exception;           /* most-recently-thrown exception */
 
     /* Per-context options. */
     unsigned            options_;            /* see jsapi.h for JSOPTION_* */
 
   public:
@@ -1642,21 +1641,61 @@ struct JSContext : js::ContextFriendFiel
 
     /* Client opaque pointers. */
     void                *data;
     void                *data2;
 
     inline js::RegExpStatics *regExpStatics();
 
   public:
+    /*
+     * The default script compilation version can be set iff there is no code running.
+     * This typically occurs via the JSAPI right after a context is constructed.
+     */
+    inline bool canSetDefaultVersion() const;
+
+    /* Force a version for future script compilation. */
+    inline void overrideVersion(JSVersion newVersion);
+
+    /* Set the default script compilation version. */
+    void setDefaultVersion(JSVersion version) {
+        defaultVersion = version;
+    }
+
+    void clearVersionOverride() { hasVersionOverride = false; }
+    JSVersion getDefaultVersion() const { return defaultVersion; }
+    bool isVersionOverridden() const { return hasVersionOverride; }
+
+    JSVersion getVersionOverride() const {
+        JS_ASSERT(isVersionOverridden());
+        return versionOverride;
+    }
+
+    /*
+     * Set the default version if possible; otherwise, force the version.
+     * Return whether an override occurred.
+     */
+    inline bool maybeOverrideVersion(JSVersion newVersion);
+
+    /*
+     * If there is no code on the stack, turn the override version into the
+     * default version.
+     */
+    void maybeMigrateVersionOverride() {
+        JS_ASSERT(stack.empty());
+        if (JS_UNLIKELY(isVersionOverridden())) {
+            defaultVersion = versionOverride;
+            clearVersionOverride();
+        }
+    }
 
     /*
      * Return:
+     * - The override version, if there is an override version.
      * - The newest scripted frame's version, if there is such a frame.
-     * - The version from the compartment.
      * - The default version.
      *
      * Note: if this ever shows up in a profile, just add caching!
      */
     inline JSVersion findVersion() const;
 
     void setOptions(unsigned opts) {
         JS_ASSERT((opts & JSOPTION_MASK) == opts);
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -463,23 +463,48 @@ CallSetter(JSContext *cx, HandleObject o
     return CallJSPropertyOpSetter(cx, op, obj, nid, strict, vp);
 }
 
 }  /* namespace js */
 
 inline JSVersion
 JSContext::findVersion() const
 {
+    if (hasVersionOverride)
+        return versionOverride;
+
     if (JSScript *script = stack.currentScript(NULL, js::ContextStack::ALLOW_CROSS_COMPARTMENT))
         return script->getVersion();
 
-    if (compartment() && compartment()->options().hasVersion)
-        return compartment()->options().version;
+    return defaultVersion;
+}
+
+inline bool
+JSContext::canSetDefaultVersion() const
+{
+    return !stack.hasfp() && !hasVersionOverride;
+}
 
-    return runtime()->defaultVersion();
+inline void
+JSContext::overrideVersion(JSVersion newVersion)
+{
+    JS_ASSERT(!canSetDefaultVersion());
+    versionOverride = newVersion;
+    hasVersionOverride = true;
+}
+
+inline bool
+JSContext::maybeOverrideVersion(JSVersion newVersion)
+{
+    if (canSetDefaultVersion()) {
+        setDefaultVersion(newVersion);
+        return false;
+    }
+    overrideVersion(newVersion);
+    return true;
 }
 
 inline js::LifoAlloc &
 JSContext::analysisLifoAlloc()
 {
     return compartment()->analysisLifoAlloc;
 }
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -25,19 +25,18 @@
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::DebugOnly;
 
-JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options = JS::CompartmentOptions())
+JSCompartment::JSCompartment(Zone *zone)
   : zone_(zone),
-    options_(options),
     rt(zone->rt),
     principals(NULL),
     isSystem(false),
     marked(true),
     global_(NULL),
     enterCompartmentDepth(0),
     lastCodeRelease(0),
     analysisLifoAlloc(ANALYSIS_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -118,17 +118,16 @@ struct TypeInferenceSizes;
 namespace js {
 class AutoDebugModeGC;
 class DebugScopes;
 }
 
 struct JSCompartment
 {
     JS::Zone                     *zone_;
-    JS::CompartmentOptions       options_;
 
     JSRuntime                    *rt;
     JSPrincipals                 *principals;
     bool                         isSystem;
     bool                         marked;
 
     void mark() { marked = true; }
 
@@ -140,18 +139,16 @@ struct JSCompartment
     unsigned                     enterCompartmentDepth;
 
   public:
     void enter() { enterCompartmentDepth++; }
     void leave() { enterCompartmentDepth--; }
 
     JS::Zone *zone() { return zone_; }
     const JS::Zone *zone() const { return zone_; }
-    JS::CompartmentOptions &options() { return options_; }
-    const JS::CompartmentOptions &options() const { return options_; }
 
     /*
      * 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.
      *
@@ -257,17 +254,17 @@ struct JSCompartment
     js::WeakMapBase              *gcWeakMapList;
 
   private:
     enum { DebugFromC = 1, DebugFromJS = 2 };
 
     unsigned                     debugModeBits;  // see debugMode() below
 
   public:
-    JSCompartment(JS::Zone *zone, const JS::CompartmentOptions &options);
+    JSCompartment(JS::Zone *zone);
     ~JSCompartment();
 
     bool init(JSContext *cx);
 
     /* Mark cross-compartment wrappers. */
     void markCrossCompartmentWrappers(JSTracer *trc);
     void markAllCrossCompartmentWrappers(JSTracer *trc);
 
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -822,16 +822,22 @@ JS_SetDebugErrorHook(JSRuntime *rt, JSDe
 {
     rt->debugHooks.debugErrorHook = hook;
     rt->debugHooks.debugErrorHookData = closure;
     return JS_TRUE;
 }
 
 /************************************************************************/
 
+JS_FRIEND_API(void)
+js_RevertVersion(JSContext *cx)
+{
+    cx->clearVersionOverride();
+}
+
 JS_PUBLIC_API(const JSDebugHooks *)
 JS_GetGlobalDebugHooks(JSRuntime *rt)
 {
     return &rt->debugHooks;
 }
 
 /************************************************************************/
 
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -422,16 +422,19 @@ JS_SetCallHook(JSRuntime *rt, JSInterpre
 extern JS_PUBLIC_API(JSBool)
 JS_SetThrowHook(JSRuntime *rt, JSThrowHook hook, void *closure);
 
 extern JS_PUBLIC_API(JSBool)
 JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure);
 
 /************************************************************************/
 
+extern JS_FRIEND_API(void)
+js_RevertVersion(JSContext *cx);
+
 extern JS_PUBLIC_API(const JSDebugHooks *)
 JS_GetGlobalDebugHooks(JSRuntime *rt);
 
 /**
  * Add various profiling-related functions as properties of the given object.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj);
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -4694,18 +4694,17 @@ AutoPrepareForTracing::AutoPrepareForTra
   : finish(rt),
     session(rt),
     copy(rt)
 {
     RecordNativeStackTopForGC(rt);
 }
 
 JSCompartment *
-js::NewCompartment(JSContext *cx, Zone *zone, JSPrincipals *principals,
-                   const JS::CompartmentOptions &options)
+js::NewCompartment(JSContext *cx, Zone *zone, JSPrincipals *principals)
 {
     JSRuntime *rt = cx->runtime();
     JS_AbortIfWrongThread(rt);
 
     ScopedJSDeletePtr<Zone> zoneHolder;
     if (!zone) {
         zone = cx->new_<Zone>(rt);
         if (!zone)
@@ -4717,17 +4716,17 @@ js::NewCompartment(JSContext *cx, Zone *
             return NULL;
 
         zone->setGCLastBytes(8192, GC_NORMAL);
 
         JSPrincipals *trusted = rt->trustedPrincipals();
         zone->isSystem = principals && principals == trusted;
     }
 
-    ScopedJSDeletePtr<JSCompartment> compartment(cx->new_<JSCompartment>(zone, options));
+    ScopedJSDeletePtr<JSCompartment> compartment(cx->new_<JSCompartment>(zone));
     if (!compartment || !compartment->init(cx))
         return NULL;
 
     // Set up the principals.
     JS_SetCompartmentPrincipals(compartment, principals);
 
     AutoLockGC lock(rt);
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1196,18 +1196,17 @@ js_FinalizeStringRT(JSRuntime *rt, JSStr
  * Macro to test if a traversal is the marking phase of the GC.
  */
 #define IS_GC_MARKING_TRACER(trc) \
     ((trc)->callback == NULL || (trc)->callback == GCMarker::GrayCallback)
 
 namespace js {
 
 JSCompartment *
-NewCompartment(JSContext *cx, JS::Zone *zone, JSPrincipals *principals,
-               const JS::CompartmentOptions &options);
+NewCompartment(JSContext *cx, JS::Zone *zone, JSPrincipals *principals);
 
 namespace gc {
 
 /* Tries to run a GC no matter what (used for GC zeal). */
 void
 RunDebugGC(JSContext *cx);
 
 void
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -620,40 +620,47 @@ MapContextOptionNameToFlag(JSContext* cx
 }
 
 extern JSClass global_class;
 
 static JSBool
 Version(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    JSVersion origVersion = JS_GetVersion(cx);
     if (args.length() == 0 || JSVAL_IS_VOID(args[0])) {
         /* Get version. */
-        args.rval().setInt32(origVersion);
+        args.rval().setInt32(JS_GetVersion(cx));
     } else {
         /* Set version. */
         int32_t v = -1;
         if (args[0].isInt32()) {
             v = args[0].toInt32();
         } else if (args[0].isDouble()) {
             double fv = args[0].toDouble();
             if (int32_t(fv) == fv)
                 v = int32_t(fv);
         }
         if (v < 0 || v > JSVERSION_LATEST) {
             JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS, "version");
             return false;
         }
-        JS_SetVersionForCompartment(js::GetContextCompartment(cx), JSVersion(v));
-        args.rval().setInt32(origVersion);
+        args.rval().setInt32(JS_SetVersion(cx, JSVersion(v)));
     }
     return true;
 }
 
+static JSBool
+RevertVersion(JSContext *cx, unsigned argc, jsval *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    js_RevertVersion(cx);
+    args.rval().setUndefined();
+    return true;
+}
+
 static JSScript *
 GetTopScript(JSContext *cx)
 {
     RootedScript script(cx);
     JS_DescribeScriptedCaller(cx, script.address(), NULL);
     return script;
 }
 
@@ -3553,16 +3560,20 @@ GetSelfHostedValue(JSContext *cx, unsign
     return cx->runtime()->cloneSelfHostedValue(cx, srcName, args.rval());
 }
 
 static JSFunctionSpecWithHelp shell_functions[] = {
     JS_FN_HELP("version", Version, 0, 0,
 "version([number])",
 "  Get or force a script compilation version number."),
 
+    JS_FN_HELP("revertVersion", RevertVersion, 0, 0,
+"revertVersion()",
+"  Revert previously set version number."),
+
     JS_FN_HELP("options", Options, 0, 0,
 "options([option ...])",
 "  Get or toggle JavaScript options."),
 
     JS_FN_HELP("load", Load, 1, 0,
 "load(['foo.js' ...])",
 "  Load files named by string arguments. Filename is relative to the\n"
 "      current working directory."),
@@ -4758,16 +4769,17 @@ NewContext(JSRuntime *rt)
     JSShellContextData *data = NewContextData();
     if (!data) {
         DestroyContext(cx, false);
         return NULL;
     }
 
     JS_SetContextPrivate(cx, data);
     JS_SetErrorReporter(cx, my_ErrorReporter);
+    JS_SetVersion(cx, JSVERSION_LATEST);
     SetContextOptions(cx);
     if (enableTypeInference)
         JS_ToggleOptions(cx, JSOPTION_TYPE_INFERENCE);
     if (enableIon)
         JS_ToggleOptions(cx, JSOPTION_ION);
     if (enableBaseline)
         JS_ToggleOptions(cx, JSOPTION_BASELINE);
     if (enableAsmJS)
@@ -4782,20 +4794,18 @@ DestroyContext(JSContext *cx, bool withG
     JS_SetContextPrivate(cx, NULL);
     free(data);
     WITH_SIGNALS_DISABLED(withGC ? JS_DestroyContext(cx) : JS_DestroyContextNoGC(cx));
 }
 
 static JSObject *
 NewGlobalObject(JSContext *cx, JSObject *sameZoneAs)
 {
-    JS::CompartmentOptions options;
-    options.setZone(sameZoneAs ? JS::SameZoneAs(sameZoneAs) : JS::FreshZone)
-           .setVersion(JSVERSION_LATEST);
-    RootedObject glob(cx, JS_NewGlobalObject(cx, &global_class, NULL, options));
+    JS::ZoneSpecifier spec = sameZoneAs ? JS::SameZoneAs(sameZoneAs) : JS::FreshZone;
+    RootedObject glob(cx, JS_NewGlobalObject(cx, &global_class, NULL, spec));
     if (!glob)
         return NULL;
 
     {
         JSAutoCompartment ac(cx, glob);
 
 #ifndef LAZY_STANDARD_CLASSES
         if (!JS_InitStandardClasses(cx, glob))
--- a/js/src/tests/js1_8/regress/regress-384412.js
+++ b/js/src/tests/js1_8/regress/regress-384412.js
@@ -132,16 +132,29 @@ function test()
        * the iterator gets run on a string with an empty length property.
        */
       for (let i = 0; i != 0 + this.length; i++)
         yield this[i];
     });
   expect(["a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3"] + "",
          ([a + b for (a in 'abc') for (b in '123')]) + "");
 
+/*
+ * Version switching
+ */
+  if (typeof version == 'function')
+  {
+    var v = version(150);
+    f = new Function("return version(arguments[0])");
+    revertVersion();
+    expect(150, f());
+    expect(150, eval("f()"));
+    expect(0, eval("f(0); f()"));
+    revertVersion();
+  }
   print("End of Tests");
 
 /*
  * Utility functions
  */
   function expect(a, b) {
     print('expect: ' + a + ', actual: ' + b);
     reportCompare(a, b, summary);
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -828,16 +828,19 @@ ContextStack::ensureOnTop(JSContext *cx,
     return seg_->slotsBegin();
 }
 
 void
 ContextStack::popSegment()
 {
     space().seg_ = seg_->prevInMemory();
     seg_ = seg_->prevInContext();
+
+    if (!seg_)
+        cx_->maybeMigrateVersionOverride();
 }
 
 bool
 ContextStack::pushInvokeArgs(JSContext *cx, unsigned argc, InvokeArgsGuard *iag,
                              MaybeReportError report)
 {
     JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
 
--- a/js/xpconnect/idl/nsIXPConnect.idl
+++ b/js/xpconnect/idl/nsIXPConnect.idl
@@ -39,17 +39,17 @@ class nsWrapperCache;
       native JSPropertyOp(JSPropertyOp);
       native JSEqualityOp(JSEqualityOp);
 [ptr] native JSScriptPtr(JSScript);
 [ptr] native voidPtrPtr(void*);
 [ptr] native nsScriptObjectTracerPtr(nsScriptObjectTracer);
 [ref] native nsCCTraversalCallbackRef(nsCycleCollectionTraversalCallback);
 [ptr] native nsAXPCNativeCallContextPtr(nsAXPCNativeCallContext);
 [ptr] native nsWrapperCachePtr(nsWrapperCache);
-[ref] native JSCompartmentOptions(JS::CompartmentOptions);
+      native ZoneSpecifier(uintptr_t);
 [ref] native JSCallArgsRef(const JS::CallArgs);
       native JSHandleId(JS::HandleId);
 
 /***************************************************************************/
 
 // forward declarations...
 interface nsIXPCScriptable;
 interface nsIXPConnect;
@@ -286,17 +286,17 @@ interface nsIXPCFunctionThisTranslator :
 %{ C++
 // For use with the service manager
 // {CB6593E0-F9B2-11d2-BDD6-000064657374}
 #define NS_XPCONNECT_CID \
 { 0xcb6593e0, 0xf9b2, 0x11d2, \
     { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
 %}
 
-[uuid(bd61342d-8a88-4f23-8d2d-1782fff02d26)]
+[uuid(2950bc62-ba03-4465-9685-a0eec9e188c2)]
 interface nsIXPConnect : nsISupports
 {
 %{ C++
   NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCONNECT_CID)
 %}
 
     /**
      * Initializes classes on a global object that has already been created.
@@ -313,25 +313,24 @@ interface nsIXPConnect : nsISupports
      * classes when asked by the JS engine.
      *
      * @param aJSContext the context to use while creating the global object.
      * @param aCOMObj the native object that represents the global object.
      * @param aPrincipal the principal of the code that will run in this
      *                   compartment. Can be null if not on the main thread.
      * @param aFlags one of the flags below specifying what options this
      *               global object wants.
-     * @param aOptions JSAPI-specific options for the new compartment.
      */
     nsIXPConnectJSObjectHolder
     initClassesWithNewWrappedGlobal(
-                  in JSContextPtr         aJSContext,
-                  in nsISupports          aCOMObj,
-                  in nsIPrincipal         aPrincipal,
-                  in uint32_t             aFlags,
-                  in JSCompartmentOptions aOptions);
+                  in JSContextPtr aJSContext,
+                  in nsISupports  aCOMObj,
+                  in nsIPrincipal aPrincipal,
+                  in uint32_t     aFlags,
+                  in ZoneSpecifier aZoneSpec);
 
     const uint32_t INIT_JS_STANDARD_CLASSES  = 1 << 0;
     // Free bit here!
     const uint32_t OMIT_COMPONENTS_OBJECT    = 1 << 2;
 
     /**
     * wrapNative will create a new JSObject or return an existing one.
     *
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -455,16 +455,19 @@ mozJSComponentLoader::ReallyInit()
         NS_FAILED(rv = mRuntimeService->GetRuntime(&mRuntime)))
         return rv;
 
     // Create our compilation context.
     mContext = JS_NewContext(mRuntime, 256);
     if (!mContext)
         return NS_ERROR_OUT_OF_MEMORY;
 
+    // Always use the latest js version
+    JS_SetVersion(mContext, JSVERSION_LATEST);
+
     nsCOMPtr<nsIScriptSecurityManager> secman =
         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
     if (!secman)
         return NS_ERROR_FAILURE;
 
     rv = secman->GetSystemPrincipal(getter_AddRefs(mSystemPrincipal));
     if (NS_FAILED(rv) || !mSystemPrincipal)
         return NS_ERROR_FAILURE;
@@ -718,24 +721,21 @@ mozJSComponentLoader::PrepareObjectForLo
         do_GetService(kXPConnectServiceContractID, &rv);
     NS_ENSURE_SUCCESS(rv, nullptr);
 
     if (!mLoaderGlobal) {
         nsRefPtr<BackstagePass> backstagePass;
         rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
         NS_ENSURE_SUCCESS(rv, nullptr);
 
-        JS::CompartmentOptions options;
-        options.setZone(JS::SystemZone)
-               .setVersion(JSVERSION_LATEST);
         rv = xpc->InitClassesWithNewWrappedGlobal(aCx,
                                                   static_cast<nsIGlobalObject *>(backstagePass),
                                                   mSystemPrincipal,
                                                   0,
-                                                  options,
+                                                  JS::SystemZone,
                                                   getter_AddRefs(holder));
         NS_ENSURE_SUCCESS(rv, nullptr);
 
         RootedObject global(aCx, holder->GetJSObject());
         NS_ENSURE_TRUE(global, nullptr);
 
         backstagePass->SetGlobalObject(global);
 
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -484,21 +484,20 @@ Load(JSContext *cx, unsigned argc, jsval
     }
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
 static JSBool
 Version(JSContext *cx, unsigned argc, jsval *vp)
 {
-    JSVersion origVersion = JS_GetVersion(cx);
-    JS_SET_RVAL(cx, vp, INT_TO_JSVAL(origVersion));
     if (argc > 0 && JSVAL_IS_INT(JS_ARGV(cx, vp)[0]))
-        JS_SetVersionForCompartment(js::GetContextCompartment(cx),
-                                    JSVersion(JSVAL_TO_INT(JS_ARGV(cx, vp)[0])));
+        JS_SET_RVAL(cx, vp, INT_TO_JSVAL(JS_SetVersion(cx, JSVersion(JSVAL_TO_INT(JS_ARGV(cx, vp)[0])))));
+    else
+        JS_SET_RVAL(cx, vp, INT_TO_JSVAL(JS_GetVersion(cx)));
     return true;
 }
 
 static JSBool
 BuildDate(JSContext *cx, unsigned argc, jsval *vp)
 {
     fprintf(gOutFile, "built on %s at %s\n", __DATE__, __TIME__);
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
@@ -1232,18 +1231,17 @@ ProcessArgs(JSContext *cx, JS::Handle<JS
             isInteractive = false;
             break;
         }
         switch (argv[i][1]) {
         case 'v':
             if (++i == argc) {
                 return usage();
             }
-            JS_SetVersionForCompartment(js::GetContextCompartment(cx),
-                                        JSVersion(atoi(argv[i])));
+            JS_SetVersion(cx, JSVersion(atoi(argv[i])));
             break;
         case 'W':
             reportWarnings = false;
             break;
         case 'w':
             reportWarnings = true;
             break;
         case 'x':
@@ -1397,16 +1395,17 @@ static JSContextCallback gOldJSContextCa
 static JSBool
 ContextCallback(JSContext *cx, unsigned contextOp)
 {
     if (gOldJSContextCallback && !gOldJSContextCallback(cx, contextOp))
         return false;
 
     if (contextOp == JSCONTEXT_NEW) {
         JS_SetErrorReporter(cx, my_ErrorReporter);
+        JS_SetVersion(cx, JSVERSION_LATEST);
     }
     return true;
 }
 
 static bool
 GetCurrentWorkingDirectory(nsAString& workingDirectory)
 {
 #if !defined(XP_WIN) && !defined(XP_UNIX)
@@ -1630,25 +1629,22 @@ main(int argc, char **argv, char **envp)
         nsRefPtr<BackstagePass> backstagePass;
         rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
         if (NS_FAILED(rv)) {
             fprintf(gErrFile, "+++ Failed to create BackstagePass: %8x\n",
                     static_cast<uint32_t>(rv));
             return 1;
         }
 
-        JS::CompartmentOptions options;
-        options.setZone(JS::SystemZone)
-               .setVersion(JSVERSION_LATEST);
         nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
         rv = xpc->InitClassesWithNewWrappedGlobal(cx,
                                                   static_cast<nsIGlobalObject *>(backstagePass),
                                                   systemprincipal,
                                                   0,
-                                                  options,
+                                                  JS::SystemZone,
                                                   getter_AddRefs(holder));
         if (NS_FAILED(rv))
             return 1;
 
         {
             JS::Rooted<JSObject*> glob(cx, holder->GetJSObject());
             if (!glob) {
                 return 1;
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3274,22 +3274,20 @@ xpc_CreateSandboxObject(JSContext *cx, j
                 }
 
                 return rv;
             }
         }
         MOZ_ASSERT(principal);
     }
 
-    JS::CompartmentOptions compartmentOptions;
-    compartmentOptions.setZone(options.sameZoneAs
+    JS::ZoneSpecifier zoneSpec = options.sameZoneAs
                                  ? JS::SameZoneAs(js::UncheckedUnwrap(options.sameZoneAs))
-                                 : JS::SystemZone);
-    RootedObject sandbox(cx, xpc::CreateGlobalObject(cx, &SandboxClass,
-                                                     principal, compartmentOptions));
+                                 : JS::SystemZone;
+    RootedObject sandbox(cx, xpc::CreateGlobalObject(cx, &SandboxClass, principal, zoneSpec));
     if (!sandbox)
         return NS_ERROR_FAILURE;
 
     // Set up the wantXrays flag, which indicates whether xrays are desired even
     // for same-origin access.
     //
     // This flag has historically been ignored for chrome sandboxes due to
     // quirks in the wrapping implementation that have now been removed. Indeed,
@@ -3817,23 +3815,16 @@ nsXPCComponents_Utils::EvalInSandbox(con
         if (!jsVersionStr)
             return NS_ERROR_INVALID_ARG;
 
         JSAutoByteString bytes(cx, jsVersionStr);
         if (!bytes)
             return NS_ERROR_INVALID_ARG;
 
         jsVersion = JS_StringToVersion(bytes.ptr());
-        // Explicitly check for "latest", which we support for sandboxes but
-        // isn't in the set of web-exposed version strings.
-        if (jsVersion == JSVERSION_UNKNOWN &&
-            !strcmp(bytes.ptr(), "latest"))
-        {
-            jsVersion = JSVERSION_LATEST;
-        }
         if (jsVersion == JSVERSION_UNKNOWN)
             return NS_ERROR_INVALID_ARG;
     }
 
     // Optional fourth and fifth arguments: filename and line number.
     nsXPIDLCString filename;
     int32_t lineNo = (optionalArgc >= 3) ? lineNumber : 0;
     if (optionalArgc >= 2) {
@@ -3908,21 +3899,22 @@ xpc_EvalInSandbox(JSContext *cx, HandleO
         if (!sandcx) {
             JS_ReportError(cx, "Can't prepare context for evalInSandbox");
             return NS_ERROR_OUT_OF_MEMORY;
         }
         nsCxPusher pusher;
         pusher.Push(sandcx);
         JSAutoCompartment ac(sandcx, sandbox);
 
+        if (jsVersion != JSVERSION_DEFAULT)
+            JS_SetVersion(sandcx, jsVersion);
+
         JS::CompileOptions options(sandcx);
         options.setPrincipals(nsJSPrincipals::get(prin))
                .setFileAndLine(filename, lineNo);
-        if (jsVersion != JSVERSION_DEFAULT)
-               options.setVersion(jsVersion);
         JS::RootedObject rootedSandbox(sandcx, sandbox);
         ok = JS::Evaluate(sandcx, rootedSandbox, options,
                           PromiseFlatString(source).get(), source.Length(),
                           v.address());
         if (ok && returnStringOnly && !v.isUndefined()) {
             JSString *str = JS_ValueToString(sandcx, v);
             ok = !!str;
             v = ok ? JS::StringValue(str) : JS::UndefinedValue();
--- a/js/xpconnect/src/XPCJSContextStack.cpp
+++ b/js/xpconnect/src/XPCJSContextStack.cpp
@@ -162,19 +162,17 @@ XPCJSContextStack::GetSafeJSContext()
 
     JS::RootedObject glob(mSafeJSContext);
     {
         // scoped JS Request
         JSAutoRequest req(mSafeJSContext);
 
         JS_SetErrorReporter(mSafeJSContext, mozJSLoaderErrorReporter);
 
-        JS::CompartmentOptions options;
-        options.setZone(JS::SystemZone);
-        glob = xpc::CreateGlobalObject(mSafeJSContext, &global_class, principal, options);
+        glob = xpc::CreateGlobalObject(mSafeJSContext, &global_class, principal, JS::SystemZone);
 
         if (glob) {
             // Make sure the context is associated with a proper compartment
             // and not the default compartment.
             JS_SetGlobalObject(mSafeJSContext, glob);
 
             // Note: make sure to set the private before calling
             // InitClasses
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -280,17 +280,17 @@ FinishCreate(XPCWrappedNativeScope* Scop
 // XPCConvert::NativeInterface2JSObject, XPCWrappedNative::GetNewOrUsed,
 // and finally into XPCWrappedNative::Init. Unfortunately, this path assumes
 // very early on that we have an XPCWrappedNativeScope and corresponding global
 // JS object, which are the very things we need to create here. So we special-
 // case the logic and do some things in a different order.
 nsresult
 XPCWrappedNative::WrapNewGlobal(xpcObjectHelper &nativeHelper,
                                 nsIPrincipal *principal, bool initStandardClasses,
-                                JS::CompartmentOptions& aOptions,
+                                ZoneSpecifier zoneSpec,
                                 XPCWrappedNative **wrappedGlobal)
 {
     AutoJSContext cx;
     nsISupports *identity = nativeHelper.GetCanonical();
 
     // The object should specify that it's meant to be global.
     MOZ_ASSERT(nativeHelper.GetScriptableFlags() & nsIXPCScriptable::IS_GLOBAL_OBJECT);
 
@@ -310,17 +310,17 @@ XPCWrappedNative::WrapNewGlobal(xpcObjec
     AutoMarkingNativeScriptableInfoPtr si(cx, XPCNativeScriptableInfo::Construct(&sciWrapper));
     MOZ_ASSERT(si.get());
 
     // Finally, we get to the JSClass.
     JSClass *clasp = si->GetJSClass();
     MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
 
     // Create the global.
-    RootedObject global(cx, xpc::CreateGlobalObject(cx, clasp, principal, aOptions));
+    RootedObject global(cx, xpc::CreateGlobalObject(cx, clasp, principal, zoneSpec));
     if (!global)
         return NS_ERROR_FAILURE;
     XPCWrappedNativeScope *scope = GetCompartmentPrivate(global)->scope;
 
     // Immediately enter the global's compartment, so that everything else we
     // create ends up there.
     JSAutoCompartment ac(cx, global);
 
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -976,27 +976,27 @@ CheckTypeInference(JSContext *cx, JSClas
 #else
 #define CheckTypeInference(cx, clasp, principal) {}
 #endif
 
 namespace xpc {
 
 JSObject*
 CreateGlobalObject(JSContext *cx, JSClass *clasp, nsIPrincipal *principal,
-                   JS::CompartmentOptions& aOptions)
+                   JS::ZoneSpecifier zoneSpec)
 {
     // Make sure that Type Inference is enabled for everything non-chrome.
     // Sandboxes and compilation scopes are exceptions. See bug 744034.
     CheckTypeInference(cx, clasp, principal);
 
     NS_ABORT_IF_FALSE(NS_IsMainThread(), "using a principal off the main thread?");
     MOZ_ASSERT(principal);
 
     RootedObject global(cx,
-                        JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal), aOptions));
+                        JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal), zoneSpec));
     if (!global)
         return nullptr;
     JSAutoCompartment ac(cx, global);
     // The constructor automatically attaches the scope to the compartment private
     // of |global|.
     (void) new XPCWrappedNativeScope(cx, global);
 
 #ifdef DEBUG
@@ -1022,17 +1022,17 @@ CreateGlobalObject(JSContext *cx, JSClas
 
 } // namespace xpc
 
 NS_IMETHODIMP
 nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
                                              nsISupports *aCOMObj,
                                              nsIPrincipal * aPrincipal,
                                              uint32_t aFlags,
-                                             JS::CompartmentOptions& aOptions,
+                                             JS::ZoneSpecifier zoneSpec,
                                              nsIXPConnectJSObjectHolder **_retval)
 {
     NS_ASSERTION(aJSContext, "bad param");
     NS_ASSERTION(aCOMObj, "bad param");
     NS_ASSERTION(_retval, "bad param");
 
     // We pass null for the 'extra' pointer during global object creation, so
     // we need to have a principal.
@@ -1041,17 +1041,18 @@ nsXPConnect::InitClassesWithNewWrappedGl
     // Call into XPCWrappedNative to make a new global object, scope, and global
     // prototype.
     xpcObjectHelper helper(aCOMObj);
     MOZ_ASSERT(helper.GetScriptableFlags() & nsIXPCScriptable::IS_GLOBAL_OBJECT);
     nsRefPtr<XPCWrappedNative> wrappedGlobal;
     nsresult rv =
         XPCWrappedNative::WrapNewGlobal(helper, aPrincipal,
                                         aFlags & nsIXPConnect::INIT_JS_STANDARD_CLASSES,
-                                        aOptions, getter_AddRefs(wrappedGlobal));
+                                        zoneSpec,
+                                        getter_AddRefs(wrappedGlobal));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Grab a copy of the global and enter its compartment.
     RootedObject global(aJSContext, wrappedGlobal->GetFlatJSObject());
     MOZ_ASSERT(!js::GetObjectParent(global));
     JSAutoCompartment ac(aJSContext, global);
 
     if (!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2466,17 +2466,17 @@ public:
 
     XPCJSRuntime*
     GetRuntime() const {XPCWrappedNativeScope* scope = GetScope();
                         return scope ? scope->GetRuntime() : nullptr;}
 
     static nsresult
     WrapNewGlobal(xpcObjectHelper &nativeHelper,
                   nsIPrincipal *principal, bool initStandardClasses,
-                  JS::CompartmentOptions& aOptions,
+                  JS::ZoneSpecifier zoneSpec,
                   XPCWrappedNative **wrappedGlobal);
 
     static nsresult
     GetNewOrUsed(xpcObjectHelper& helper,
                  XPCWrappedNativeScope* Scope,
                  XPCNativeInterface* Interface,
                  XPCWrappedNative** wrapper);
 
@@ -3791,17 +3791,17 @@ struct SandboxOptions {
     bool wantXHRConstructor;
     JS::RootedObject proto;
     nsCString sandboxName;
     JS::RootedObject sameZoneAs;
 };
 
 JSObject *
 CreateGlobalObject(JSContext *cx, JSClass *clasp, nsIPrincipal *principal,
-                   JS::CompartmentOptions& aOptions);
+                   JS::ZoneSpecifier zoneSpec);
 }
 
 // Helper for creating a sandbox object to use for evaluating
 // untrusted code completely separated from all other code in the
 // system using xpc_EvalInSandbox(). Takes the JSContext on which to
 // do setup etc on, puts the sandbox object in *vp (which must be
 // rooted by the caller), and uses the principal that's either
 // directly passed in prinOrSop or indirectly as an
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/bug596580_versioned.js
@@ -0,0 +1,3 @@
+/* Some constructs that require a high default version number. */
+let x = 12;
+function simpleGen() { yield 12; }
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_bug596580.js
@@ -0,0 +1,19 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+function run_test() {
+  var file = do_get_file("bug596580_versioned.js");
+  var ios = Cc["@mozilla.org/network/io-service;1"]
+              .getService(Ci.nsIIOService);
+  var uri = ios.newFileURI(file);
+  var scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
+                       .getService(Ci.mozIJSSubScriptLoader);
+  scriptLoader.loadSubScript(uri.spec);
+  version(150)
+  try {
+      scriptLoader.loadSubScript(uri.spec);
+      throw new Error("Subscript should fail to load.");
+  } catch (e if e instanceof SyntaxError) {
+      // Okay.
+  }
+}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -1,15 +1,16 @@
 [DEFAULT]
 head = 
 tail = 
 
 [test_bogus_files.js]
 [test_bug408412.js]
 [test_bug451678.js]
+[test_bug596580.js]
 [test_bug604362.js]
 [test_bug641378.js]
 [test_bug677864.js]
 [test_bug711404.js]
 [test_bug778409.js]
 [test_bug780370.js]
 [test_bug805807.js]
 [test_bug809652.js]
--- a/netwerk/base/src/ProxyAutoConfig.cpp
+++ b/netwerk/base/src/ProxyAutoConfig.cpp
@@ -531,25 +531,23 @@ private:
      */ 
     JS_SetNativeStackQuota(mRuntime, 128 * sizeof(size_t) * 1024); 
 
     mContext = JS_NewContext(mRuntime, 0);
     NS_ENSURE_TRUE(mContext, NS_ERROR_OUT_OF_MEMORY);
 
     JSAutoRequest ar(mContext);
 
-    JS::CompartmentOptions options;
-    options.setZone(JS::SystemZone)
-           .setVersion(JSVERSION_LATEST);
-    mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr, options);
+    mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr, JS::SystemZone);
     NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY);
 
     JS_SetGlobalObject(mContext, mGlobal);
     JS_InitStandardClasses(mContext, mGlobal);
 
+    JS_SetVersion(mContext, JSVERSION_LATEST);
     JS_SetErrorReporter(mContext, PACErrorReporter);
 
     if (!JS_DefineFunctions(mContext, mGlobal, PACGlobalFunctions))
       return NS_ERROR_FAILURE;
 
     return NS_OK;
   }
 };
--- a/netwerk/test/httpserver/httpd.js
+++ b/netwerk/test/httpserver/httpd.js
@@ -2722,17 +2722,17 @@ ServerHandler.prototype =
         try
         {
           // Alas, the line number in errors dumped to console when calling the
           // request handler is simply an offset from where we load the SJS file.
           // Work around this in a reasonably non-fragile way by dynamically
           // getting the line number where we evaluate the SJS file.  Don't
           // separate these two lines!
           var line = new Error().lineNumber;
-          Cu.evalInSandbox(sis.read(file.fileSize), s, "latest");
+          Cu.evalInSandbox(sis.read(file.fileSize), s);
         }
         catch (e)
         {
           dumpn("*** syntax error in SJS at " + file.path + ": " + e);
           throw HTTP_500;
         }
 
         try