Bug 1529758 - Add a pref for fields. r=tcampbell
authorJason Orendorff <jorendorff@mozilla.com>
Tue, 12 Mar 2019 19:14:57 +0000
changeset 521596 7a1ad6647c22
parent 521595 15affcdf9d0d
child 521597 3a1ed20749c5
push id10867
push userdvarga@mozilla.com
push dateThu, 14 Mar 2019 15:20:45 +0000
treeherdermozilla-beta@abad13547875 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1529758
milestone67.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 1529758 - Add a pref for fields. r=tcampbell This creates a shell command-line option, `--enable-experimental-fields`, and a Gecko pref, `javascript.options.experimental.fields`. Both are off by default everywhere, for now. Differential Revision: https://phabricator.services.mozilla.com/D22045
js/public/CompileOptions.h
js/src/frontend/Parser.cpp
js/src/frontend/TokenStream.cpp
js/src/fuzz-tests/tests.cpp
js/src/jsapi-tests/tests.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/shell/js.cpp
js/xpconnect/src/XPCJSContext.cpp
modules/libpref/init/StaticPrefList.h
modules/libpref/init/all.js
--- a/js/public/CompileOptions.h
+++ b/js/public/CompileOptions.h
@@ -112,16 +112,17 @@ class JS_PUBLIC_API TransitiveCompileOpt
   AsmJSOption asmJSOption = AsmJSOption::Disabled;
   bool throwOnAsmJSValidationFailureOption = false;
   bool forceAsync = false;
   bool sourceIsLazy = false;
   bool allowHTMLComments = true;
   bool isProbablySystemCode = false;
   bool hideScriptFromDebugger = false;
   bool bigIntEnabledOption = false;
+  bool fieldsEnabledOption = false;
 
   /**
    * |introductionType| is a statically allocated C string: one of "eval",
    * "Function", or "GeneratorFunction".
    */
   const char* introductionType = nullptr;
 
   unsigned introductionLineno = 0;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6774,21 +6774,20 @@ bool GeneralParser<ParseHandler, Unit>::
   Node propName = propertyName(yieldHandling, PropertyNameInClass,
                                /* maybeDecl = */ Nothing(), classMembers,
                                &propType, &propAtom);
   if (!propName) {
     return false;
   }
 
   if (propType == PropertyType::Field) {
-    // TODO(khyperia): Delete the two lines below once fields are fully
-    // supported in the backend. We can't fail in BytecodeCompiler because of
-    // lazy parsing.
-    errorAt(propNameOffset, JSMSG_FIELDS_NOT_SUPPORTED);
-    return false;
+    if (!options().fieldsEnabledOption) {
+      errorAt(propNameOffset, JSMSG_FIELDS_NOT_SUPPORTED);
+      return false;
+    }
 
     if (isStatic) {
       errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
       return false;
     }
     if (!tokenStream.getToken(&tt)) {
       return false;
     }
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -1989,19 +1989,20 @@ MOZ_MUST_USE bool TokenStreamSpecific<Un
   }
 
   noteBadToken.release();
   if (visibility == NameVisibility::Private) {
     MOZ_ASSERT(identStart[0] == static_cast<Unit>('#'),
                "Private identifier starts with #");
     newPrivateNameToken(atom->asPropertyName(), start, modifier, out);
 
-    // TODO(khypera): Delete the below once private names are supported.
-    errorAt(start.offset(), JSMSG_FIELDS_NOT_SUPPORTED);
-    return false;
+    if (!anyCharsAccess().options().fieldsEnabledOption) {
+      errorAt(start.offset(), JSMSG_FIELDS_NOT_SUPPORTED);
+      return false;
+    }
   } else {
     newNameToken(atom->asPropertyName(), start, modifier, out);
   }
   return true;
 }
 
 enum FirstCharKind {
   // A char16_t has the 'OneChar' kind if it, by itself, constitutes a valid
--- a/js/src/fuzz-tests/tests.cpp
+++ b/js/src/fuzz-tests/tests.cpp
@@ -37,18 +37,20 @@ static const JSClass* getGlobalClass() {
   static const JSClass c = {"global", JSCLASS_GLOBAL_FLAGS, &cOps};
   return &c;
 }
 
 static JSObject* jsfuzz_createGlobal(JSContext* cx, JSPrincipals* principals) {
   /* Create the global object. */
   JS::RootedObject newGlobal(cx);
   JS::RealmOptions options;
-  options.creationOptions().setStreamsEnabled(true);
-  options.creationOptions().setBigIntEnabled(true);
+  options.creationOptions()
+      .setStreamsEnabled(true)
+      .setBigIntEnabled(true)
+      .setFieldsEnabled(false);
   newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), principals,
                                  JS::FireOnNewGlobalHook, options);
   if (!newGlobal) {
     return nullptr;
   }
 
   JSAutoRealm ar(cx, newGlobal);
 
