diff --git a/js/public/CompileOptions.h b/js/public/CompileOptions.h index 8fa95a201215..6bd95249a3a7 100644 --- a/js/public/CompileOptions.h +++ b/js/public/CompileOptions.h @@ -117,6 +117,7 @@ class JS_PUBLIC_API TransitiveCompileOptions { bool isProbablySystemCode = false; bool hideScriptFromDebugger = false; bool bigIntEnabledOption = false; + bool fieldsEnabledOption = false; /** * |introductionType| is a statically allocated C string: one of "eval", diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 78071fbba6c5..274f9b7133ab 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -6779,11 +6779,10 @@ bool GeneralParser::classMember( } 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 null(); + } if (isStatic) { errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF); diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index f2483ced218d..9c6059820ec6 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -1994,9 +1994,10 @@ MOZ_MUST_USE bool TokenStreamSpecific::identifierName( "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); } diff --git a/js/src/fuzz-tests/tests.cpp b/js/src/fuzz-tests/tests.cpp index 37a543aa5925..87b25304f9b3 100644 --- a/js/src/fuzz-tests/tests.cpp +++ b/js/src/fuzz-tests/tests.cpp @@ -42,8 +42,10 @@ 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) { diff --git a/js/src/jsapi-tests/tests.cpp b/js/src/jsapi-tests/tests.cpp index 96d1cd991c69..b5ce9befac68 100644 --- a/js/src/jsapi-tests/tests.cpp +++ b/js/src/jsapi-tests/tests.cpp @@ -79,8 +79,10 @@ 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) { diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 8e60b23a6169..fa9ed7423981 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3425,6 +3425,7 @@ void JS::TransitiveCompileOptions::copyPODTransitiveOptions( isProbablySystemCode = rhs.isProbablySystemCode; hideScriptFromDebugger = rhs.hideScriptFromDebugger; bigIntEnabledOption = rhs.bigIntEnabledOption; + fieldsEnabledOption = rhs.fieldsEnabledOption; }; void JS::ReadOnlyCompileOptions::copyPODOptions( @@ -3552,6 +3553,7 @@ JS::CompileOptions::CompileOptions(JSContext* cx) throwOnAsmJSValidationFailureOption = cx->options().throwOnAsmJSValidationFailure(); bigIntEnabledOption = cx->realm()->creationOptions().getBigIntEnabled(); + fieldsEnabledOption = cx->realm()->creationOptions().getFieldsEnabled(); } CompileOptions& CompileOptions::setIntroductionInfoToCaller( diff --git a/js/src/jsapi.h b/js/src/jsapi.h index db0172f33d16..fd1cb67dd607 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -964,6 +964,7 @@ class JS_PUBLIC_API RealmCreationOptions { sharedMemoryAndAtomics_(false), streams_(false), bigint_(false), + fields_(false), secureContext_(false), clampAndJitterTime_(true) {} @@ -1045,6 +1046,12 @@ class JS_PUBLIC_API RealmCreationOptions { 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/ @@ -1075,6 +1082,7 @@ class JS_PUBLIC_API RealmCreationOptions { bool sharedMemoryAndAtomics_; bool streams_; bool bigint_; + bool fields_; bool secureContext_; bool clampAndJitterTime_; }; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index f0c74c22d523..d154846a207d 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -503,6 +503,7 @@ 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; @@ -3763,7 +3764,8 @@ 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, @@ -10186,6 +10188,7 @@ static bool SetContextOptions(JSContext* cx, const OptionParser& op) { 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) @@ -10897,8 +10900,8 @@ int main(int argc, char** argv, char** envp) { !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 diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index a06a06380f70..33177e07114e 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -760,12 +760,14 @@ bool xpc::ExtraWarningsForSystemJS() { return false; } static mozilla::Atomic sSharedMemoryEnabled(false); static mozilla::Atomic sStreamsEnabled(false); static mozilla::Atomic sBigIntEnabled(false); +static mozilla::Atomic 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) { @@ -847,6 +849,7 @@ static void ReloadPrefsCallback(const char* pref, XPCJSContext* xpccx) { 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 = diff --git a/modules/libpref/init/StaticPrefList.h b/modules/libpref/init/StaticPrefList.h index 6b04619a5fe8..8d5297479d87 100644 --- a/modules/libpref/init/StaticPrefList.h +++ b/modules/libpref/init/StaticPrefList.h @@ -1113,6 +1113,12 @@ VARCACHE_PREF( RelaxedAtomicBool, false ) +VARCACHE_PREF( + "javascript.options.experimental.fields", + javascript_options_experimental_fields, + RelaxedAtomicBool, false +) + //--------------------------------------------------------------------------- // Media prefs diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index c110b185c0a4..fa64217bdfae 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1603,6 +1603,8 @@ 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);