--- a/js/src/jsapi-tests/tests.cpp
+++ b/js/src/jsapi-tests/tests.cpp
@@ -74,18 +74,20 @@ bool JSAPITest::evaluate(const char* utf
 bool JSAPITest::definePrint() {
   return JS_DefineFunction(cx, global, "print", (JSNative)print, 0, 0);
 }
 
 JSObject* JSAPITest::createGlobal(JSPrincipals* principals) {
   /* Create the global object. */
   JS::RootedObject newGlobal(cx);
   JS::RealmOptions options;
-  options.creationOptions().setStreamsEnabled(true);
-  options.creationOptions().setBigIntEnabled(true);
+  options.creationOptions()
+      .setStreamsEnabled(true)
+      .setBigIntEnabled(true)
+      .setFieldsEnabled(true);
   newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), principals,
                                  JS::FireOnNewGlobalHook, options);
   if (!newGlobal) {
     return nullptr;
   }
 
   JSAutoRealm ar(cx, newGlobal);
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3420,16 +3420,17 @@ void JS::TransitiveCompileOptions::copyP
   sourceIsLazy = rhs.sourceIsLazy;
   introductionType = rhs.introductionType;
   introductionLineno = rhs.introductionLineno;
   introductionOffset = rhs.introductionOffset;
   hasIntroductionInfo = rhs.hasIntroductionInfo;
   isProbablySystemCode = rhs.isProbablySystemCode;
   hideScriptFromDebugger = rhs.hideScriptFromDebugger;
   bigIntEnabledOption = rhs.bigIntEnabledOption;
+  fieldsEnabledOption = rhs.fieldsEnabledOption;
 };
 
 void JS::ReadOnlyCompileOptions::copyPODOptions(
     const ReadOnlyCompileOptions& rhs) {
   copyPODTransitiveOptions(rhs);
   lineno = rhs.lineno;
   column = rhs.column;
   scriptSourceOffset = rhs.scriptSourceOffset;
@@ -3547,16 +3548,17 @@ JS::CompileOptions::CompileOptions(JSCon
   } else if (cx->realm()->debuggerObservesAsmJS()) {
     asmJSOption = AsmJSOption::DisabledByDebugger;
   } else {
     asmJSOption = AsmJSOption::Enabled;
   }
   throwOnAsmJSValidationFailureOption =
       cx->options().throwOnAsmJSValidationFailure();
   bigIntEnabledOption = cx->realm()->creationOptions().getBigIntEnabled();
+  fieldsEnabledOption = cx->realm()->creationOptions().getFieldsEnabled();
 }
 
 CompileOptions& CompileOptions::setIntroductionInfoToCaller(
     JSContext* cx, const char* introductionType) {
   RootedScript maybeScript(cx);
   const char* filename;
   unsigned lineno;
   uint32_t pcOffset;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -959,16 +959,17 @@ class JS_PUBLIC_API RealmCreationOptions
         comp_(nullptr),
         invisibleToDebugger_(false),
         mergeable_(false),
         preserveJitCode_(false),
         cloneSingletons_(false),
         sharedMemoryAndAtomics_(false),
         streams_(false),
         bigint_(false),
+        fields_(false),
         secureContext_(false),
         clampAndJitterTime_(true) {}
 
   JSTraceOp getTrace() const { return traceGlobal_; }
   RealmCreationOptions& setTrace(JSTraceOp op) {
     traceGlobal_ = op;
     return *this;
   }
@@ -1040,16 +1041,22 @@ class JS_PUBLIC_API RealmCreationOptions
   }
 
   bool getBigIntEnabled() const { return bigint_; }
   RealmCreationOptions& setBigIntEnabled(bool flag) {
     bigint_ = flag;
     return *this;
   }
 
+  bool getFieldsEnabled() const { return fields_; }
+  RealmCreationOptions& setFieldsEnabled(bool flag) {
+    fields_ = flag;
+    return *this;
+  }
+
   // This flag doesn't affect JS engine behavior.  It is used by Gecko to
   // mark whether content windows and workers are "Secure Context"s. See
   // https://w3c.github.io/webappsec-secure-contexts/
   // https://bugzilla.mozilla.org/show_bug.cgi?id=1162772#c34
   bool secureContext() const { return secureContext_; }
   RealmCreationOptions& setSecureContext(bool flag) {
     secureContext_ = flag;
     return *this;
@@ -1070,16 +1077,17 @@ class JS_PUBLIC_API RealmCreationOptions
   };
   bool invisibleToDebugger_;
   bool mergeable_;
   bool preserveJitCode_;
   bool cloneSingletons_;
   bool sharedMemoryAndAtomics_;
   bool streams_;
   bool bigint_;
+  bool fields_;
   bool secureContext_;
   bool clampAndJitterTime_;
 };
 
 /**
  * RealmBehaviors specifies behaviors of a realm that can be changed after the
  * realm's been created.
  */
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -498,16 +498,17 @@ static bool enableWasmCranelift = false;
 #ifdef ENABLE_WASM_GC
 static bool enableWasmGc = false;
 #endif
 static bool enableWasmVerbose = false;
 static bool enableTestWasmAwaitTier2 = false;
 static bool enableAsyncStacks = false;
 static bool enableStreams = false;
 static bool enableBigInt = false;
+static bool enableFields = false;
 #ifdef JS_GC_ZEAL
 static uint32_t gZealBits = 0;
 static uint32_t gZealFrequency = 0;
 #endif
 static bool printTiming = false;
 static RCFile* gErrFile = nullptr;
 static RCFile* gOutFile = nullptr;
 static bool reportWarnings = true;
@@ -3758,17 +3759,18 @@ static const JSClassOps sandbox_classOps
 
 static const JSClass sandbox_class = {"sandbox", JSCLASS_GLOBAL_FLAGS,
                                       &sandbox_classOps};
 
 static void SetStandardRealmOptions(JS::RealmOptions& options) {
   options.creationOptions()
       .setSharedMemoryAndAtomicsEnabled(enableSharedMemory)
       .setBigIntEnabled(enableBigInt)
-      .setStreamsEnabled(enableStreams);
+      .setStreamsEnabled(enableStreams)
+      .setFieldsEnabled(enableFields);
 }
 
 static MOZ_MUST_USE bool CheckRealmOptions(JSContext* cx,
                                            JS::RealmOptions& options,
                                            JSPrincipals* principals) {
   JS::RealmCreationOptions& creationOptions = options.creationOptions();
   if (creationOptions.compartmentSpecifier() !=
       JS::CompartmentSpecifier::ExistingCompartment) {
@@ -10181,16 +10183,17 @@ static bool SetContextOptions(JSContext*
 #ifdef ENABLE_WASM_GC
   enableWasmGc = op.getBoolOption("wasm-gc");
 #endif
   enableWasmVerbose = op.getBoolOption("wasm-verbose");
   enableTestWasmAwaitTier2 = op.getBoolOption("test-wasm-await-tier2");
   enableAsyncStacks = !op.getBoolOption("no-async-stacks");
   enableStreams = !op.getBoolOption("no-streams");
   enableBigInt = !op.getBoolOption("no-bigint");
+  enableFields = op.getBoolOption("enable-experimental-fields");
 
   JS::ContextOptionsRef(cx)
       .setBaseline(enableBaseline)
       .setIon(enableIon)
       .setAsmJS(enableAsmJS)
       .setWasm(enableWasm)
       .setWasmBaseline(enableWasmBaseline)
       .setWasmIon(enableWasmIon)
@@ -10892,18 +10895,18 @@ int main(int argc, char** argv, char** e
 #endif
       || !op.addBoolOption('\0', "no-native-regexp",
                            "Disable native regexp compilation") ||
       !op.addBoolOption('\0', "no-unboxed-objects",
                         "Disable creating unboxed plain objects") ||
       !op.addBoolOption('\0', "enable-streams",
                         "Enable WHATWG Streams (default)") ||
       !op.addBoolOption('\0', "no-streams", "Disable WHATWG Streams") ||
-      !op.addBoolOption('\0', "no-bigint",
-                        "Disable experimental BigInt support") ||
+      !op.addBoolOption('\0', "no-bigint", "Disable BigInt support") ||
+      !op.addBoolOption('\0', "enable-experimental-fields", "Enable fields in classes") ||
       !op.addStringOption('\0', "shared-memory", "on/off",
                           "SharedArrayBuffer and Atomics "
 #if SHARED_MEMORY_DEFAULT
                           "(default: on, off to disable)"
 #else
                           "(default: off, on to enable)"
 #endif
                           ) ||
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -755,22 +755,24 @@ static mozilla::Atomic<bool> sExtraWarni
 bool xpc::ExtraWarningsForSystemJS() { return sExtraWarningsForSystemJS; }
 #else
 bool xpc::ExtraWarningsForSystemJS() { return false; }
 #endif
 
 static mozilla::Atomic<bool> sSharedMemoryEnabled(false);
 static mozilla::Atomic<bool> sStreamsEnabled(false);
 static mozilla::Atomic<bool> sBigIntEnabled(false);
+static mozilla::Atomic<bool> sFieldsEnabled(false);
 
 void xpc::SetPrefableRealmOptions(JS::RealmOptions& options) {
   options.creationOptions()
       .setSharedMemoryAndAtomicsEnabled(sSharedMemoryEnabled)
       .setBigIntEnabled(sBigIntEnabled)
-      .setStreamsEnabled(sStreamsEnabled);
+      .setStreamsEnabled(sStreamsEnabled)
+      .setFieldsEnabled(sFieldsEnabled);
 }
 
 static void ReloadPrefsCallback(const char* pref, XPCJSContext* xpccx) {
   JSContext* cx = xpccx->Context();
 
   bool useBaseline = Preferences::GetBool(JS_OPTIONS_DOT_STR "baselinejit");
   bool useIon = Preferences::GetBool(JS_OPTIONS_DOT_STR "ion");
   bool useAsmJS = Preferences::GetBool(JS_OPTIONS_DOT_STR "asmjs");
@@ -842,16 +844,17 @@ static void ReloadPrefsCallback(const ch
       Preferences::GetBool(JS_OPTIONS_DOT_STR "spectre.jit_to_C++_calls");
 
   bool unboxedObjects =
       Preferences::GetBool(JS_OPTIONS_DOT_STR "unboxed_objects");
 
   sSharedMemoryEnabled =
       Preferences::GetBool(JS_OPTIONS_DOT_STR "shared_memory");
   sStreamsEnabled = Preferences::GetBool(JS_OPTIONS_DOT_STR "streams");
+  sFieldsEnabled = Preferences::GetBool(JS_OPTIONS_DOT_STR "experimental.fields");
 
 #ifdef DEBUG
   sExtraWarningsForSystemJS =
       Preferences::GetBool(JS_OPTIONS_DOT_STR "strict.debug");
 #endif
 
 #ifdef JS_GC_ZEAL
   int32_t zeal = Preferences::GetInt(JS_OPTIONS_DOT_STR "gczeal", -1);
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -1108,16 +1108,22 @@ VARCACHE_PREF(
 
 // BigInt API
 VARCACHE_PREF(
   "javascript.options.bigint",
    javascript_options_bigint,
   RelaxedAtomicBool, false
 )
 
+VARCACHE_PREF(
+  "javascript.options.experimental.fields",
+   javascript_options_experimental_fields,
+  RelaxedAtomicBool, false
+)
+
 
 //---------------------------------------------------------------------------
 // Media prefs
 //---------------------------------------------------------------------------
 
 // These prefs use camel case instead of snake case for the getter because one
 // reviewer had an unshakeable preference for that.
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1598,16 +1598,18 @@ pref("javascript.options.spectre.jit_to_
 #endif
 
 // Streams API
 pref("javascript.options.streams", true);
 
 // BigInt API
 pref("javascript.options.bigint", false);
 
+pref("javascript.options.experimental.fields", false);
+
 // Dynamic module import.
 pref("javascript.options.dynamicImport", true);
 
 // advanced prefs
 pref("advanced.mailftp",                    false);
 pref("image.animation_mode",                "normal");
 
 // Same-origin policy for file URIs, "false" is traditional