Harden JSC against the abuse of runtime options.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Sep 2019 15:04:29 +0000 (15:04 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Sep 2019 15:04:29 +0000 (15:04 +0000)
https://bugs.webkit.org/show_bug.cgi?id=201597
<rdar://problem/55167068>

Reviewed by Filip Pizlo.

JSTests:

Remove the call to forceGCSlowPaths().  This utility function will be removed.
The modern way to set the required option is to use //@ requireOptions.

* stress/ftl-try-catch-oom-error-lazy-slow-path.js:

Source/JavaScriptCore:

Linux parts contributed by Carlos Garcia Campos <cgarcia@igalia.com>.

1. Introduce a JSC::Config struct that will be protected as ReadOnly once the
   first VM instance is constructed.  The end of the VM constructor calls
   Config::permanentlyFreeze() which will make the Config ReadOnly.

   Note: this is currently only supported for OS(DARWIN) and OS(LINUX).
   OS(WINDOWS) will need to implement some missing pieces before it can enable
   this hardening (see FIXME in JSCConfig.cpp).

   The hardening strategy here is to put immutable global values into the Config.
   Any modifications that need to be made to these values must be done before the
   first VM instance is done instantiating.  This ensures that no script will
   ever run while the Config is still writable.

   Also, the policy for this hardening is that a process is opted in by default.
   If there's a valid need to disable this hardening (e.g. for some test
   environments), the relevant process will need to opt itself out by calling
   Config::configureForTesting().

   The jsc shell, WK2 UI and WebContent processes are opted in by default.
   Only test processes may be opt out.

2. Put all JSC::Options in the Config.  This enforces the invariant that options
   can only be changed before we instantiate a VM.  Once a VM is instantiated,
   the options are immutable.

3. Remove functionForceGCSlowPaths() from the jsc shell.  Setting
   Options::forceGCSlowPaths this way is no longer allowed.

4. Re-factored the Options code (Options.h) into:
   - OptionEntry.h: the data structure that stores the option values.
   - OptionsList.h: the list of options.
   - Options.h: the Options singleton object which is the interface for accessing options.

   Renamed the JSC_OPTIONS macro to FOR_EACH_JSC_OPTION, because
   "FOR_EACH_JSC_OPTION(SET_OPTION_VALUE)" reads a lot better than
   "JSC_OPTIONS(FOR_EACH_OPTION)".

5. Change testapi to call Config::configureForTesting().  Parts of testapi makes
   use of setting options in its tests.  Hence, this hardening is disabled for
   testapi.

   Note: the jsc shell does enable this hardening.

6. Put ExecutableAllocator's immutable globals in the Config.

7. RELEASE_ASSERT that restrictedOptionsEnabled in order to use the
   FunctionOverrides test utility.

8. RELEASE_ASSERT that Options::useDollarVM() is enabled in order to use the $vm.

   We must RELEASE_ASSERT(Options::useDollarVM()) in all JSDollarVM functions
   that are non-trivial at an eye's glance.  This includes (but is not limited to):
       constructors
       create() factory
       createStructure() factory
       finishCreation()
       HOST_CALL or operation functions
       Constructors and methods of utility and test classes

   The only exception are some constexpr constructors used for instantiating
   globals (since these must have trivial constructors) e.g. DOMJITAttribute.
   Instead, these constructors should always be ALWAYS_INLINE.

* API/glib/JSCOptions.cpp:
(jscOptionsSetValue):
(jscOptionsGetValue):
(jsc_options_foreach):
(jsc_options_get_option_group):
* API/tests/testapi.c:
(main):
* API/tests/testapi.cpp:
(configureJSCForTesting):
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Sources.txt:
* jit/ExecutableAllocator.cpp:
(JSC::isJITEnabled):
(JSC::ExecutableAllocator::setJITEnabled):
(JSC::ExecutableAllocator::initializeUnderlyingAllocator):
(JSC::ExecutableAllocator::isValid const):
(JSC::ExecutableAllocator::underMemoryPressure):
(JSC::ExecutableAllocator::memoryPressureMultiplier):
(JSC::ExecutableAllocator::allocate):
(JSC::ExecutableAllocator::isValidExecutableMemory):
(JSC::ExecutableAllocator::getLock const):
(JSC::ExecutableAllocator::committedByteCount):
(JSC::ExecutableAllocator::dumpProfile):
(JSC::startOfFixedExecutableMemoryPoolImpl):
(JSC::endOfFixedExecutableMemoryPoolImpl):
(JSC::isJITPC):
(JSC::dumpJITMemory):
(JSC::ExecutableAllocator::initialize):
(JSC::ExecutableAllocator::singleton):
* jit/ExecutableAllocator.h:
(JSC::performJITMemcpy):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionJSCOptions):
(jscmain):
(functionForceGCSlowPaths): Deleted.
* runtime/ConfigFile.cpp:
(JSC::ConfigFile::parse):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCConfig.cpp: Added.
(JSC::Config::disableFreezingForTesting):
(JSC::Config::enableRestrictedOptions):
(JSC::Config::permanentlyFreeze):
* runtime/JSCConfig.h: Added.
(JSC::Config::configureForTesting):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::exposeDollarVM):
* runtime/OptionEntry.h: Added.
(JSC::OptionRange::operator= ):
(JSC::OptionRange::rangeString const):
* runtime/Options.cpp:
(JSC::Options::isAvailable):
(JSC::scaleJITPolicy):
(JSC::Options::initialize):
(JSC::Options::setOptions):
(JSC::Options::setOptionWithoutAlias):
(JSC::Options::setAliasedOption):
(JSC::Option::dump const):
(JSC::Option::operator== const):
(): Deleted.
(JSC::Options::enableRestrictedOptions): Deleted.
* runtime/Options.h:
(JSC::Option::Option):
(JSC::Option::defaultOption const):
(JSC::Option::boolVal):
(JSC::Option::unsignedVal):
(JSC::Option::doubleVal):
(JSC::Option::int32Val):
(JSC::Option::optionRangeVal):
(JSC::Option::optionStringVal):
(JSC::Option::gcLogLevelVal):
(JSC::OptionRange::operator= ): Deleted.
(JSC::OptionRange::rangeString const): Deleted.
* runtime/OptionsList.h: Added.
(JSC::countNumberOfJSCOptions):
* runtime/VM.cpp:
(JSC::VM::VM):
* tools/FunctionOverrides.cpp:
(JSC::FunctionOverrides::FunctionOverrides):
(JSC::FunctionOverrides::reinstallOverrides):
(JSC::FunctionOverrides::initializeOverrideFor):
(JSC::FunctionOverrides::parseOverridesInFile):
* tools/JSDollarVM.cpp:
(JSC::JSDollarVMCallFrame::JSDollarVMCallFrame):
(JSC::JSDollarVMCallFrame::createStructure):
(JSC::JSDollarVMCallFrame::create):
(JSC::JSDollarVMCallFrame::finishCreation):
(JSC::JSDollarVMCallFrame::addProperty):
(JSC::Element::Element):
(JSC::Element::create):
(JSC::Element::createStructure):
(JSC::Root::Root):
(JSC::Root::create):
(JSC::Root::createStructure):
(JSC::SimpleObject::SimpleObject):
(JSC::SimpleObject::create):
(JSC::SimpleObject::createStructure):
(JSC::ImpureGetter::ImpureGetter):
(JSC::ImpureGetter::createStructure):
(JSC::ImpureGetter::create):
(JSC::ImpureGetter::finishCreation):
(JSC::ImpureGetter::getOwnPropertySlot):
(JSC::CustomGetter::CustomGetter):
(JSC::CustomGetter::createStructure):
(JSC::CustomGetter::create):
(JSC::CustomGetter::getOwnPropertySlot):
(JSC::CustomGetter::customGetter):
(JSC::CustomGetter::customGetterAcessor):
(JSC::RuntimeArray::create):
(JSC::RuntimeArray::destroy):
(JSC::RuntimeArray::getOwnPropertySlot):
(JSC::RuntimeArray::getOwnPropertySlotByIndex):
(JSC::RuntimeArray::createPrototype):
(JSC::RuntimeArray::createStructure):
(JSC::RuntimeArray::finishCreation):
(JSC::RuntimeArray::RuntimeArray):
(JSC::RuntimeArray::lengthGetter):
(JSC::DOMJITNode::DOMJITNode):
(JSC::DOMJITNode::createStructure):
(JSC::DOMJITNode::checkSubClassSnippet):
(JSC::DOMJITNode::create):
(JSC::DOMJITGetter::DOMJITGetter):
(JSC::DOMJITGetter::createStructure):
(JSC::DOMJITGetter::create):
(JSC::DOMJITGetter::DOMJITAttribute::DOMJITAttribute):
(JSC::DOMJITGetter::DOMJITAttribute::slowCall):
(JSC::DOMJITGetter::DOMJITAttribute::callDOMGetter):
(JSC::DOMJITGetter::customGetter):
(JSC::DOMJITGetter::finishCreation):
(JSC::DOMJITGetterComplex::DOMJITGetterComplex):
(JSC::DOMJITGetterComplex::createStructure):
(JSC::DOMJITGetterComplex::create):
(JSC::DOMJITGetterComplex::DOMJITAttribute::DOMJITAttribute):
(JSC::DOMJITGetterComplex::DOMJITAttribute::slowCall):
(JSC::DOMJITGetterComplex::DOMJITAttribute::callDOMGetter):
(JSC::DOMJITGetterComplex::functionEnableException):
(JSC::DOMJITGetterComplex::customGetter):
(JSC::DOMJITGetterComplex::finishCreation):
(JSC::DOMJITFunctionObject::DOMJITFunctionObject):
(JSC::DOMJITFunctionObject::createStructure):
(JSC::DOMJITFunctionObject::create):
(JSC::DOMJITFunctionObject::functionWithTypeCheck):
(JSC::DOMJITFunctionObject::functionWithoutTypeCheck):
(JSC::DOMJITFunctionObject::checkSubClassSnippet):
(JSC::DOMJITFunctionObject::finishCreation):
(JSC::DOMJITCheckSubClassObject::DOMJITCheckSubClassObject):
(JSC::DOMJITCheckSubClassObject::createStructure):
(JSC::DOMJITCheckSubClassObject::create):
(JSC::DOMJITCheckSubClassObject::functionWithTypeCheck):
(JSC::DOMJITCheckSubClassObject::functionWithoutTypeCheck):
(JSC::DOMJITCheckSubClassObject::finishCreation):
(JSC::DOMJITGetterBaseJSObject::DOMJITGetterBaseJSObject):
(JSC::DOMJITGetterBaseJSObject::createStructure):
(JSC::DOMJITGetterBaseJSObject::create):
(JSC::DOMJITGetterBaseJSObject::DOMJITAttribute::DOMJITAttribute):
(JSC::DOMJITGetterBaseJSObject::DOMJITAttribute::slowCall):
(JSC::DOMJITGetterBaseJSObject::DOMJITAttribute::callDOMGetter):
(JSC::DOMJITGetterBaseJSObject::customGetter):
(JSC::DOMJITGetterBaseJSObject::finishCreation):
(JSC::JSTestCustomGetterSetter::JSTestCustomGetterSetter):
(JSC::JSTestCustomGetterSetter::create):
(JSC::JSTestCustomGetterSetter::createStructure):
(JSC::customSetAccessor):
(JSC::customSetValue):
(JSC::JSTestCustomGetterSetter::finishCreation):
(JSC::Element::handleOwner):
(JSC::Element::finishCreation):
(JSC::WasmStreamingParser::WasmStreamingParser):
(JSC::WasmStreamingParser::create):
(JSC::WasmStreamingParser::createStructure):
(JSC::WasmStreamingParser::finishCreation):
(JSC::functionWasmStreamingParserAddBytes):
(JSC::functionWasmStreamingParserFinalize):
(JSC::functionCrash):
(JSC::functionBreakpoint):
(JSC::functionDFGTrue):
(JSC::functionFTLTrue):
(JSC::functionCpuMfence):
(JSC::functionCpuRdtsc):
(JSC::functionCpuCpuid):
(JSC::functionCpuPause):
(JSC::functionCpuClflush):
(JSC::CallerFrameJITTypeFunctor::CallerFrameJITTypeFunctor):
(JSC::getExecutableForFunction):
(JSC::functionLLintTrue):
(JSC::functionJITTrue):
(JSC::functionNoInline):
(JSC::functionGC):
(JSC::functionEdenGC):
(JSC::functionDumpSubspaceHashes):
(JSC::functionCallFrame):
(JSC::functionCodeBlockForFrame):
(JSC::codeBlockFromArg):
(JSC::functionCodeBlockFor):
(JSC::functionDumpSourceFor):
(JSC::functionDumpBytecodeFor):
(JSC::doPrint):
(JSC::functionDataLog):
(JSC::functionPrint):
(JSC::functionDumpCallFrame):
(JSC::functionDumpStack):
(JSC::functionDumpRegisters):
(JSC::functionDumpCell):
(JSC::functionIndexingMode):
(JSC::functionInlineCapacity):
(JSC::functionValue):
(JSC::functionGetPID):
(JSC::functionHaveABadTime):
(JSC::functionIsHavingABadTime):
(JSC::functionCreateGlobalObject):
(JSC::functionCreateProxy):
(JSC::functionCreateRuntimeArray):
(JSC::functionCreateNullRopeString):
(JSC::functionCreateImpureGetter):
(JSC::functionCreateCustomGetterObject):
(JSC::functionCreateDOMJITNodeObject):
(JSC::functionCreateDOMJITGetterObject):
(JSC::functionCreateDOMJITGetterComplexObject):
(JSC::functionCreateDOMJITFunctionObject):
(JSC::functionCreateDOMJITCheckSubClassObject):
(JSC::functionCreateDOMJITGetterBaseJSObject):
(JSC::functionCreateWasmStreamingParser):
(JSC::functionSetImpureGetterDelegate):
(JSC::functionCreateBuiltin):
(JSC::functionGetPrivateProperty):
(JSC::functionCreateRoot):
(JSC::functionCreateElement):
(JSC::functionGetElement):
(JSC::functionCreateSimpleObject):
(JSC::functionGetHiddenValue):
(JSC::functionSetHiddenValue):
(JSC::functionShadowChickenFunctionsOnStack):
(JSC::functionSetGlobalConstRedeclarationShouldNotThrow):
(JSC::functionFindTypeForExpression):
(JSC::functionReturnTypeFor):
(JSC::functionFlattenDictionaryObject):
(JSC::functionDumpBasicBlockExecutionRanges):
(JSC::functionHasBasicBlockExecuted):
(JSC::functionBasicBlockExecutionCount):
(JSC::functionEnableExceptionFuzz):
(JSC::changeDebuggerModeWhenIdle):
(JSC::functionEnableDebuggerModeWhenIdle):
(JSC::functionDisableDebuggerModeWhenIdle):
(JSC::functionDeleteAllCodeWhenIdle):
(JSC::functionGlobalObjectCount):
(JSC::functionGlobalObjectForObject):
(JSC::functionGetGetterSetter):
(JSC::functionLoadGetterFromGetterSetter):
(JSC::functionCreateCustomTestGetterSetter):
(JSC::functionDeltaBetweenButterflies):
(JSC::functionTotalGCTime):
(JSC::functionParseCount):
(JSC::functionIsWasmSupported):
(JSC::JSDollarVM::finishCreation):
(JSC::JSDollarVM::addFunction):
(JSC::JSDollarVM::addConstructibleFunction):
* tools/JSDollarVM.h:

Source/WebCore:

No new tests.  Covered by existing tests.

Enable Options::useDollarVM before we tell the JSGlobalObject to exposeDollarVM().
The $vm utility is now hardened to require that Options::useDollarVM be
enabled in order for it to be used.

* testing/js/WebCoreTestSupport.cpp:
(WebCoreTestSupport::injectInternalsObject):

Source/WebKit:

Linux parts contributed by Carlos Garcia Campos <cgarcia@igalia.com>.

1. Add plumbing to allow WK2 tests to configureJSCForTesting().
2. Removed the call enable Options::useBigInt in WebInspectorUI.
   WebInspectorUI doesn't really need it for now.

* PluginProcess/unix/PluginProcessMainUnix.cpp:
* Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceEntryPoint.h:
(WebKit::XPCServiceInitializer):
* Shared/unix/AuxiliaryProcessMain.cpp:
(WebKit::AuxiliaryProcessMainBase::parseCommandLine):
* Shared/unix/AuxiliaryProcessMain.h:
(WebKit::AuxiliaryProcessMain):
* UIProcess/API/APIProcessPoolConfiguration.cpp:
(API::ProcessPoolConfiguration::copy):
* UIProcess/API/APIProcessPoolConfiguration.h:
* UIProcess/API/C/WKContextConfigurationRef.cpp:
(WKContextConfigurationSetShouldConfigureJSCForTesting):
* UIProcess/API/C/WKContextConfigurationRef.h:
* UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h:
* UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm:
(-[_WKProcessPoolConfiguration configureJSCForTesting]):
(-[_WKProcessPoolConfiguration setConfigureJSCForTesting:]):
* UIProcess/Launcher/ProcessLauncher.h:
(WebKit::ProcessLauncher::Client::shouldConfigureJSCForTesting const):
* UIProcess/Launcher/glib/ProcessLauncherGLib.cpp:
(WebKit::ProcessLauncher::launchProcess):
* UIProcess/Launcher/mac/ProcessLauncherMac.mm:
(WebKit::ProcessLauncher::launchProcess):
* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::shouldConfigureJSCForTesting const):
* UIProcess/WebProcessProxy.h:
* WebProcess/WebPage/WebInspectorUI.cpp:
(WebKit::WebInspectorUI::WebInspectorUI):

Source/WTF:

Add a source file that was missing so that Xcode can search its contents too.

* WTF.xcodeproj/project.pbxproj:

Tools:

Linux parts contributed by Carlos Garcia Campos <cgarcia@igalia.com>.
Windows parts contributed by Fujii Hironori <Hironori.Fujii@sony.com>.

Call JSC::Config::configureForTesting() in test harnesses or at the top of tests
to disable the hardening on test runs.  Tests rely on setting options to enable
test features.

* DumpRenderTree/mac/DumpRenderTree.mm:
(dumpRenderTree):
* DumpRenderTree/win/DumpRenderTree.cpp:
(initialize):
* TestWebKitAPI/PlatformUtilities.cpp:
(TestWebKitAPI::Util::createContextWithInjectedBundle):
* TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp:
(main):
* TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm:
(TestWebKitAPI::TEST):
(TestWebKitAPI::runActiveSessionTest):
* TestWebKitAPI/Tests/WebKitCocoa/WKWebViewDiagnosticLogging.mm:
(TEST):
* TestWebKitAPI/Tests/WebKitCocoa/WebsiteDataStoreCustomPaths.mm:
(TEST):
* TestWebKitAPI/Tests/mac/MediaPlaybackSleepAssertion.mm:
(TestWebKitAPI::TEST):
* TestWebKitAPI/WKWebViewConfigurationExtras.h:
* TestWebKitAPI/WKWebViewConfigurationExtras.mm:
(+[WKWebViewConfiguration _test_configurationWithTestPlugInClassName:]):
(+[WKWebViewConfiguration _test_configurationWithTestPlugInClassName:configureJSCForTesting:]):
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::generateContextConfiguration const):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@249808 268f45cc-cd09-0410-ab3c-d52691b4dbfc

58 files changed:
JSTests/ChangeLog
JSTests/stress/ftl-try-catch-oom-error-lazy-slow-path.js
Source/JavaScriptCore/API/glib/JSCOptions.cpp
Source/JavaScriptCore/API/tests/testapi.c
Source/JavaScriptCore/API/tests/testapi.cpp
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Sources.txt
Source/JavaScriptCore/jit/ExecutableAllocator.cpp
Source/JavaScriptCore/jit/ExecutableAllocator.h
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/runtime/ConfigFile.cpp
Source/JavaScriptCore/runtime/InitializeThreading.cpp
Source/JavaScriptCore/runtime/JSCConfig.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSCConfig.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/OptionEntry.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/Options.cpp
Source/JavaScriptCore/runtime/Options.h
Source/JavaScriptCore/runtime/OptionsList.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/tools/FunctionOverrides.cpp
Source/JavaScriptCore/tools/JSDollarVM.cpp
Source/JavaScriptCore/tools/JSDollarVM.h
Source/WTF/ChangeLog
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WebCore/ChangeLog
Source/WebCore/testing/js/WebCoreTestSupport.cpp
Source/WebKit/ChangeLog
Source/WebKit/PluginProcess/unix/PluginProcessMainUnix.cpp
Source/WebKit/Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceEntryPoint.h
Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp
Source/WebKit/Shared/unix/AuxiliaryProcessMain.h
Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp
Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h
Source/WebKit/UIProcess/API/C/WKContextConfigurationRef.cpp
Source/WebKit/UIProcess/API/C/WKContextConfigurationRef.h
Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h
Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm
Source/WebKit/UIProcess/Launcher/ProcessLauncher.h
Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp
Source/WebKit/UIProcess/Launcher/mac/ProcessLauncherMac.mm
Source/WebKit/UIProcess/WebProcessProxy.cpp
Source/WebKit/UIProcess/WebProcessProxy.h
Source/WebKit/WebProcess/WebPage/WebInspectorUI.cpp
Tools/ChangeLog
Tools/DumpRenderTree/mac/DumpRenderTree.mm
Tools/DumpRenderTree/win/DumpRenderTree.cpp
Tools/TestWebKitAPI/PlatformUtilities.cpp
Tools/TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp
Tools/TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm
Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebViewDiagnosticLogging.mm
Tools/TestWebKitAPI/Tests/WebKitCocoa/WebsiteDataStoreCustomPaths.mm
Tools/TestWebKitAPI/Tests/mac/MediaPlaybackSleepAssertion.mm
Tools/TestWebKitAPI/WKWebViewConfigurationExtras.h
Tools/TestWebKitAPI/WKWebViewConfigurationExtras.mm
Tools/WebKitTestRunner/TestController.cpp

index 34f97cc..faf916e 100644 (file)
@@ -1,3 +1,16 @@
+2019-09-12  Mark Lam  <mark.lam@apple.com>
+
+        Harden JSC against the abuse of runtime options.
+        https://bugs.webkit.org/show_bug.cgi?id=201597
+        <rdar://problem/55167068>
+
+        Reviewed by Filip Pizlo.
+
+        Remove the call to forceGCSlowPaths().  This utility function will be removed.
+        The modern way to set the required option is to use //@ requireOptions.
+
+        * stress/ftl-try-catch-oom-error-lazy-slow-path.js:
+
 2019-09-11  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [JSC] Add StringCodePointAt intrinsic
index a8f2b18..80cf411 100644 (file)
@@ -1,4 +1,6 @@
-forceGCSlowPaths(); // Force OOM error in FTL MakeRope to happen in a lazy slow path.
+//@ requireOptions("--forceGCSlowPaths=true")
+
+// We require --forceGCSlowPaths=true to force OOM error in FTL MakeRope to happen in a lazy slow path.
 
 function assert(b) {
     if (!b)
index af7b345..655f5f0 100644 (file)
@@ -31,7 +31,7 @@
  * @title: JSCOptions
  *
  * JavaScript options allow changing the behavior of the JavaScript engine.
- * They affect the way the engine works, so it's encouraged to set the options
+ * They affect the way the engine works, so the options must be set
  * at the very beginning of the program execution, before any other JavaScript
  * API call. Most of the options are only useful for testing and debugging.
  * Only a few of them are documented; you can use the undocumented options at
@@ -166,9 +166,9 @@ static void valueToGValue(GCLogging::Level value, GValue* gValue)
 
 static gboolean jscOptionsSetValue(const char* option, const GValue* value)
 {
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
+#define SET_OPTION_VALUE(type_, name_, defaultValue_, availability_, description_) \
     if (!g_strcmp0(#name_, option)) {                                   \
-        type_ valueToSet;                                               \
+        OptionEntry::type_ valueToSet;                                  \
         if (!valueFromGValue(value, valueToSet))                        \
             return FALSE;                                               \
         Options::name_() = valueToSet;                                  \
@@ -176,24 +176,24 @@ static gboolean jscOptionsSetValue(const char* option, const GValue* value)
     }
 
     Options::initialize();
-    JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+    FOR_EACH_JSC_OPTION(SET_OPTION_VALUE)
+#undef SET_OPTION_VALUE
 
     return FALSE;
 }
 
 static gboolean jscOptionsGetValue(const char* option, GValue* value)
 {
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
+#define GET_OPTION_VALUE(type_, name_, defaultValue_, availability_, description_) \
     if (!g_strcmp0(#name_, option)) {                                   \
-        type_ valueToGet = Options::name_();                            \
+        OptionEntry::type_ valueToGet = Options::name_();               \
         valueToGValue(valueToGet, value);                               \
         return TRUE;                                                    \
     }
 
     Options::initialize();
-    JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+    FOR_EACH_JSC_OPTION(GET_OPTION_VALUE)
+#undef GET_OPTION_VALUE
 
     return FALSE;
 }
@@ -614,18 +614,18 @@ void jsc_options_foreach(JSCOptionsFunc function, gpointer userData)
 {
     g_return_if_fail(function);
 
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
+#define VISIT_OPTION(type_, name_, defaultValue_, availability_, description_) \
     if (Options::Availability::availability_ == Options::Availability::Normal \
         || Options::isAvailable(Options::name_##ID, Options::Availability::availability_)) { \
-        type_ defaultValue { };                                         \
+        OptionEntry::type_ defaultValue { };                            \
         auto optionType = jscOptionsType(defaultValue);                 \
         if (function (#name_, optionType, description_, userData))      \
             return;                                                     \
     }
 
     Options::initialize();
-    JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+    FOR_EACH_JSC_OPTION(VISIT_OPTION)
+#undef VISIT_OPTION
 }
 
 static gboolean setOptionEntry(const char* optionNameFull, const char* value, gpointer, GError** error)
@@ -664,7 +664,7 @@ GOptionGroup* jsc_options_get_option_group(void)
     g_option_group_set_translation_domain(group, GETTEXT_PACKAGE);
 
     GArray* entries = g_array_new(TRUE, TRUE, sizeof(GOptionEntry));
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
+#define REGISTER_OPTION(type_, name_, defaultValue_, availability_, description_) \
     if (Options::Availability::availability_ == Options::Availability::Normal \
         || Options::isAvailable(Options::name_##ID, Options::Availability::availability_)) { \
         GUniquePtr<char> name(g_strdup_printf("jsc-%s", #name_));       \
@@ -678,8 +678,8 @@ GOptionGroup* jsc_options_get_option_group(void)
     }
 
     Options::initialize();
-    JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+    FOR_EACH_JSC_OPTION(REGISTER_OPTION)
+#undef REGISTER_OPTION
 
     g_option_group_add_entries(group, reinterpret_cast<GOptionEntry*>(entries->data));
     return group;
index 3150fdb..f2993ee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2017 Apple Inc.  All rights reserved.
+ * Copyright (C) 2006-2019 Apple Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -77,6 +77,7 @@
 void testObjectiveCAPI(const char*);
 #endif
 
+void configureJSCForTesting(void);
 int testCAPIViaCpp(const char* filter);
 
 bool assertTrue(bool value, const char* message);
@@ -1387,6 +1388,8 @@ int main(int argc, char* argv[])
     SetErrorMode(0);
 #endif
 
+    configureJSCForTesting();
+
 #if !OS(WINDOWS)
     char resolvedPath[PATH_MAX];
     if (!realpath(argv[0], resolvedPath))
index d9266c7..3ffa3ea 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -39,6 +39,7 @@
 #include <wtf/Vector.h>
 #include <wtf/text/StringCommon.h>
 
+extern "C" void configureJSCForTesting();
 extern "C" int testCAPIViaCpp(const char* filter);
 
 class APIString {
@@ -589,6 +590,11 @@ void TestAPI::promiseEarlyHandledRejections()
     check(!callbackCalled, "unhandled rejection callback should not be called for asynchronous early-handled rejection");
 }
 
+void configureJSCForTesting()
+{
+    JSC::Config::configureForTesting();
+}
+
 #define RUN(test) do {                                 \
         if (!shouldRun(#test))                         \
             break;                                     \
index d9940ff..a6c0f02 100644 (file)
@@ -842,6 +842,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
     runtime/JSArrayBufferView.h
     runtime/JSArrayBufferViewInlines.h
     runtime/JSBigInt.h
+    runtime/JSCConfig.h
     runtime/JSCInlines.h
     runtime/JSCJSValue.h
     runtime/JSCJSValueInlines.h
@@ -918,7 +919,9 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
     runtime/ObjectInitializationScope.h
     runtime/ObjectPrototype.h
     runtime/Operations.h
+    runtime/OptionEntry.h
     runtime/Options.h
+    runtime/OptionsList.h
     runtime/ParseInt.h
     runtime/PrivateName.h
     runtime/ProgramExecutable.h
index 58c955c..6d53b70 100644 (file)
@@ -1,3 +1,336 @@
+2019-09-12  Mark Lam  <mark.lam@apple.com>
+
+        Harden JSC against the abuse of runtime options.
+        https://bugs.webkit.org/show_bug.cgi?id=201597
+        <rdar://problem/55167068>
+
+        Reviewed by Filip Pizlo.
+
+        Linux parts contributed by Carlos Garcia Campos <cgarcia@igalia.com>.
+
+        1. Introduce a JSC::Config struct that will be protected as ReadOnly once the
+           first VM instance is constructed.  The end of the VM constructor calls
+           Config::permanentlyFreeze() which will make the Config ReadOnly.
+
+           Note: this is currently only supported for OS(DARWIN) and OS(LINUX).
+           OS(WINDOWS) will need to implement some missing pieces before it can enable
+           this hardening (see FIXME in JSCConfig.cpp).
+
+           The hardening strategy here is to put immutable global values into the Config.
+           Any modifications that need to be made to these values must be done before the
+           first VM instance is done instantiating.  This ensures that no script will
+           ever run while the Config is still writable.
+
+           Also, the policy for this hardening is that a process is opted in by default.
+           If there's a valid need to disable this hardening (e.g. for some test
+           environments), the relevant process will need to opt itself out by calling
+           Config::configureForTesting().
+
+           The jsc shell, WK2 UI and WebContent processes are opted in by default.
+           Only test processes may be opt out.
+
+        2. Put all JSC::Options in the Config.  This enforces the invariant that options
+           can only be changed before we instantiate a VM.  Once a VM is instantiated,
+           the options are immutable.
+
+        3. Remove functionForceGCSlowPaths() from the jsc shell.  Setting
+           Options::forceGCSlowPaths this way is no longer allowed.
+
+        4. Re-factored the Options code (Options.h) into:
+           - OptionEntry.h: the data structure that stores the option values.
+           - OptionsList.h: the list of options.
+           - Options.h: the Options singleton object which is the interface for accessing options.
+
+           Renamed the JSC_OPTIONS macro to FOR_EACH_JSC_OPTION, because
+           "FOR_EACH_JSC_OPTION(SET_OPTION_VALUE)" reads a lot better than
+           "JSC_OPTIONS(FOR_EACH_OPTION)".
+
+        5. Change testapi to call Config::configureForTesting().  Parts of testapi makes
+           use of setting options in its tests.  Hence, this hardening is disabled for
+           testapi.
+
+           Note: the jsc shell does enable this hardening.
+
+        6. Put ExecutableAllocator's immutable globals in the Config.
+
+        7. RELEASE_ASSERT that restrictedOptionsEnabled in order to use the
+           FunctionOverrides test utility.
+
+        8. RELEASE_ASSERT that Options::useDollarVM() is enabled in order to use the $vm.
+
+           We must RELEASE_ASSERT(Options::useDollarVM()) in all JSDollarVM functions
+           that are non-trivial at an eye's glance.  This includes (but is not limited to):
+               constructors
+               create() factory
+               createStructure() factory
+               finishCreation()
+               HOST_CALL or operation functions
+               Constructors and methods of utility and test classes
+
+           The only exception are some constexpr constructors used for instantiating
+           globals (since these must have trivial constructors) e.g. DOMJITAttribute.
+           Instead, these constructors should always be ALWAYS_INLINE.
+
+        * API/glib/JSCOptions.cpp:
+        (jscOptionsSetValue):
+        (jscOptionsGetValue):
+        (jsc_options_foreach):
+        (jsc_options_get_option_group):
+        * API/tests/testapi.c:
+        (main):
+        * API/tests/testapi.cpp:
+        (configureJSCForTesting):
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        * jit/ExecutableAllocator.cpp:
+        (JSC::isJITEnabled):
+        (JSC::ExecutableAllocator::setJITEnabled):
+        (JSC::ExecutableAllocator::initializeUnderlyingAllocator):
+        (JSC::ExecutableAllocator::isValid const):
+        (JSC::ExecutableAllocator::underMemoryPressure):
+        (JSC::ExecutableAllocator::memoryPressureMultiplier):
+        (JSC::ExecutableAllocator::allocate):
+        (JSC::ExecutableAllocator::isValidExecutableMemory):
+        (JSC::ExecutableAllocator::getLock const):
+        (JSC::ExecutableAllocator::committedByteCount):
+        (JSC::ExecutableAllocator::dumpProfile):
+        (JSC::startOfFixedExecutableMemoryPoolImpl):
+        (JSC::endOfFixedExecutableMemoryPoolImpl):
+        (JSC::isJITPC):
+        (JSC::dumpJITMemory):
+        (JSC::ExecutableAllocator::initialize):
+        (JSC::ExecutableAllocator::singleton):
+        * jit/ExecutableAllocator.h:
+        (JSC::performJITMemcpy):
+        * jsc.cpp:
+        (GlobalObject::finishCreation):
+        (functionJSCOptions):
+        (jscmain):
+        (functionForceGCSlowPaths): Deleted.
+        * runtime/ConfigFile.cpp:
+        (JSC::ConfigFile::parse):
+        * runtime/InitializeThreading.cpp:
+        (JSC::initializeThreading):
+        * runtime/JSCConfig.cpp: Added.
+        (JSC::Config::disableFreezingForTesting):
+        (JSC::Config::enableRestrictedOptions):
+        (JSC::Config::permanentlyFreeze):
+        * runtime/JSCConfig.h: Added.
+        (JSC::Config::configureForTesting):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::exposeDollarVM):
+        * runtime/OptionEntry.h: Added.
+        (JSC::OptionRange::operator= ):
+        (JSC::OptionRange::rangeString const):
+        * runtime/Options.cpp:
+        (JSC::Options::isAvailable):
+        (JSC::scaleJITPolicy):
+        (JSC::Options::initialize):
+        (JSC::Options::setOptions):
+        (JSC::Options::setOptionWithoutAlias):
+        (JSC::Options::setAliasedOption):
+        (JSC::Option::dump const):
+        (JSC::Option::operator== const):
+        (): Deleted.
+        (JSC::Options::enableRestrictedOptions): Deleted.
+        * runtime/Options.h:
+        (JSC::Option::Option):
+        (JSC::Option::defaultOption const):
+        (JSC::Option::boolVal):
+        (JSC::Option::unsignedVal):
+        (JSC::Option::doubleVal):
+        (JSC::Option::int32Val):
+        (JSC::Option::optionRangeVal):
+        (JSC::Option::optionStringVal):
+        (JSC::Option::gcLogLevelVal):
+        (JSC::OptionRange::operator= ): Deleted.
+        (JSC::OptionRange::rangeString const): Deleted.
+        * runtime/OptionsList.h: Added.
+        (JSC::countNumberOfJSCOptions):
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        * tools/FunctionOverrides.cpp:
+        (JSC::FunctionOverrides::FunctionOverrides):
+        (JSC::FunctionOverrides::reinstallOverrides):
+        (JSC::FunctionOverrides::initializeOverrideFor):
+        (JSC::FunctionOverrides::parseOverridesInFile):
+        * tools/JSDollarVM.cpp:
+        (JSC::JSDollarVMCallFrame::JSDollarVMCallFrame):
+        (JSC::JSDollarVMCallFrame::createStructure):
+        (JSC::JSDollarVMCallFrame::create):
+        (JSC::JSDollarVMCallFrame::finishCreation):
+        (JSC::JSDollarVMCallFrame::addProperty):
+        (JSC::Element::Element):
+        (JSC::Element::create):
+        (JSC::Element::createStructure):
+        (JSC::Root::Root):
+        (JSC::Root::create):
+        (JSC::Root::createStructure):
+        (JSC::SimpleObject::SimpleObject):
+        (JSC::SimpleObject::create):
+        (JSC::SimpleObject::createStructure):
+        (JSC::ImpureGetter::ImpureGetter):
+        (JSC::ImpureGetter::createStructure):
+        (JSC::ImpureGetter::create):
+        (JSC::ImpureGetter::finishCreation):
+        (JSC::ImpureGetter::getOwnPropertySlot):
+        (JSC::CustomGetter::CustomGetter):
+        (JSC::CustomGetter::createStructure):
+        (JSC::CustomGetter::create):
+        (JSC::CustomGetter::getOwnPropertySlot):
+        (JSC::CustomGetter::customGetter):
+        (JSC::CustomGetter::customGetterAcessor):
+        (JSC::RuntimeArray::create):
+        (JSC::RuntimeArray::destroy):
+        (JSC::RuntimeArray::getOwnPropertySlot):
+        (JSC::RuntimeArray::getOwnPropertySlotByIndex):
+        (JSC::RuntimeArray::createPrototype):
+        (JSC::RuntimeArray::createStructure):
+        (JSC::RuntimeArray::finishCreation):
+        (JSC::RuntimeArray::RuntimeArray):
+        (JSC::RuntimeArray::lengthGetter):
+        (JSC::DOMJITNode::DOMJITNode):
+        (JSC::DOMJITNode::createStructure):
+        (JSC::DOMJITNode::checkSubClassSnippet):
+        (JSC::DOMJITNode::create):
+        (JSC::DOMJITGetter::DOMJITGetter):
+        (JSC::DOMJITGetter::createStructure):
+        (JSC::DOMJITGetter::create):
+        (JSC::DOMJITGetter::DOMJITAttribute::DOMJITAttribute):
+        (JSC::DOMJITGetter::DOMJITAttribute::slowCall):
+        (JSC::DOMJITGetter::DOMJITAttribute::callDOMGetter):
+        (JSC::DOMJITGetter::customGetter):
+        (JSC::DOMJITGetter::finishCreation):
+        (JSC::DOMJITGetterComplex::DOMJITGetterComplex):
+        (JSC::DOMJITGetterComplex::createStructure):
+        (JSC::DOMJITGetterComplex::create):
+        (JSC::DOMJITGetterComplex::DOMJITAttribute::DOMJITAttribute):
+        (JSC::DOMJITGetterComplex::DOMJITAttribute::slowCall):
+        (JSC::DOMJITGetterComplex::DOMJITAttribute::callDOMGetter):
+        (JSC::DOMJITGetterComplex::functionEnableException):
+        (JSC::DOMJITGetterComplex::customGetter):
+        (JSC::DOMJITGetterComplex::finishCreation):
+        (JSC::DOMJITFunctionObject::DOMJITFunctionObject):
+        (JSC::DOMJITFunctionObject::createStructure):
+        (JSC::DOMJITFunctionObject::create):
+        (JSC::DOMJITFunctionObject::functionWithTypeCheck):
+        (JSC::DOMJITFunctionObject::functionWithoutTypeCheck):
+        (JSC::DOMJITFunctionObject::checkSubClassSnippet):
+        (JSC::DOMJITFunctionObject::finishCreation):
+        (JSC::DOMJITCheckSubClassObject::DOMJITCheckSubClassObject):
+        (JSC::DOMJITCheckSubClassObject::createStructure):
+        (JSC::DOMJITCheckSubClassObject::create):
+        (JSC::DOMJITCheckSubClassObject::functionWithTypeCheck):
+        (JSC::DOMJITCheckSubClassObject::functionWithoutTypeCheck):
+        (JSC::DOMJITCheckSubClassObject::finishCreation):
+        (JSC::DOMJITGetterBaseJSObject::DOMJITGetterBaseJSObject):
+        (JSC::DOMJITGetterBaseJSObject::createStructure):
+        (JSC::DOMJITGetterBaseJSObject::create):
+        (JSC::DOMJITGetterBaseJSObject::DOMJITAttribute::DOMJITAttribute):
+        (JSC::DOMJITGetterBaseJSObject::DOMJITAttribute::slowCall):
+        (JSC::DOMJITGetterBaseJSObject::DOMJITAttribute::callDOMGetter):
+        (JSC::DOMJITGetterBaseJSObject::customGetter):
+        (JSC::DOMJITGetterBaseJSObject::finishCreation):
+        (JSC::JSTestCustomGetterSetter::JSTestCustomGetterSetter):
+        (JSC::JSTestCustomGetterSetter::create):
+        (JSC::JSTestCustomGetterSetter::createStructure):
+        (JSC::customSetAccessor):
+        (JSC::customSetValue):
+        (JSC::JSTestCustomGetterSetter::finishCreation):
+        (JSC::Element::handleOwner):
+        (JSC::Element::finishCreation):
+        (JSC::WasmStreamingParser::WasmStreamingParser):
+        (JSC::WasmStreamingParser::create):
+        (JSC::WasmStreamingParser::createStructure):
+        (JSC::WasmStreamingParser::finishCreation):
+        (JSC::functionWasmStreamingParserAddBytes):
+        (JSC::functionWasmStreamingParserFinalize):
+        (JSC::functionCrash):
+        (JSC::functionBreakpoint):
+        (JSC::functionDFGTrue):
+        (JSC::functionFTLTrue):
+        (JSC::functionCpuMfence):
+        (JSC::functionCpuRdtsc):
+        (JSC::functionCpuCpuid):
+        (JSC::functionCpuPause):
+        (JSC::functionCpuClflush):
+        (JSC::CallerFrameJITTypeFunctor::CallerFrameJITTypeFunctor):
+        (JSC::getExecutableForFunction):
+        (JSC::functionLLintTrue):
+        (JSC::functionJITTrue):
+        (JSC::functionNoInline):
+        (JSC::functionGC):
+        (JSC::functionEdenGC):
+        (JSC::functionDumpSubspaceHashes):
+        (JSC::functionCallFrame):
+        (JSC::functionCodeBlockForFrame):
+        (JSC::codeBlockFromArg):
+        (JSC::functionCodeBlockFor):
+        (JSC::functionDumpSourceFor):
+        (JSC::functionDumpBytecodeFor):
+        (JSC::doPrint):
+        (JSC::functionDataLog):
+        (JSC::functionPrint):
+        (JSC::functionDumpCallFrame):
+        (JSC::functionDumpStack):
+        (JSC::functionDumpRegisters):
+        (JSC::functionDumpCell):
+        (JSC::functionIndexingMode):
+        (JSC::functionInlineCapacity):
+        (JSC::functionValue):
+        (JSC::functionGetPID):
+        (JSC::functionHaveABadTime):
+        (JSC::functionIsHavingABadTime):
+        (JSC::functionCreateGlobalObject):
+        (JSC::functionCreateProxy):
+        (JSC::functionCreateRuntimeArray):
+        (JSC::functionCreateNullRopeString):
+        (JSC::functionCreateImpureGetter):
+        (JSC::functionCreateCustomGetterObject):
+        (JSC::functionCreateDOMJITNodeObject):
+        (JSC::functionCreateDOMJITGetterObject):
+        (JSC::functionCreateDOMJITGetterComplexObject):
+        (JSC::functionCreateDOMJITFunctionObject):
+        (JSC::functionCreateDOMJITCheckSubClassObject):
+        (JSC::functionCreateDOMJITGetterBaseJSObject):
+        (JSC::functionCreateWasmStreamingParser):
+        (JSC::functionSetImpureGetterDelegate):
+        (JSC::functionCreateBuiltin):
+        (JSC::functionGetPrivateProperty):
+        (JSC::functionCreateRoot):
+        (JSC::functionCreateElement):
+        (JSC::functionGetElement):
+        (JSC::functionCreateSimpleObject):
+        (JSC::functionGetHiddenValue):
+        (JSC::functionSetHiddenValue):
+        (JSC::functionShadowChickenFunctionsOnStack):
+        (JSC::functionSetGlobalConstRedeclarationShouldNotThrow):
+        (JSC::functionFindTypeForExpression):
+        (JSC::functionReturnTypeFor):
+        (JSC::functionFlattenDictionaryObject):
+        (JSC::functionDumpBasicBlockExecutionRanges):
+        (JSC::functionHasBasicBlockExecuted):
+        (JSC::functionBasicBlockExecutionCount):
+        (JSC::functionEnableExceptionFuzz):
+        (JSC::changeDebuggerModeWhenIdle):
+        (JSC::functionEnableDebuggerModeWhenIdle):
+        (JSC::functionDisableDebuggerModeWhenIdle):
+        (JSC::functionDeleteAllCodeWhenIdle):
+        (JSC::functionGlobalObjectCount):
+        (JSC::functionGlobalObjectForObject):
+        (JSC::functionGetGetterSetter):
+        (JSC::functionLoadGetterFromGetterSetter):
+        (JSC::functionCreateCustomTestGetterSetter):
+        (JSC::functionDeltaBetweenButterflies):
+        (JSC::functionTotalGCTime):
+        (JSC::functionParseCount):
+        (JSC::functionIsWasmSupported):
+        (JSC::JSDollarVM::finishCreation):
+        (JSC::JSDollarVM::addFunction):
+        (JSC::JSDollarVM::addConstructibleFunction):
+        * tools/JSDollarVM.h:
+
 2019-09-11  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: Canvas: instrument WebGPUDevice instead of GPUCanvasContext
index ae0eeb7..e22c14f 100644 (file)
                };
                E1AC2E2720F7B94C00B0897D /* Unlock Keychain */ = {
                        isa = PBXAggregateTarget;
-                       buildConfigurationList = 14CFB10523035EF300F0048C /* Build configuration list */;
+                       buildConfigurationList = 14CFB10523035EF300F0048C /* Build configuration list for PBXAggregateTarget "Unlock Keychain" */;
                        buildPhases = (
                                E1AC2E2C20F7B95800B0897D /* Unlock Keychain */,
                        );
                FE3022D71E42857300BAC493 /* VMInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3022D51E42856700BAC493 /* VMInspector.h */; };
                FE318FE01CAC982F00DFCC54 /* ECMAScriptSpecInternalFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = FE318FDE1CAC8C5300DFCC54 /* ECMAScriptSpecInternalFunctions.h */; };
                FE3422121D6B81C30032BE88 /* ThrowScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3422111D6B818C0032BE88 /* ThrowScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               FE3842322324D51B009DD445 /* OptionEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3842302324D51A009DD445 /* OptionEntry.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               FE3842332324D51B009DD445 /* OptionsList.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3842312324D51B009DD445 /* OptionsList.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE384EE61ADDB7AD0055DE2C /* JSDollarVM.h in Headers */ = {isa = PBXBuildFile; fileRef = FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE3A06A61C10B72D00390FDD /* JITBitOrGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3A06A41C10B70800390FDD /* JITBitOrGenerator.h */; };
                FE3A06A81C10BC8100390FDD /* JITBitBinaryOpGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3A06A71C10BC7400390FDD /* JITBitBinaryOpGenerator.h */; };
                FE3A06BE1C11041200390FDD /* JITLeftShiftGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3A06B71C1103D900390FDD /* JITLeftShiftGenerator.h */; };
                FE3A06C01C11041A00390FDD /* JITRightShiftGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3A06B91C1103D900390FDD /* JITRightShiftGenerator.h */; };
                FE476FF4207E85D50093CA2D /* JITCodeMap.h in Headers */ = {isa = PBXBuildFile; fileRef = FE476FF3207E85D40093CA2D /* JITCodeMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               FE48BD4423245E9300F136D0 /* JSCConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = FE48BD4223245E8700F136D0 /* JSCConfig.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE48E6381EB118D2005D7A96 /* ObjectInitializationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FE48E6361EB1188F005D7A96 /* ObjectInitializationScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE4BFF2C1AD476E700088F87 /* FunctionOverrides.h in Headers */ = {isa = PBXBuildFile; fileRef = FE4BFF2A1AD476E700088F87 /* FunctionOverrides.h */; };
                FE4D55B81AE716CA0052E459 /* IterationStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = FE4D55B71AE716CA0052E459 /* IterationStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };
                        compilerSpec = com.apple.compilers.proxy.script;
                        filePatterns = "*.h";
                        fileType = pattern.proxy;
+                       inputFiles = (
+                       );
                        isEditable = 1;
                        outputFiles = (
                                "$(HEADER_OUTPUT_DIR)/$(INPUT_FILE_NAME)",
                FE35C2FA21B1E6C7000F4CA8 /* Options.rb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.ruby; path = Options.rb; sourceTree = "<group>"; };
                FE35C2FB21B1E6C7000F4CA8 /* OpcodeGroup.rb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.ruby; path = OpcodeGroup.rb; sourceTree = "<group>"; };
                FE35C2FC21B1E6C7000F4CA8 /* Metadata.rb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.ruby; path = Metadata.rb; sourceTree = "<group>"; };
+               FE3842302324D51A009DD445 /* OptionEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OptionEntry.h; sourceTree = "<group>"; };
+               FE3842312324D51B009DD445 /* OptionsList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OptionsList.h; sourceTree = "<group>"; };
                FE384EE11ADDB7AD0055DE2C /* JSDollarVM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDollarVM.cpp; sourceTree = "<group>"; };
                FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDollarVM.h; sourceTree = "<group>"; };
                FE3A06A31C10B70800390FDD /* JITBitOrGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITBitOrGenerator.cpp; sourceTree = "<group>"; };
                FE3A06B91C1103D900390FDD /* JITRightShiftGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITRightShiftGenerator.h; sourceTree = "<group>"; };
                FE42388F1BE18C1200514737 /* JITSubGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITSubGenerator.cpp; sourceTree = "<group>"; };
                FE476FF3207E85D40093CA2D /* JITCodeMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITCodeMap.h; sourceTree = "<group>"; };
+               FE48BD4223245E8700F136D0 /* JSCConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSCConfig.h; sourceTree = "<group>"; };
+               FE48BD4323245E8700F136D0 /* JSCConfig.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSCConfig.cpp; sourceTree = "<group>"; };
                FE48E6361EB1188F005D7A96 /* ObjectInitializationScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectInitializationScope.h; sourceTree = "<group>"; };
                FE48E6371EB118AD005D7A96 /* ObjectInitializationScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectInitializationScope.cpp; sourceTree = "<group>"; };
                FE4BFF291AD476E700088F87 /* FunctionOverrides.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionOverrides.cpp; sourceTree = "<group>"; };
                                868921C11F9C0CB7001159F6 /* JSBigInt.h */,
                                86FA9E8F142BBB2D001773B7 /* JSBoundFunction.cpp */,
                                86FA9E90142BBB2E001773B7 /* JSBoundFunction.h */,
+                               FE48BD4323245E8700F136D0 /* JSCConfig.cpp */,
+                               FE48BD4223245E8700F136D0 /* JSCConfig.h */,
                                657CF45619BF6662004ACBF2 /* JSCallee.cpp */,
                                657CF45719BF6662004ACBF2 /* JSCallee.h */,
                                53B601EB2034B8C5006BE667 /* JSCast.h */,
                                E39EEAF22281244C008474F4 /* ObjectToStringAdaptiveStructureWatchpoint.h */,
                                F692A8770255597D01FF60F7 /* Operations.cpp */,
                                F692A8780255597D01FF60F7 /* Operations.h */,
+                               FE3842302324D51A009DD445 /* OptionEntry.h */,
                                0FE228EA1436AB2300196C48 /* Options.cpp */,
                                0FE228EB1436AB2300196C48 /* Options.h */,
+                               FE3842312324D51B009DD445 /* OptionsList.h */,
                                37C738D11EDB5672003F2B0B /* ParseInt.h */,
                                868916A9155F285400CB2B9A /* PrivateName.h */,
                                147341DF1DC2CE9600AA29BA /* ProgramExecutable.cpp */,
                                0FEA0A10170513DB00BB722C /* FTLLowerDFGToB3.h in Headers */,
                                A7D89D0217A0B90400773AD8 /* FTLLoweredNodeValue.h in Headers */,
                                0F2B9CF919D0BAC100B1D1B5 /* FTLOperations.h in Headers */,
+                               FE3842322324D51B009DD445 /* OptionEntry.h in Headers */,
                                0FD8A31C17D51F2200CA2C40 /* FTLOSREntry.h in Headers */,
                                0F235BDD17178E1C00690C7F /* FTLOSRExit.h in Headers */,
                                0F235BE017178E1C00690C7F /* FTLOSRExitCompiler.h in Headers */,
                                A1D793011B43864B004516F5 /* IntlNumberFormatPrototype.h in Headers */,
                                A125846F1B45A36000CC7F6C /* IntlNumberFormatPrototype.lut.h in Headers */,
                                A12BBFF21B044A8B00664B69 /* IntlObject.h in Headers */,
+                               FE48BD4423245E9300F136D0 /* JSCConfig.h in Headers */,
                                708EBE241CE8F35800453146 /* IntlObjectInlines.h in Headers */,
                                860BD801148EA6F200112B2F /* Intrinsic.h in Headers */,
                                534E03541E53BD2900213F64 /* IntrinsicGetterAccessCase.h in Headers */,
                                0FE050281AA9095600D33B33 /* ScopedArguments.h in Headers */,
                                0FE050291AA9095600D33B33 /* ScopedArgumentsTable.h in Headers */,
                                0FE0502B1AA9095600D33B33 /* ScopeOffset.h in Headers */,
+                               FE3842332324D51B009DD445 /* OptionsList.h in Headers */,
                                0F24E55217EE274900ABB217 /* ScratchRegisterAllocator.h in Headers */,
                                A5FD0068189AFE9C00633231 /* ScriptArguments.h in Headers */,
                                A503FA21188EFF6800110F14 /* ScriptBreakpoint.h in Headers */,
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Production;
                };
-               14CFB10523035EF300F0048C /* Build configuration list */ = {
+               14CFB10523035EF300F0048C /* Build configuration list for PBXAggregateTarget "Unlock Keychain" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                14CFB10123035EF300F0048C /* Debug */,
index cd7d992..6a331d1 100644 (file)
@@ -733,7 +733,6 @@ runtime/CodeSpecializationKind.cpp
 runtime/CommonIdentifiers.cpp
 runtime/CommonSlowPaths.cpp
 runtime/CompilationResult.cpp
-tools/CompilerTimingScope.cpp
 runtime/Completion.cpp
 runtime/ConfigFile.cpp
 runtime/ConsoleClient.cpp
@@ -813,6 +812,7 @@ runtime/JSAsyncFunction.cpp
 runtime/JSAsyncGeneratorFunction.cpp
 runtime/JSBigInt.cpp
 runtime/JSBoundFunction.cpp
+runtime/JSCConfig.cpp
 runtime/JSCJSValue.cpp
 runtime/JSCPtrTag.cpp
 runtime/JSCallee.cpp
@@ -984,6 +984,7 @@ JSCBuiltins.cpp
 tools/CellList.cpp
 tools/CodeProfile.cpp
 tools/CodeProfiling.cpp
+tools/CompilerTimingScope.cpp
 tools/FunctionOverrides.cpp
 tools/FunctionWhitelist.cpp
 tools/HeapVerifier.cpp
index 36d7ccc..74c4fb5 100644 (file)
@@ -92,52 +92,41 @@ namespace JSC {
 using namespace WTF;
 
 #if defined(FIXED_EXECUTABLE_MEMORY_POOL_SIZE_IN_MB) && FIXED_EXECUTABLE_MEMORY_POOL_SIZE_IN_MB > 0
-static const size_t fixedExecutableMemoryPoolSize = FIXED_EXECUTABLE_MEMORY_POOL_SIZE_IN_MB * 1024 * 1024;
+static constexpr size_t fixedExecutableMemoryPoolSize = FIXED_EXECUTABLE_MEMORY_POOL_SIZE_IN_MB * 1024 * 1024;
 #elif CPU(ARM)
-static const size_t fixedExecutableMemoryPoolSize = 16 * 1024 * 1024;
+static constexpr size_t fixedExecutableMemoryPoolSize = 16 * 1024 * 1024;
 #elif CPU(ARM64)
-static const size_t fixedExecutableMemoryPoolSize = 128 * 1024 * 1024;
+static constexpr size_t fixedExecutableMemoryPoolSize = 128 * 1024 * 1024;
 #elif CPU(X86_64)
-static const size_t fixedExecutableMemoryPoolSize = 1024 * 1024 * 1024;
+static constexpr size_t fixedExecutableMemoryPoolSize = 1024 * 1024 * 1024;
 #else
-static const size_t fixedExecutableMemoryPoolSize = 32 * 1024 * 1024;
+static constexpr size_t fixedExecutableMemoryPoolSize = 32 * 1024 * 1024;
 #endif
 
 #if CPU(ARM)
-static const double executablePoolReservationFraction = 0.15;
+static constexpr double executablePoolReservationFraction = 0.15;
 #else
-static const double executablePoolReservationFraction = 0.25;
+static constexpr double executablePoolReservationFraction = 0.25;
 #endif
 
-#if ENABLE(SEPARATED_WX_HEAP)
-JS_EXPORT_PRIVATE bool useFastPermisionsJITCopy { false };
-JS_EXPORT_PRIVATE JITWriteSeparateHeapsFunction jitWriteSeparateHeapsFunction;
-#endif
-
-#if !USE(EXECUTE_ONLY_JIT_WRITE_FUNCTION) && HAVE(REMAP_JIT)
-static uintptr_t startOfFixedWritableMemoryPool;
-#endif
-
-class FixedVMPoolExecutableAllocator;
-static FixedVMPoolExecutableAllocator* allocator = nullptr;
-
-static bool s_isJITEnabled = true;
 static bool isJITEnabled()
 {
+    bool jitEnabled = !g_jscConfig.jitDisabled;
 #if PLATFORM(IOS_FAMILY) && (CPU(ARM64) || CPU(ARM))
-    return processHasEntitlement("dynamic-codesigning") && s_isJITEnabled;
+    return processHasEntitlement("dynamic-codesigning") && jitEnabled;
 #else
-    return s_isJITEnabled;
+    return jitEnabled;
 #endif
 }
 
 void ExecutableAllocator::setJITEnabled(bool enabled)
 {
-    ASSERT(!allocator);
-    if (s_isJITEnabled == enabled)
+    bool jitEnabled = !g_jscConfig.jitDisabled;
+    ASSERT(!g_jscConfig.fixedVMPoolExecutableAllocator);
+    if (jitEnabled == enabled)
         return;
 
-    s_isJITEnabled = enabled;
+    g_jscConfig.jitDisabled = !enabled;
 
 #if PLATFORM(IOS_FAMILY) && (CPU(ARM64) || CPU(ARM))
     if (!enabled) {
@@ -193,7 +182,7 @@ public:
 #else // not ENABLE(FAST_JIT_PERMISSIONS) or ENABLE(SEPARATED_WX_HEAP)
 #if ENABLE(FAST_JIT_PERMISSIONS)
             if (os_thread_self_restrict_rwx_is_supported()) {
-                useFastPermisionsJITCopy = true;
+                g_jscConfig.useFastPermisionsJITCopy = true;
                 os_thread_self_restrict_rwx_to_rx();
             } else
 #endif
@@ -212,15 +201,15 @@ public:
 
             void* reservationEnd = reinterpret_cast<uint8_t*>(reservationBase) + reservationSize;
 
-            m_memoryStart = MacroAssemblerCodePtr<ExecutableMemoryPtrTag>(tagCodePtr<ExecutableMemoryPtrTag>(reservationBase));
-            m_memoryEnd = MacroAssemblerCodePtr<ExecutableMemoryPtrTag>(tagCodePtr<ExecutableMemoryPtrTag>(reservationEnd));
+            g_jscConfig.startExecutableMemory = tagCodePtr<ExecutableMemoryPtrTag>(reservationBase);
+            g_jscConfig.endExecutableMemory = tagCodePtr<ExecutableMemoryPtrTag>(reservationEnd);
         }
     }
 
     virtual ~FixedVMPoolExecutableAllocator();
 
-    void* memoryStart() { return m_memoryStart.untaggedExecutableAddress(); }
-    void* memoryEnd() { return m_memoryEnd.untaggedExecutableAddress(); }
+    void* memoryStart() { return untagCodePtr<ExecutableMemoryPtrTag>(g_jscConfig.startExecutableMemory); }
+    void* memoryEnd() { return untagCodePtr<ExecutableMemoryPtrTag>(g_jscConfig.endExecutableMemory); }
     bool isJITPC(void* pc) { return memoryStart() <= pc && pc < memoryEnd(); }
 
 protected:
@@ -302,7 +291,7 @@ private:
         memset_s(&writableAddr, sizeof(writableAddr), 0, sizeof(writableAddr));
 
 #if ENABLE(SEPARATED_WX_HEAP)
-        jitWriteSeparateHeapsFunction = reinterpret_cast<JITWriteSeparateHeapsFunction>(writeThunk.code().executableAddress());
+        g_jscConfig.jitWriteSeparateHeaps = reinterpret_cast<JITWriteSeparateHeapsFunction>(writeThunk.code().executableAddress());
 #endif
     }
 
@@ -381,12 +370,12 @@ private:
 #else // not CPU(ARM64) && USE(EXECUTE_ONLY_JIT_WRITE_FUNCTION)
     static void genericWriteToJITRegion(off_t offset, const void* data, size_t dataSize)
     {
-        memcpy((void*)(startOfFixedWritableMemoryPool + offset), data, dataSize);
+        memcpy((void*)(g_jscConfig.startOfFixedWritableMemoryPool + offset), data, dataSize);
     }
 
     MacroAssemblerCodeRef<JITThunkPtrTag> jitWriteThunkGenerator(void* address, void*, size_t)
     {
-        startOfFixedWritableMemoryPool = reinterpret_cast<uintptr_t>(address);
+        g_jscConfig.startOfFixedWritableMemoryPool = reinterpret_cast<uintptr_t>(address);
         void* function = reinterpret_cast<void*>(&genericWriteToJITRegion);
 #if CPU(ARM_THUMB2)
         // Handle thumb offset
@@ -407,8 +396,6 @@ private:
 
 private:
     PageReservation m_reservation;
-    MacroAssemblerCodePtr<ExecutableMemoryPtrTag> m_memoryStart;
-    MacroAssemblerCodePtr<ExecutableMemoryPtrTag> m_memoryEnd;
 };
 
 FixedVMPoolExecutableAllocator::~FixedVMPoolExecutableAllocator()
@@ -418,13 +405,14 @@ FixedVMPoolExecutableAllocator::~FixedVMPoolExecutableAllocator()
 
 void ExecutableAllocator::initializeUnderlyingAllocator()
 {
-    ASSERT(!allocator);
-    allocator = new FixedVMPoolExecutableAllocator();
-    CodeProfiling::notifyAllocator(allocator);
+    RELEASE_ASSERT(!g_jscConfig.fixedVMPoolExecutableAllocator);
+    g_jscConfig.fixedVMPoolExecutableAllocator = new FixedVMPoolExecutableAllocator();
+    CodeProfiling::notifyAllocator(g_jscConfig.fixedVMPoolExecutableAllocator);
 }
 
 bool ExecutableAllocator::isValid() const
 {
+    auto* allocator = g_jscConfig.fixedVMPoolExecutableAllocator;
     if (!allocator)
         return Base::isValid();
     return !!allocator->bytesReserved();
@@ -432,6 +420,7 @@ bool ExecutableAllocator::isValid() const
 
 bool ExecutableAllocator::underMemoryPressure()
 {
+    auto* allocator = g_jscConfig.fixedVMPoolExecutableAllocator;
     if (!allocator)
         return Base::underMemoryPressure();
     return allocator->bytesAllocated() > allocator->bytesReserved() / 2;
@@ -439,6 +428,7 @@ bool ExecutableAllocator::underMemoryPressure()
 
 double ExecutableAllocator::memoryPressureMultiplier(size_t addedMemoryUsage)
 {
+    auto* allocator = g_jscConfig.fixedVMPoolExecutableAllocator;
     if (!allocator)
         return Base::memoryPressureMultiplier(addedMemoryUsage);
     ASSERT(allocator->bytesAllocated() <= allocator->bytesReserved());
@@ -458,6 +448,7 @@ double ExecutableAllocator::memoryPressureMultiplier(size_t addedMemoryUsage)
 
 RefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(size_t sizeInBytes, void* ownerUID, JITCompilationEffort effort)
 {
+    auto* allocator = g_jscConfig.fixedVMPoolExecutableAllocator;
     if (!allocator)
         return Base::allocate(sizeInBytes, ownerUID, effort);
     if (Options::logExecutableAllocation()) {
@@ -495,19 +486,18 @@ RefPtr<ExecutableMemoryHandle> ExecutableAllocator::allocate(size_t sizeInBytes,
         return nullptr;
     }
 
-#if CPU(ARM64E)
     void* start = allocator->memoryStart();
     void* end = allocator->memoryEnd();
     void* resultStart = result->start().untaggedPtr();
     void* resultEnd = result->end().untaggedPtr();
     RELEASE_ASSERT(start <= resultStart && resultStart < end);
     RELEASE_ASSERT(start < resultEnd && resultEnd <= end);
-#endif
     return result;
 }
 
 bool ExecutableAllocator::isValidExecutableMemory(const AbstractLocker& locker, void* address)
 {
+    auto* allocator = g_jscConfig.fixedVMPoolExecutableAllocator;
     if (!allocator)
         return Base::isValidExecutableMemory(locker, address);
     return allocator->isInAllocatedMemory(locker, address);
@@ -515,6 +505,7 @@ bool ExecutableAllocator::isValidExecutableMemory(const AbstractLocker& locker,
 
 Lock& ExecutableAllocator::getLock() const
 {
+    auto* allocator = g_jscConfig.fixedVMPoolExecutableAllocator;
     if (!allocator)
         return Base::getLock();
     return allocator->getLock();
@@ -522,6 +513,7 @@ Lock& ExecutableAllocator::getLock() const
 
 size_t ExecutableAllocator::committedByteCount()
 {
+    auto* allocator = g_jscConfig.fixedVMPoolExecutableAllocator;
     if (!allocator)
         return Base::committedByteCount();
     return allocator->bytesCommitted();
@@ -530,6 +522,7 @@ size_t ExecutableAllocator::committedByteCount()
 #if ENABLE(META_ALLOCATOR_PROFILE)
 void ExecutableAllocator::dumpProfile()
 {
+    auto* allocator = g_jscConfig.fixedVMPoolExecutableAllocator;
     if (!allocator)
         return;
     allocator->dumpProfile();
@@ -538,6 +531,7 @@ void ExecutableAllocator::dumpProfile()
 
 void* startOfFixedExecutableMemoryPoolImpl()
 {
+    auto* allocator = g_jscConfig.fixedVMPoolExecutableAllocator;
     if (!allocator)
         return nullptr;
     return allocator->memoryStart();
@@ -545,6 +539,7 @@ void* startOfFixedExecutableMemoryPoolImpl()
 
 void* endOfFixedExecutableMemoryPoolImpl()
 {
+    auto* allocator = g_jscConfig.fixedVMPoolExecutableAllocator;
     if (!allocator)
         return nullptr;
     return allocator->memoryEnd();
@@ -552,12 +547,13 @@ void* endOfFixedExecutableMemoryPoolImpl()
 
 bool isJITPC(void* pc)
 {
+    auto* allocator = g_jscConfig.fixedVMPoolExecutableAllocator;
     return allocator && allocator->isJITPC(pc);
 }
 
 void dumpJITMemory(const void* dst, const void* src, size_t size)
 {
-    ASSERT(Options::dumpJITMemoryPath());
+    RELEASE_ASSERT(Options::dumpJITMemoryPath());
 
 #if OS(DARWIN)
     static int fd = -1;
@@ -635,17 +631,15 @@ void dumpJITMemory(const void* dst, const void* src, size_t size)
 
 namespace JSC {
 
-static ExecutableAllocator* executableAllocator;
-
 void ExecutableAllocator::initialize()
 {
-    executableAllocator = new ExecutableAllocator;
+    g_jscConfig.executableAllocator = new ExecutableAllocator;
 }
 
 ExecutableAllocator& ExecutableAllocator::singleton()
 {
-    ASSERT(executableAllocator);
-    return *executableAllocator;
+    ASSERT(g_jscConfig.executableAllocator);
+    return *g_jscConfig.executableAllocator;
 }
 
 } // namespace JSC
index d451eaf..71b4498 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "JITCompilationEffort.h"
+#include "JSCConfig.h"
 #include "JSCPtrTag.h"
 #include "Options.h"
 #include <stddef.h> // for ptrdiff_t
@@ -115,14 +116,6 @@ JS_EXPORT_PRIVATE bool isJITPC(void* pc);
 
 JS_EXPORT_PRIVATE void dumpJITMemory(const void*, const void*, size_t);
 
-#if ENABLE(SEPARATED_WX_HEAP)
-
-typedef void (*JITWriteSeparateHeapsFunction)(off_t, const void*, size_t);
-extern JS_EXPORT_PRIVATE JITWriteSeparateHeapsFunction jitWriteSeparateHeapsFunction;
-extern JS_EXPORT_PRIVATE bool useFastPermisionsJITCopy;
-
-#endif // ENABLE(SEPARATED_WX_HEAP)
-
 static ALWAYS_INLINE void* performJITMemcpy(void *dst, const void *src, size_t n)
 {
     RELEASE_ASSERT(!Gigacage::contains(src));
@@ -138,7 +131,7 @@ static ALWAYS_INLINE void* performJITMemcpy(void *dst, const void *src, size_t n
             dumpJITMemory(dst, src, n);
 #if ENABLE(FAST_JIT_PERMISSIONS)
 #if ENABLE(SEPARATED_WX_HEAP)
-        if (useFastPermisionsJITCopy)
+        if (g_jscConfig.useFastPermisionsJITCopy)
 #endif
         {
             os_thread_self_restrict_rwx_to_rw();
@@ -149,11 +142,11 @@ static ALWAYS_INLINE void* performJITMemcpy(void *dst, const void *src, size_t n
 #endif // ENABLE(FAST_JIT_PERMISSIONS)
 
 #if ENABLE(SEPARATED_WX_HEAP)
-        if (jitWriteSeparateHeapsFunction) {
+        if (g_jscConfig.jitWriteSeparateHeaps) {
             // Use execute-only write thunk for writes inside the JIT region. This is a variant of
             // memcpy that takes an offset into the JIT region as its destination (first) parameter.
             off_t offset = (off_t)((uintptr_t)dst - startOfFixedExecutableMemoryPool<uintptr_t>());
-            retagCodePtr<JITThunkPtrTag, CFunctionPtrTag>(jitWriteSeparateHeapsFunction)(offset, src, n);
+            retagCodePtr<JITThunkPtrTag, CFunctionPtrTag>(g_jscConfig.jitWriteSeparateHeaps)(offset, src, n);
             return dst;
         }
 #endif
index 927c75c..4db0480 100644 (file)
@@ -301,7 +301,6 @@ static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionGCAndSweep(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionFullGC(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState*);
-static EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionCreateMemoryFootprint(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionResetMemoryPeak(ExecState*);
@@ -520,7 +519,6 @@ protected:
         addFunction(vm, "gc", functionGCAndSweep, 0);
         addFunction(vm, "fullGC", functionFullGC, 0);
         addFunction(vm, "edenGC", functionEdenGC, 0);
-        addFunction(vm, "forceGCSlowPaths", functionForceGCSlowPaths, 0);
         addFunction(vm, "gcHeapSize", functionHeapSize, 0);
         addFunction(vm, "MemoryFootprint", functionCreateMemoryFootprint, 0);
         addFunction(vm, "resetMemoryPeak", functionResetMemoryPeak, 0);
@@ -1370,14 +1368,6 @@ EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
     return JSValue::encode(jsNumber(vm.heap.sizeAfterLastEdenCollection()));
 }
 
-EncodedJSValue JSC_HOST_CALL functionForceGCSlowPaths(ExecState*)
-{
-    // It's best for this to be the first thing called in the 
-    // JS program so the option is set to true before we JIT.
-    Options::forceGCSlowPaths() = true;
-    return JSValue::encode(jsUndefined());
-}
-
 EncodedJSValue JSC_HOST_CALL functionHeapSize(ExecState* exec)
 {
     VM& vm = exec->vm();
@@ -2123,10 +2113,10 @@ EncodedJSValue JSC_HOST_CALL functionJSCOptions(ExecState* exec)
 {
     VM& vm = exec->vm();
     JSObject* optionsObject = constructEmptyObject(exec);
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
+#define READ_OPTION(type_, name_, defaultValue_, availability_, description_) \
     addOption(vm, optionsObject, Identifier::fromString(vm, #name_), Options::name_());
-    JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+    FOR_EACH_JSC_OPTION(READ_OPTION)
+#undef READ_OPTION
     return JSValue::encode(optionsObject);
 }
 
@@ -3098,7 +3088,7 @@ int runJSC(const CommandLine& options, bool isWorker, const Func& func)
 int jscmain(int argc, char** argv)
 {
     // Need to override and enable restricted options before we start parsing options below.
-    Options::enableRestrictedOptions(true);
+    Config::enableRestrictedOptions();
 
     WTF::initializeMainThread();
 
index 1c05e4b..719ab70 100644 (file)
@@ -465,7 +465,7 @@ void ConfigFile::parse()
             WTF::setDataFile(logPathname);
 
         if (!jscOptionsBuilder.isEmpty()) {
-            Options::enableRestrictedOptions(true);
+            JSC::Config::enableRestrictedOptions();
             Options::setOptions(jscOptionsBuilder.toString().utf8().data());
         }
     } else
index f3b437d..1fd59f4 100644 (file)
@@ -33,6 +33,7 @@
 #include "ExecutableAllocator.h"
 #include "Heap.h"
 #include "Identifier.h"
+#include "JSCConfig.h"
 #include "JSCPtrTag.h"
 #include "JSDateMath.h"
 #include "JSGlobalObject.h"
@@ -62,6 +63,9 @@ void initializeThreading()
     static std::once_flag initializeThreadingOnceFlag;
 
     std::call_once(initializeThreadingOnceFlag, []{
+        RELEASE_ASSERT(!g_jscConfig.initializeThreadingHasBeenCalled);
+        g_jscConfig.initializeThreadingHasBeenCalled = true;
+
         WTF::initializeThreading();
         Options::initialize();
 
diff --git a/Source/JavaScriptCore/runtime/JSCConfig.cpp b/Source/JavaScriptCore/runtime/JSCConfig.cpp
new file mode 100644 (file)
index 0000000..01e0e63
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSCConfig.h"
+
+#include <wtf/ResourceUsage.h>
+#include <wtf/StdLibExtras.h>
+
+#if OS(DARWIN)
+#include <mach/mach.h>
+#elif OS(LINUX)
+#include <sys/mman.h>
+#endif
+
+namespace JSC {
+
+alignas(PageSize) JS_EXPORT_PRIVATE Config g_jscConfig;
+
+void Config::disableFreezingForTesting()
+{
+    RELEASE_ASSERT(!g_jscConfig.isPermanentlyFrozen);
+    g_jscConfig.disabledFreezingForTesting = true;
+}
+
+void Config::enableRestrictedOptions()
+{
+    RELEASE_ASSERT(!g_jscConfig.isPermanentlyFrozen);
+    g_jscConfig.restrictedOptionsEnabled = true;
+}
+    
+void Config::permanentlyFreeze()
+{
+#if PLATFORM(COCOA)
+    RELEASE_ASSERT(roundUpToMultipleOf(vmPageSize(), ConfigSizeToProtect) == ConfigSizeToProtect);
+#endif
+
+    if (!g_jscConfig.isPermanentlyFrozen)
+        g_jscConfig.isPermanentlyFrozen = true;
+
+    int result = 0;
+#if OS(DARWIN)
+    enum {
+        AllowPermissionChangesAfterThis = false,
+        DisallowPermissionChangesAfterThis = true
+    };
+
+    // There's no going back now!
+    result = vm_protect(mach_task_self(), reinterpret_cast<vm_address_t>(&g_jscConfig), ConfigSizeToProtect, DisallowPermissionChangesAfterThis, VM_PROT_READ);
+#elif OS(LINUX)
+    result = mprotect(&g_jscConfig, ConfigSizeToProtect, PROT_READ);
+#elif OS(WINDOWS)
+    // FIXME: Implement equivalent, maybe with VirtualProtect.
+    // Also need to fix WebKitTestRunner.
+#endif
+    RELEASE_ASSERT(!result);
+    RELEASE_ASSERT(g_jscConfig.isPermanentlyFrozen);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSCConfig.h b/Source/JavaScriptCore/runtime/JSCConfig.h
new file mode 100644 (file)
index 0000000..0f52bac
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "OptionEntry.h"
+#include "OptionsList.h"
+#include <wtf/StdLibExtras.h>
+
+namespace JSC {
+
+class ExecutableAllocator;
+class FixedVMPoolExecutableAllocator;
+
+#if CPU(ARM64)
+constexpr size_t PageSize = 16 * KB;
+#else
+constexpr size_t PageSize = 4 * KB;
+#endif
+
+constexpr size_t ConfigSizeToProtect = 16 * KB;
+
+#if ENABLE(SEPARATED_WX_HEAP)
+using JITWriteSeparateHeapsFunction = void (*)(off_t, const void*, size_t);
+#endif
+
+struct Config {
+    JS_EXPORT_PRIVATE static void disableFreezingForTesting();
+    JS_EXPORT_PRIVATE static void enableRestrictedOptions();
+    JS_EXPORT_PRIVATE static void permanentlyFreeze();
+
+    static void configureForTesting()
+    {
+        disableFreezingForTesting();
+        enableRestrictedOptions();
+    }
+
+    union {
+        struct {
+            // All the fields in this struct should be chosen such that their
+            // initial value is 0 / null / falsy because Config is instantiated
+            // as a global singleton.
+
+            bool isPermanentlyFrozen;
+            bool disabledFreezingForTesting;
+            bool restrictedOptionsEnabled;
+            bool jitDisabled;
+
+            // The following HasBeenCalled flags are for auditing call_once initialization functions.
+            bool initializeThreadingHasBeenCalled;
+
+            ExecutableAllocator* executableAllocator;
+            FixedVMPoolExecutableAllocator* fixedVMPoolExecutableAllocator;
+            void* startExecutableMemory;
+            void* endExecutableMemory;
+            uintptr_t startOfFixedWritableMemoryPool;
+
+#if ENABLE(SEPARATED_WX_HEAP)
+            JITWriteSeparateHeapsFunction jitWriteSeparateHeaps;
+            bool useFastPermisionsJITCopy;
+#endif
+
+            OptionEntry options[NumberOfOptions];
+            OptionEntry defaultOptions[NumberOfOptions];
+        };
+        char ensureSize[ConfigSizeToProtect];
+    };
+};
+
+extern "C" alignas(PageSize) JS_EXPORT_PRIVATE Config g_jscConfig;
+
+static_assert(sizeof(Config) == ConfigSizeToProtect, "");
+static_assert(roundUpToMultipleOf<PageSize>(ConfigSizeToProtect) == ConfigSizeToProtect, "");
+
+} // namespace JSC
index c6ab86b..aa73fc5 100644 (file)
@@ -1822,6 +1822,7 @@ ExecState* JSGlobalObject::globalExec()
 
 void JSGlobalObject::exposeDollarVM(VM& vm)
 {
+    RELEASE_ASSERT(g_jscConfig.restrictedOptionsEnabled && Options::useDollarVM());
     if (hasOwnProperty(globalExec(), vm.propertyNames->builtinNames().dollarVMPrivateName()))
         return;
 
diff --git a/Source/JavaScriptCore/runtime/OptionEntry.h b/Source/JavaScriptCore/runtime/OptionEntry.h
new file mode 100644 (file)
index 0000000..3bd6ccc
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "GCLogging.h"
+#include <wtf/PrintStream.h>
+
+namespace JSC {
+
+class OptionRange {
+private:
+    enum RangeState { Uninitialized, InitError, Normal, Inverted };
+public:
+    OptionRange& operator= (const int& rhs)
+    { // Only needed for initialization
+        if (!rhs) {
+            m_state = Uninitialized;
+            m_rangeString = 0;
+            m_lowLimit = 0;
+            m_highLimit = 0;
+        }
+        return *this;
+    }
+
+    bool init(const char*);
+    bool isInRange(unsigned);
+    const char* rangeString() const { return (m_state > InitError) ? m_rangeString : s_nullRangeStr; }
+    
+    void dump(PrintStream& out) const;
+
+private:
+    static const char* const s_nullRangeStr;
+
+    RangeState m_state;
+    const char* m_rangeString;
+    unsigned m_lowLimit;
+    unsigned m_highLimit;
+};
+
+// For storing for an option value:
+union OptionEntry {
+    using Bool = bool;
+    using Unsigned = unsigned;
+    using Double = double;
+    using Int32 = int32_t;
+    using Size = size_t;
+    using OptionRange = JSC::OptionRange;
+    using OptionString = const char*;
+    using GCLogLevel = GCLogging::Level;
+
+    bool valBool;
+    unsigned valUnsigned;
+    double valDouble;
+    int32_t valInt32;
+    size_t valSize;
+    OptionRange valOptionRange;
+    const char* valOptionString;
+    GCLogging::Level valGCLogLevel;
+};
+
+} // namespace JSC
index b30a7c5..b0a242b 100644 (file)
 
 namespace JSC {
 
-namespace {
-#ifdef NDEBUG
-bool restrictedOptionsEnabled = false;
-#else
-bool restrictedOptionsEnabled = true;
-#endif
-}
-
-void Options::enableRestrictedOptions(bool enableOrNot)
-{
-    restrictedOptionsEnabled = enableOrNot;
-}
-    
 static bool parse(const char* string, bool& value)
 {
     if (equalLettersIgnoringASCIICase(string, "true") || equalLettersIgnoringASCIICase(string, "yes") || !strcmp(string, "1")) {
@@ -148,7 +135,7 @@ static bool parse(const char* string, GCLogging::Level& value)
 bool Options::isAvailable(Options::ID id, Options::Availability availability)
 {
     if (availability == Availability::Restricted)
-        return restrictedOptionsEnabled;
+        return g_jscConfig.restrictedOptionsEnabled;
     ASSERT(availability == Availability::Configurable);
     
     UNUSED_PARAM(id);
@@ -295,15 +282,12 @@ void OptionRange::dump(PrintStream& out) const
     out.print(m_rangeString);
 }
 
-Options::Entry Options::s_options[Options::numberOfOptions];
-Options::Entry Options::s_defaultOptions[Options::numberOfOptions];
-
 // Realize the names for each of the options:
 const Options::EntryInfo Options::s_optionsInfo[Options::numberOfOptions] = {
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
-    { #name_, description_, Options::Type::type_##Type, Availability::availability_ },
-    JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+#define FILL_OPTION_INFO(type_, name_, defaultValue_, availability_, description_) \
+    { #name_, description_, Options::Type::type_, Availability::availability_ },
+    FOR_EACH_JSC_OPTION(FILL_OPTION_INFO)
+#undef FILL_OPTION_INFO
 };
 
 static void scaleJITPolicy()
@@ -332,7 +316,7 @@ static void scaleJITPolicy()
     const int numberOfOptionsToScale = sizeof(optionsToScale) / sizeof(OptionToScale);
     for (int i = 0; i < numberOfOptionsToScale; i++) {
         Option option(optionsToScale[i].id);
-        ASSERT(option.type() == Options::Type::int32Type);
+        ASSERT(option.type() == Options::Type::Int32);
         option.int32Val() *= scaleFactor;
         option.int32Val() = std::max(option.int32Val(), optionsToScale[i].minVal);
     }
@@ -529,12 +513,15 @@ void Options::initialize()
     std::call_once(
         initializeOptionsOnceFlag,
         [] {
+#ifndef NDEBUG
+            Config::enableRestrictedOptions();
+#endif
             // Initialize each of the options with their default values:
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
-            name_() = defaultValue_;                                    \
+#define INIT_OPTION(type_, name_, defaultValue_, availability_, description_) \
+            name_() = defaultValue_; \
             name_##Default() = defaultValue_;
-            JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+            FOR_EACH_JSC_OPTION(INIT_OPTION)
+#undef INIT_OPTION
 
             overrideDefaults();
                 
@@ -555,16 +542,16 @@ void Options::initialize()
             if (hasBadOptions && Options::validateOptions())
                 CRASH();
 #else // PLATFORM(COCOA)
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
+#define OVERRIDE_OPTION_WITH_HEURISTICS(type_, name_, defaultValue_, availability_, description_) \
             overrideOptionWithHeuristic(name_(), name_##ID, "JSC_" #name_, Availability::availability_);
-            JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+            FOR_EACH_JSC_OPTION(OVERRIDE_OPTION_WITH_HEURISTICS)
+#undef OVERRIDE_OPTION_WITH_HEURISTICS
 #endif // PLATFORM(COCOA)
 
-#define FOR_EACH_OPTION(aliasedName_, unaliasedName_, equivalence_) \
+#define OVERRIDE_ALIASED_OPTION_WITH_HEURISTICS(aliasedName_, unaliasedName_, equivalence_) \
             overrideAliasedOptionWithHeuristic("JSC_" #aliasedName_);
-            JSC_ALIASED_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+            FOR_EACH_JSC_ALIASED_OPTION(OVERRIDE_ALIASED_OPTION_WITH_HEURISTICS)
+#undef OVERRIDE_ALIASED_OPTION_WITH_HEURISTICS
 
 #if 0
                 ; // Deconfuse editors that do auto indentation
@@ -642,6 +629,7 @@ static bool isSeparator(char c)
 
 bool Options::setOptions(const char* optionsStr)
 {
+    RELEASE_ASSERT(!g_jscConfig.isPermanentlyFrozen);
     Vector<char*> options;
 
     size_t length = strlen(optionsStr);
@@ -736,13 +724,13 @@ bool Options::setOptionWithoutAlias(const char* arg)
 
     // For each option, check if the specify arg is a match. If so, set the arg
     // if the value makes sense. Otherwise, move on to checking the next option.
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
+#define SET_OPTION_IF_MATCH(type_, name_, defaultValue_, availability_, description_) \
     if (strlen(#name_) == static_cast<size_t>(equalStr - arg)      \
         && !strncmp(arg, #name_, equalStr - arg)) {                \
         if (Availability::availability_ != Availability::Normal     \
             && !isAvailable(name_##ID, Availability::availability_)) \
             return false;                                          \
-        type_ value;                                               \
+        OptionEntry::type_ value;                                  \
         value = (defaultValue_);                                   \
         bool success = parse(valueStr, value);                     \
         if (success) {                                             \
@@ -754,8 +742,8 @@ bool Options::setOptionWithoutAlias(const char* arg)
         return false;                                              \
     }
 
-    JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+    FOR_EACH_JSC_OPTION(SET_OPTION_IF_MATCH)
+#undef SET_OPTION_IF_MATCH
 
     return false; // No option matched.
 }
@@ -798,7 +786,7 @@ bool Options::setAliasedOption(const char* arg)
         return setOptionWithoutAlias(unaliasedOption.utf8().data());   \
     }
 
-    JSC_ALIASED_OPTIONS(FOR_EACH_OPTION)
+    FOR_EACH_JSC_ALIASED_OPTION(FOR_EACH_OPTION)
 #undef FOR_EACH_OPTION
 
     IGNORE_WARNINGS_END
@@ -890,26 +878,26 @@ void Options::ensureOptionsAreCoherent()
 void Option::dump(StringBuilder& builder) const
 {
     switch (type()) {
-    case Options::Type::boolType:
-        builder.append(m_entry.boolVal ? "true" : "false");
+    case Options::Type::Bool:
+        builder.append(m_entry.valBool ? "true" : "false");
         break;
-    case Options::Type::unsignedType:
-        builder.appendNumber(m_entry.unsignedVal);
+    case Options::Type::Unsigned:
+        builder.appendNumber(m_entry.valUnsigned);
         break;
-    case Options::Type::sizeType:
-        builder.appendNumber(m_entry.sizeVal);
+    case Options::Type::Size:
+        builder.appendNumber(m_entry.valSize);
         break;
-    case Options::Type::doubleType:
-        builder.appendFixedPrecisionNumber(m_entry.doubleVal);
+    case Options::Type::Double:
+        builder.appendFixedPrecisionNumber(m_entry.valDouble);
         break;
-    case Options::Type::int32Type:
-        builder.appendNumber(m_entry.int32Val);
+    case Options::Type::Int32:
+        builder.appendNumber(m_entry.valInt32);
         break;
-    case Options::Type::optionRangeType:
-        builder.append(m_entry.optionRangeVal.rangeString());
+    case Options::Type::OptionRange:
+        builder.append(m_entry.valOptionRange.rangeString());
         break;
-    case Options::Type::optionStringType: {
-        const char* option = m_entry.optionStringVal;
+    case Options::Type::OptionString: {
+        const char* option = m_entry.valOptionString;
         if (!option)
             option = "";
         builder.append('"');
@@ -917,8 +905,8 @@ void Option::dump(StringBuilder& builder) const
         builder.append('"');
         break;
     }
-    case Options::Type::gcLogLevelType: {
-        builder.append(GCLogging::levelAsString(m_entry.gcLogLevelVal));
+    case Options::Type::GCLogLevel: {
+        builder.append(GCLogging::levelAsString(m_entry.valGCLogLevel));
         break;
     }
     }
@@ -927,26 +915,25 @@ void Option::dump(StringBuilder& builder) const
 bool Option::operator==(const Option& other) const
 {
     switch (type()) {
-    case Options::Type::boolType:
-        return m_entry.boolVal == other.m_entry.boolVal;
-    case Options::Type::unsignedType:
-        return m_entry.unsignedVal == other.m_entry.unsignedVal;
-    case Options::Type::sizeType:
-        return m_entry.sizeVal == other.m_entry.sizeVal;
-    case Options::Type::doubleType:
-        return (m_entry.doubleVal == other.m_entry.doubleVal) || (std::isnan(m_entry.doubleVal) && std::isnan(other.m_entry.doubleVal));
-    case Options::Type::int32Type:
-        return m_entry.int32Val == other.m_entry.int32Val;
-    case Options::Type::optionRangeType:
-        return m_entry.optionRangeVal.rangeString() == other.m_entry.optionRangeVal.rangeString();
-    case Options::Type::optionStringType:
-        return (m_entry.optionStringVal == other.m_entry.optionStringVal)
-            || (m_entry.optionStringVal && other.m_entry.optionStringVal && !strcmp(m_entry.optionStringVal, other.m_entry.optionStringVal));
-    case Options::Type::gcLogLevelType:
-        return m_entry.gcLogLevelVal == other.m_entry.gcLogLevelVal;
+    case Options::Type::Bool:
+        return m_entry.valBool == other.m_entry.valBool;
+    case Options::Type::Unsigned:
+        return m_entry.valUnsigned == other.m_entry.valUnsigned;
+    case Options::Type::Size:
+        return m_entry.valSize == other.m_entry.valSize;
+    case Options::Type::Double:
+        return (m_entry.valDouble == other.m_entry.valDouble) || (std::isnan(m_entry.valDouble) && std::isnan(other.m_entry.valDouble));
+    case Options::Type::Int32:
+        return m_entry.valInt32 == other.m_entry.valInt32;
+    case Options::Type::OptionRange:
+        return m_entry.valOptionRange.rangeString() == other.m_entry.valOptionRange.rangeString();
+    case Options::Type::OptionString:
+        return (m_entry.valOptionString == other.m_entry.valOptionString)
+            || (m_entry.valOptionString && other.m_entry.valOptionString && !strcmp(m_entry.valOptionString, other.m_entry.valOptionString));
+    case Options::Type::GCLogLevel:
+        return m_entry.valGCLogLevel == other.m_entry.valGCLogLevel;
     }
     return false;
 }
 
 } // namespace JSC
-
index 44fbc30..03ad2a0 100644 (file)
@@ -25,7 +25,7 @@
 
 #pragma once
 
-#include "GCLogging.h"
+#include "JSCConfig.h"
 #include "JSExportMacros.h"
 #include <stdint.h>
 #include <stdio.h>
@@ -41,12 +41,12 @@ namespace JSC {
 
 // How do JSC VM options work?
 // ===========================
-// The JSC_OPTIONS() macro below defines a list of all JSC options in use,
+// The FOR_EACH_JSC_OPTION() macro below defines a list of all JSC options in use,
 // along with their types and default values. The options values are actually
-// realized as an array of Options::Entry elements.
+// realized as an array of OptionEntry elements in JSC::Config.
 //
 //     Options::initialize() will initialize the array of options values with
-// the defaults specified in JSC_OPTIONS() below. After that, the values can
+// the defaults specified in FOR_EACH_JSC_OPTION() below. After that, the values can
 // be programmatically read and written to using an accessor method with the
 // same name as the option. For example, the option "useJIT" can be read and
 // set like so:
@@ -67,39 +67,6 @@ namespace JSC {
 // values after the sanity checks (for your own testing), then you're liable to
 // ensure that the new values set are sane and reasonable for your own run.
 
-class OptionRange {
-private:
-    enum RangeState { Uninitialized, InitError, Normal, Inverted };
-public:
-    OptionRange& operator= (const int& rhs)
-    { // Only needed for initialization
-        if (!rhs) {
-            m_state = Uninitialized;
-            m_rangeString = 0;
-            m_lowLimit = 0;
-            m_highLimit = 0;
-        }
-        return *this;
-    }
-
-    bool init(const char*);
-    bool isInRange(unsigned);
-    const char* rangeString() const { return (m_state > InitError) ? m_rangeString : s_nullRangeStr; }
-    
-    void dump(PrintStream& out) const;
-
-private:
-    static const char* const s_nullRangeStr;
-
-    RangeState m_state;
-    const char* m_rangeString;
-    unsigned m_lowLimit;
-    unsigned m_highLimit;
-};
-
-typedef OptionRange optionRange;
-typedef const char* optionString;
-
 #if PLATFORM(IOS_FAMILY)
 #define MAXIMUM_NUMBER_OF_FTL_COMPILER_THREADS 2
 #else
@@ -112,456 +79,6 @@ constexpr bool enableWebAssemblyStreamingApi = true;
 constexpr bool enableWebAssemblyStreamingApi = false;
 #endif
 
-#define JSC_OPTIONS(v) \
-    v(bool, useKernTCSM, true, Normal, "Note: this needs to go before other options since they depend on this value.") \
-    v(bool, validateOptions, false, Normal, "crashes if mis-typed JSC options were passed to the VM") \
-    v(unsigned, dumpOptions, 0, Normal, "dumps JSC options (0 = None, 1 = Overridden only, 2 = All, 3 = Verbose)") \
-    v(optionString, configFile, nullptr, Normal, "file to configure JSC options and logging location") \
-    \
-    v(bool, useLLInt,  true, Normal, "allows the LLINT to be used if true") \
-    v(bool, useJIT, jitEnabledByDefault(), Normal, "allows the executable pages to be allocated for JIT and thunks if true") \
-    v(bool, useBaselineJIT, true, Normal, "allows the baseline JIT to be used if true") \
-    v(bool, useDFGJIT, true, Normal, "allows the DFG JIT to be used if true") \
-    v(bool, useRegExpJIT, jitEnabledByDefault(), Normal, "allows the RegExp JIT to be used if true") \
-    v(bool, useDOMJIT, is64Bit(), Normal, "allows the DOMJIT to be used if true") \
-    \
-    v(bool, reportMustSucceedExecutableAllocations, false, Normal, nullptr) \
-    \
-    v(unsigned, maxPerThreadStackUsage, 4 * MB, Normal, "Max allowed stack usage by the VM") \
-    v(unsigned, softReservedZoneSize, 128 * KB, Normal, "A buffer greater than reservedZoneSize that reserves space for stringifying exceptions.") \
-    v(unsigned, reservedZoneSize, 64 * KB, Normal, "The amount of stack space we guarantee to our clients (and to interal VM code that does not call out to clients).") \
-    \
-    v(bool, crashIfCantAllocateJITMemory, false, Normal, nullptr) \
-    v(unsigned, jitMemoryReservationSize, 0, Normal, "Set this number to change the executable allocation size in ExecutableAllocatorFixedVMPool. (In bytes.)") \
-    v(bool, useSeparatedWXHeap, false, Normal, nullptr) \
-    \
-    v(bool, forceCodeBlockLiveness, false, Normal, nullptr) \
-    v(bool, forceICFailure, false, Normal, nullptr) \
-    \
-    v(unsigned, repatchCountForCoolDown, 8, Normal, nullptr) \
-    v(unsigned, initialCoolDownCount, 20, Normal, nullptr) \
-    v(unsigned, repatchBufferingCountdown, 8, Normal, nullptr) \
-    \
-    v(bool, dumpGeneratedBytecodes, false, Normal, nullptr) \
-    v(bool, dumpBytecodeLivenessResults, false, Normal, nullptr) \
-    v(bool, validateBytecode, false, Normal, nullptr) \
-    v(bool, forceDebuggerBytecodeGeneration, false, Normal, nullptr) \
-    v(bool, dumpBytecodesBeforeGeneratorification, false, Normal, nullptr) \
-    \
-    v(bool, useFunctionDotArguments, true, Normal, nullptr) \
-    v(bool, useTailCalls, true, Normal, nullptr) \
-    v(bool, optimizeRecursiveTailCalls, true, Normal, nullptr) \
-    v(bool, alwaysUseShadowChicken, false, Normal, nullptr) \
-    v(unsigned, shadowChickenLogSize, 1000, Normal, nullptr) \
-    v(unsigned, shadowChickenMaxTailDeletedFramesSize, 128, Normal, nullptr) \
-    \
-    /* dumpDisassembly implies dumpDFGDisassembly. */ \
-    v(bool, dumpDisassembly, false, Normal, "dumps disassembly of all JIT compiled code upon compilation") \
-    v(bool, asyncDisassembly, false, Normal, nullptr) \
-    v(bool, dumpDFGDisassembly, false, Normal, "dumps disassembly of DFG function upon compilation") \
-    v(bool, dumpFTLDisassembly, false, Normal, "dumps disassembly of FTL function upon compilation") \
-    v(bool, dumpRegExpDisassembly, false, Normal, "dumps disassembly of RegExp upon compilation") \
-    v(bool, dumpAllDFGNodes, false, Normal, nullptr) \
-    v(bool, logJITCodeForPerf, false, Configurable, nullptr) \
-    v(optionRange, bytecodeRangeToJITCompile, 0, Normal, "bytecode size range to allow compilation on, e.g. 1:100") \
-    v(optionRange, bytecodeRangeToDFGCompile, 0, Normal, "bytecode size range to allow DFG compilation on, e.g. 1:100") \
-    v(optionRange, bytecodeRangeToFTLCompile, 0, Normal, "bytecode size range to allow FTL compilation on, e.g. 1:100") \
-    v(optionString, jitWhitelist, nullptr, Normal, "file with list of function signatures to allow compilation on") \
-    v(optionString, dfgWhitelist, nullptr, Normal, "file with list of function signatures to allow DFG compilation on") \
-    v(optionString, ftlWhitelist, nullptr, Normal, "file with list of function signatures to allow FTL compilation on") \
-    v(bool, dumpSourceAtDFGTime, false, Normal, "dumps source code of JS function being DFG compiled") \
-    v(bool, dumpBytecodeAtDFGTime, false, Normal, "dumps bytecode of JS function being DFG compiled") \
-    v(bool, dumpGraphAfterParsing, false, Normal, nullptr) \
-    v(bool, dumpGraphAtEachPhase, false, Normal, nullptr) \
-    v(bool, dumpDFGGraphAtEachPhase, false, Normal, "dumps the DFG graph at each phase of DFG compilation (note this excludes DFG graphs during FTL compilation)") \
-    v(bool, dumpDFGFTLGraphAtEachPhase, false, Normal, "dumps the DFG graph at each phase of DFG compilation when compiling FTL code") \
-    v(bool, dumpB3GraphAtEachPhase, false, Normal, "dumps the B3 graph at each phase of compilation") \
-    v(bool, dumpAirGraphAtEachPhase, false, Normal, "dumps the Air graph at each phase of compilation") \
-    v(bool, verboseDFGBytecodeParsing, false, Normal, nullptr) \
-    v(bool, safepointBeforeEachPhase, true, Normal, nullptr) \
-    v(bool, verboseCompilation, false, Normal, nullptr) \
-    v(bool, verboseFTLCompilation, false, Normal, nullptr) \
-    v(bool, logCompilationChanges, false, Normal, nullptr) \
-    v(bool, useProbeOSRExit, false, Normal, nullptr) \
-    v(bool, printEachOSRExit, false, Normal, nullptr) \
-    v(bool, validateGraph, false, Normal, nullptr) \
-    v(bool, validateGraphAtEachPhase, false, Normal, nullptr) \
-    v(bool, verboseValidationFailure, false, Normal, nullptr) \
-    v(bool, verboseOSR, false, Normal, nullptr) \
-    v(bool, verboseDFGOSRExit, false, Normal, nullptr) \
-    v(bool, verboseFTLOSRExit, false, Normal, nullptr) \
-    v(bool, verboseCallLink, false, Normal, nullptr) \
-    v(bool, verboseCompilationQueue, false, Normal, nullptr) \
-    v(bool, reportCompileTimes, false, Normal, "dumps JS function signature and the time it took to compile in all tiers") \
-    v(bool, reportBaselineCompileTimes, false, Normal, "dumps JS function signature and the time it took to BaselineJIT compile") \
-    v(bool, reportDFGCompileTimes, false, Normal, "dumps JS function signature and the time it took to DFG and FTL compile") \
-    v(bool, reportFTLCompileTimes, false, Normal, "dumps JS function signature and the time it took to FTL compile") \
-    v(bool, reportTotalCompileTimes, false, Normal, nullptr) \
-    v(bool, reportParseTimes, false, Normal, "dumps JS function signature and the time it took to parse") \
-    v(bool, reportBytecodeCompileTimes, false, Normal, "dumps JS function signature and the time it took to bytecode compile") \
-    v(bool, countParseTimes, false, Normal, "counts parse times") \
-    v(bool, verboseExitProfile, false, Normal, nullptr) \
-    v(bool, verboseCFA, false, Normal, nullptr) \
-    v(bool, verboseDFGFailure, false, Normal, nullptr) \
-    v(bool, verboseFTLToJSThunk, false, Normal, nullptr) \
-    v(bool, verboseFTLFailure, false, Normal, nullptr) \
-    v(bool, alwaysComputeHash, false, Normal, nullptr) \
-    v(bool, testTheFTL, false, Normal, nullptr) \
-    v(bool, verboseSanitizeStack, false, Normal, nullptr) \
-    v(bool, useGenerationalGC, true, Normal, nullptr) \
-    v(bool, useConcurrentGC, true, Normal, nullptr) \
-    v(bool, collectContinuously, false, Normal, nullptr) \
-    v(double, collectContinuouslyPeriodMS, 1, Normal, nullptr) \
-    v(bool, forceFencedBarrier, false, Normal, nullptr) \
-    v(bool, verboseVisitRace, false, Normal, nullptr) \
-    v(bool, optimizeParallelSlotVisitorsForStoppedMutator, false, Normal, nullptr) \
-    v(unsigned, largeHeapSize, 32 * 1024 * 1024, Normal, nullptr) \
-    v(unsigned, smallHeapSize, 1 * 1024 * 1024, Normal, nullptr) \
-    v(double, smallHeapRAMFraction, 0.25, Normal, nullptr) \
-    v(double, smallHeapGrowthFactor, 2, Normal, nullptr) \
-    v(double, mediumHeapRAMFraction, 0.5, Normal, nullptr) \
-    v(double, mediumHeapGrowthFactor, 1.5, Normal, nullptr) \
-    v(double, largeHeapGrowthFactor, 1.24, Normal, nullptr) \
-    v(double, miniVMHeapGrowthFactor, 1.27, Normal, nullptr) \
-    v(double, criticalGCMemoryThreshold, 0.80, Normal, "percent memory in use the GC considers critical.  The collector is much more aggressive above this threshold") \
-    v(double, minimumMutatorUtilization, 0, Normal, nullptr) \
-    v(double, maximumMutatorUtilization, 0.7, Normal, nullptr) \
-    v(double, epsilonMutatorUtilization, 0.01, Normal, nullptr) \
-    v(double, concurrentGCMaxHeadroom, 1.5, Normal, nullptr) \
-    v(double, concurrentGCPeriodMS, 2, Normal, nullptr) \
-    v(bool, useStochasticMutatorScheduler, true, Normal, nullptr) \
-    v(double, minimumGCPauseMS, 0.3, Normal, nullptr) \
-    v(double, gcPauseScale, 0.3, Normal, nullptr) \
-    v(double, gcIncrementBytes, 10000, Normal, nullptr) \
-    v(double, gcIncrementMaxBytes, 100000, Normal, nullptr) \
-    v(double, gcIncrementScale, 0, Normal, nullptr) \
-    v(bool, scribbleFreeCells, false, Normal, nullptr) \
-    v(double, sizeClassProgression, 1.4, Normal, nullptr) \
-    v(unsigned, largeAllocationCutoff, 100000, Normal, nullptr) \
-    v(bool, dumpSizeClasses, false, Normal, nullptr) \
-    v(bool, useBumpAllocator, true, Normal, nullptr) \
-    v(bool, stealEmptyBlocksFromOtherAllocators, true, Normal, nullptr) \
-    v(bool, eagerlyUpdateTopCallFrame, false, Normal, nullptr) \
-    v(bool, dumpZappedCellCrashData, false, Normal, nullptr) \
-    \
-    v(bool, useOSREntryToDFG, true, Normal, nullptr) \
-    v(bool, useOSREntryToFTL, true, Normal, nullptr) \
-    \
-    v(bool, useFTLJIT, true, Normal, "allows the FTL JIT to be used if true") \
-    v(bool, useFTLTBAA, true, Normal, nullptr) \
-    v(bool, validateFTLOSRExitLiveness, false, Normal, nullptr) \
-    v(unsigned, defaultB3OptLevel, 2, Normal, nullptr) \
-    v(bool, b3AlwaysFailsBeforeCompile, false, Normal, nullptr) \
-    v(bool, b3AlwaysFailsBeforeLink, false, Normal, nullptr) \
-    v(bool, ftlCrashes, false, Normal, nullptr) /* fool-proof way of checking that you ended up in the FTL. ;-) */\
-    v(bool, clobberAllRegsInFTLICSlowPath, !ASSERT_DISABLED, Normal, nullptr) \
-    v(bool, enableJITDebugAssertions, !ASSERT_DISABLED, Normal, nullptr) \
-    v(bool, useAccessInlining, true, Normal, nullptr) \
-    v(unsigned, maxAccessVariantListSize, 8, Normal, nullptr) \
-    v(bool, usePolyvariantDevirtualization, true, Normal, nullptr) \
-    v(bool, usePolymorphicAccessInlining, true, Normal, nullptr) \
-    v(unsigned, maxPolymorphicAccessInliningListSize, 8, Normal, nullptr) \
-    v(bool, usePolymorphicCallInlining, true, Normal, nullptr) \
-    v(bool, usePolymorphicCallInliningForNonStubStatus, false, Normal, nullptr) \
-    v(unsigned, maxPolymorphicCallVariantListSize, 15, Normal, nullptr) \
-    v(unsigned, maxPolymorphicCallVariantListSizeForTopTier, 5, Normal, nullptr) \
-    v(unsigned, maxPolymorphicCallVariantListSizeForWebAssemblyToJS, 5, Normal, nullptr) \
-    v(unsigned, maxPolymorphicCallVariantsForInlining, 5, Normal, nullptr) \
-    v(unsigned, frequentCallThreshold, 2, Normal, nullptr) \
-    v(double, minimumCallToKnownRate, 0.51, Normal, nullptr) \
-    v(bool, createPreHeaders, true, Normal, nullptr) \
-    v(bool, useMovHintRemoval, true, Normal, nullptr) \
-    v(bool, usePutStackSinking, true, Normal, nullptr) \
-    v(bool, useObjectAllocationSinking, true, Normal, nullptr) \
-    v(bool, useValueRepElimination, true, Normal, nullptr) \
-    v(bool, useArityFixupInlining, true, Normal, nullptr) \
-    v(bool, logExecutableAllocation, false, Normal, nullptr) \
-    v(unsigned, maxDFGNodesInBasicBlockForPreciseAnalysis, 20000, Normal, "Disable precise but costly analysis and give conservative results if the number of DFG nodes in a block exceeds this threshold") \
-    \
-    v(bool, useConcurrentJIT, true, Normal, "allows the DFG / FTL compilation in threads other than the executing JS thread") \
-    v(unsigned, numberOfDFGCompilerThreads, computeNumberOfWorkerThreads(3, 2) - 1, Normal, nullptr) \
-    v(unsigned, numberOfFTLCompilerThreads, computeNumberOfWorkerThreads(MAXIMUM_NUMBER_OF_FTL_COMPILER_THREADS, 2) - 1, Normal, nullptr) \
-    v(int32, priorityDeltaOfDFGCompilerThreads, computePriorityDeltaOfWorkerThreads(-1, 0), Normal, nullptr) \
-    v(int32, priorityDeltaOfFTLCompilerThreads, computePriorityDeltaOfWorkerThreads(-2, 0), Normal, nullptr) \
-    v(int32, priorityDeltaOfWasmCompilerThreads, computePriorityDeltaOfWorkerThreads(-1, 0), Normal, nullptr) \
-    \
-    v(bool, useProfiler, false, Normal, nullptr) \
-    v(bool, disassembleBaselineForProfiler, true, Normal, nullptr) \
-    \
-    v(bool, useArchitectureSpecificOptimizations, true, Normal, nullptr) \
-    \
-    v(bool, breakOnThrow, false, Normal, nullptr) \
-    \
-    v(unsigned, maximumOptimizationCandidateBytecodeCost, 100000, Normal, nullptr) \
-    \
-    v(unsigned, maximumFunctionForCallInlineCandidateBytecodeCost, 120, Normal, nullptr) \
-    v(unsigned, maximumFunctionForClosureCallInlineCandidateBytecodeCost, 100, Normal, nullptr) \
-    v(unsigned, maximumFunctionForConstructInlineCandidateBytecoodeCost, 100, Normal, nullptr) \
-    \
-    v(unsigned, maximumFTLCandidateBytecodeCost, 20000, Normal, nullptr) \
-    \
-    /* Depth of inline stack, so 1 = no inlining, 2 = one level, etc. */ \
-    v(unsigned, maximumInliningDepth, 5, Normal, "maximum allowed inlining depth.  Depth of 1 means no inlining") \
-    v(unsigned, maximumInliningRecursion, 2, Normal, nullptr) \
-    \
-    /* Maximum size of a caller for enabling inlining. This is purely to protect us */\
-    /* from super long compiles that take a lot of memory. */\
-    v(unsigned, maximumInliningCallerBytecodeCost, 10000, Normal, nullptr) \
-    \
-    v(unsigned, maximumVarargsForInlining, 100, Normal, nullptr) \
-    \
-    v(unsigned, maximumBinaryStringSwitchCaseLength, 50, Normal, nullptr) \
-    v(unsigned, maximumBinaryStringSwitchTotalLength, 2000, Normal, nullptr) \
-    \
-    v(double, jitPolicyScale, 1.0, Normal, "scale JIT thresholds to this specified ratio between 0.0 (compile ASAP) and 1.0 (compile like normal).") \
-    v(bool, forceEagerCompilation, false, Normal, nullptr) \
-    v(int32, thresholdForJITAfterWarmUp, 500, Normal, nullptr) \
-    v(int32, thresholdForJITSoon, 100, Normal, nullptr) \
-    \
-    v(int32, thresholdForOptimizeAfterWarmUp, 1000, Normal, nullptr) \
-    v(int32, thresholdForOptimizeAfterLongWarmUp, 1000, Normal, nullptr) \
-    v(int32, thresholdForOptimizeSoon, 1000, Normal, nullptr) \
-    v(int32, executionCounterIncrementForLoop, 1, Normal, nullptr) \
-    v(int32, executionCounterIncrementForEntry, 15, Normal, nullptr) \
-    \
-    v(int32, thresholdForFTLOptimizeAfterWarmUp, 100000, Normal, nullptr) \
-    v(int32, thresholdForFTLOptimizeSoon, 1000, Normal, nullptr) \
-    v(int32, ftlTierUpCounterIncrementForLoop, 1, Normal, nullptr) \
-    v(int32, ftlTierUpCounterIncrementForReturn, 15, Normal, nullptr) \
-    v(unsigned, ftlOSREntryFailureCountForReoptimization, 15, Normal, nullptr) \
-    v(unsigned, ftlOSREntryRetryThreshold, 100, Normal, nullptr) \
-    \
-    v(int32, evalThresholdMultiplier, 10, Normal, nullptr) \
-    v(unsigned, maximumEvalCacheableSourceLength, 256, Normal, nullptr) \
-    \
-    v(bool, randomizeExecutionCountsBetweenCheckpoints, false, Normal, nullptr) \
-    v(int32, maximumExecutionCountsBetweenCheckpointsForBaseline, 1000, Normal, nullptr) \
-    v(int32, maximumExecutionCountsBetweenCheckpointsForUpperTiers, 50000, Normal, nullptr) \
-    \
-    v(unsigned, likelyToTakeSlowCaseMinimumCount, 20, Normal, nullptr) \
-    v(unsigned, couldTakeSlowCaseMinimumCount, 10, Normal, nullptr) \
-    \
-    v(unsigned, osrExitCountForReoptimization, 100, Normal, nullptr) \
-    v(unsigned, osrExitCountForReoptimizationFromLoop, 5, Normal, nullptr) \
-    \
-    v(unsigned, reoptimizationRetryCounterMax, 0, Normal, nullptr)  \
-    \
-    v(unsigned, minimumOptimizationDelay, 1, Normal, nullptr) \
-    v(unsigned, maximumOptimizationDelay, 5, Normal, nullptr) \
-    v(double, desiredProfileLivenessRate, 0.75, Normal, nullptr) \
-    v(double, desiredProfileFullnessRate, 0.35, Normal, nullptr) \
-    \
-    v(double, doubleVoteRatioForDoubleFormat, 2, Normal, nullptr) \
-    v(double, structureCheckVoteRatioForHoisting, 1, Normal, nullptr) \
-    v(double, checkArrayVoteRatioForHoisting, 1, Normal, nullptr) \
-    \
-    v(unsigned, maximumDirectCallStackSize, 200, Normal, nullptr) \
-    \
-    v(unsigned, minimumNumberOfScansBetweenRebalance, 100, Normal, nullptr) \
-    v(unsigned, numberOfGCMarkers, computeNumberOfGCMarkers(8), Normal, nullptr) \
-    v(bool, useParallelMarkingConstraintSolver, true, Normal, nullptr) \
-    v(unsigned, opaqueRootMergeThreshold, 1000, Normal, nullptr) \
-    v(double, minHeapUtilization, 0.8, Normal, nullptr) \
-    v(double, minMarkedBlockUtilization, 0.9, Normal, nullptr) \
-    v(unsigned, slowPathAllocsBetweenGCs, 0, Normal, "force a GC on every Nth slow path alloc, where N is specified by this option") \
-    \
-    v(double, percentCPUPerMBForFullTimer, 0.0003125, Normal, nullptr) \
-    v(double, percentCPUPerMBForEdenTimer, 0.0025, Normal, nullptr) \
-    v(double, collectionTimerMaxPercentCPU, 0.05, Normal, nullptr) \
-    \
-    v(bool, forceWeakRandomSeed, false, Normal, nullptr) \
-    v(unsigned, forcedWeakRandomSeed, 0, Normal, nullptr) \
-    \
-    v(bool, useZombieMode, false, Normal, "debugging option to scribble over dead objects with 0xbadbeef0") \
-    v(bool, useImmortalObjects, false, Normal, "debugging option to keep all objects alive forever") \
-    v(bool, sweepSynchronously, false, Normal, "debugging option to sweep all dead objects synchronously at GC end before resuming mutator") \
-    v(unsigned, maxSingleAllocationSize, 0, Configurable, "debugging option to limit individual allocations to a max size (0 = limit not set, N = limit size in bytes)") \
-    \
-    v(gcLogLevel, logGC, GCLogging::None, Normal, "debugging option to log GC activity (0 = None, 1 = Basic, 2 = Verbose)") \
-    v(bool, useGC, true, Normal, nullptr) \
-    v(bool, gcAtEnd, false, Normal, "If true, the jsc CLI will do a GC before exiting") \
-    v(bool, forceGCSlowPaths, false, Normal, "If true, we will force all JIT fast allocations down their slow paths.") \
-    v(unsigned, gcMaxHeapSize, 0, Normal, nullptr) \
-    v(unsigned, forceRAMSize, 0, Normal, nullptr) \
-    v(bool, recordGCPauseTimes, false, Normal, nullptr) \
-    v(bool, dumpHeapStatisticsAtVMDestruction, false, Normal, nullptr) \
-    v(bool, forceCodeBlockToJettisonDueToOldAge, false, Normal, "If true, this means that anytime we can jettison a CodeBlock due to old age, we do.") \
-    v(bool, useEagerCodeBlockJettisonTiming, false, Normal, "If true, the time slices for jettisoning a CodeBlock due to old age are shrunk significantly.") \
-    \
-    v(bool, useTypeProfiler, false, Normal, nullptr) \
-    v(bool, useControlFlowProfiler, false, Normal, nullptr) \
-    \
-    v(bool, useSamplingProfiler, false, Normal, nullptr) \
-    v(unsigned, sampleInterval, 1000, Normal, "Time between stack traces in microseconds.") \
-    v(bool, collectSamplingProfilerDataForJSCShell, false, Normal, "This corresponds to the JSC shell's --sample option.") \
-    v(unsigned, samplingProfilerTopFunctionsCount, 12, Normal, "Number of top functions to report when using the command line interface.") \
-    v(unsigned, samplingProfilerTopBytecodesCount, 40, Normal, "Number of top bytecodes to report when using the command line interface.") \
-    v(optionString, samplingProfilerPath, nullptr, Normal, "The path to the directory to write sampiling profiler output to. This probably will not work with WK2 unless the path is in the whitelist.") \
-    v(bool, sampleCCode, false, Normal, "Causes the sampling profiler to record profiling data for C frames.") \
-    \
-    v(bool, alwaysGeneratePCToCodeOriginMap, false, Normal, "This will make sure we always generate a PCToCodeOriginMap for JITed code.") \
-    \
-    v(bool, verifyHeap, false, Normal, nullptr) \
-    v(unsigned, numberOfGCCyclesToRecordForVerification, 3, Normal, nullptr) \
-    \
-    v(unsigned, exceptionStackTraceLimit, 100, Normal, "Stack trace limit for internal Exception object") \
-    v(unsigned, defaultErrorStackTraceLimit, 100, Normal, "The default value for Error.stackTraceLimit") \
-    v(bool, useExceptionFuzz, false, Normal, nullptr) \
-    v(unsigned, fireExceptionFuzzAt, 0, Normal, nullptr) \
-    v(bool, validateDFGExceptionHandling, false, Normal, "Causes the DFG to emit code validating exception handling for each node that can exit") /* This is true by default on Debug builds */\
-    v(bool, dumpSimulatedThrows, false, Normal, "Dumps the call stack of the last simulated throw if exception scope verification fails") \
-    v(bool, validateExceptionChecks, false, Normal, "Verifies that needed exception checks are performed.") \
-    v(unsigned, unexpectedExceptionStackTraceLimit, 100, Normal, "Stack trace limit for debugging unexpected exceptions observed in the VM") \
-    \
-    v(bool, useExecutableAllocationFuzz, false, Normal, nullptr) \
-    v(unsigned, fireExecutableAllocationFuzzAt, 0, Normal, nullptr) \
-    v(unsigned, fireExecutableAllocationFuzzAtOrAfter, 0, Normal, nullptr) \
-    v(bool, verboseExecutableAllocationFuzz, false, Normal, nullptr) \
-    \
-    v(bool, useOSRExitFuzz, false, Normal, nullptr) \
-    v(unsigned, fireOSRExitFuzzAtStatic, 0, Normal, nullptr) \
-    v(unsigned, fireOSRExitFuzzAt, 0, Normal, nullptr) \
-    v(unsigned, fireOSRExitFuzzAtOrAfter, 0, Normal, nullptr) \
-    \
-    v(bool, useRandomizingFuzzerAgent, false, Normal, nullptr) \
-    v(unsigned, seedOfRandomizingFuzzerAgent, 1, Normal, nullptr) \
-    v(bool, dumpRandomizingFuzzerAgentPredictions, false, Normal, nullptr) \
-    v(bool, useDoublePredictionFuzzerAgent, false, Normal, nullptr) \
-    \
-    v(bool, logPhaseTimes, false, Normal, nullptr) \
-    v(double, rareBlockPenalty, 0.001, Normal, nullptr) \
-    v(bool, airLinearScanVerbose, false, Normal, nullptr) \
-    v(bool, airLinearScanSpillsEverything, false, Normal, nullptr) \
-    v(bool, airForceBriggsAllocator, false, Normal, nullptr) \
-    v(bool, airForceIRCAllocator, false, Normal, nullptr) \
-    v(bool, airRandomizeRegs, false, Normal, nullptr) \
-    v(unsigned, airRandomizeRegsSeed, 0, Normal, nullptr) \
-    v(bool, coalesceSpillSlots, true, Normal, nullptr) \
-    v(bool, logAirRegisterPressure, false, Normal, nullptr) \
-    v(bool, useB3TailDup, true, Normal, nullptr) \
-    v(unsigned, maxB3TailDupBlockSize, 3, Normal, nullptr) \
-    v(unsigned, maxB3TailDupBlockSuccessors, 3, Normal, nullptr) \
-    \
-    v(bool, useDollarVM, false, Restricted, "installs the $vm debugging tool in global objects") \
-    v(optionString, functionOverrides, nullptr, Restricted, "file with debugging overrides for function bodies") \
-    v(bool, useSigillCrashAnalyzer, false, Configurable, "logs data about SIGILL crashes") \
-    \
-    v(unsigned, watchdog, 0, Normal, "watchdog timeout (0 = Disabled, N = a timeout period of N milliseconds)") \
-    v(bool, usePollingTraps, false, Normal, "use polling (instead of signalling) VM traps") \
-    \
-    v(bool, useMachForExceptions, true, Normal, "Use mach exceptions rather than signals to handle faults and pass thread messages. (This does nothing on platforms without mach)") \
-    \
-    v(bool, useICStats, false, Normal, nullptr) \
-    \
-    v(unsigned, prototypeHitCountForLLIntCaching, 2, Normal, "Number of prototype property hits before caching a prototype in the LLInt. A count of 0 means never cache.") \
-    \
-    v(bool, dumpCompiledRegExpPatterns, false, Normal, nullptr) \
-    \
-    v(bool, dumpModuleRecord, false, Normal, nullptr) \
-    v(bool, dumpModuleLoadingState, false, Normal, nullptr) \
-    v(bool, exposeInternalModuleLoader, false, Normal, "expose the internal module loader object to the global space for debugging") \
-    \
-    v(bool, useSuperSampler, false, Normal, nullptr) \
-    \
-    v(bool, useSourceProviderCache, true, Normal, "If false, the parser will not use the source provider cache. It's good to verify everything works when this is false. Because the cache is so successful, it can mask bugs.") \
-    v(bool, useCodeCache, true, Normal, "If false, the unlinked byte code cache will not be used.") \
-    \
-    v(bool, useWebAssembly, true, Normal, "Expose the WebAssembly global object.") \
-    \
-    v(bool, enableSpectreMitigations, true, Restricted, "Enable Spectre mitigations.") \
-    v(bool, enableSpectreGadgets, false, Restricted, "enable gadgets to test Spectre mitigations.") \
-    v(bool, zeroStackFrame, false, Normal, "Zero stack frame on entry to a function.") \
-    \
-    v(bool, failToCompileWebAssemblyCode, false, Normal, "If true, no Wasm::Plan will sucessfully compile a function.") \
-    v(size, webAssemblyPartialCompileLimit, 5000, Normal, "Limit on the number of bytes a Wasm::Plan::compile should attempt before checking for other work.") \
-    v(unsigned, webAssemblyBBQAirOptimizationLevel, 0, Normal, "Air Optimization level for BBQ Web Assembly module compilations.") \
-    v(unsigned, webAssemblyBBQB3OptimizationLevel, 1, Normal, "B3 Optimization level for BBQ Web Assembly module compilations.") \
-    v(unsigned, webAssemblyOMGOptimizationLevel, Options::defaultB3OptLevel(), Normal, "B3 Optimization level for OMG Web Assembly module compilations.") \
-    \
-    v(bool, useBBQTierUpChecks, true, Normal, "Enables tier up checks for our BBQ code.") \
-    v(bool, useWebAssemblyOSR, true, Normal, nullptr) \
-    v(int32, thresholdForOMGOptimizeAfterWarmUp, 50000, Normal, "The count before we tier up a function to OMG.") \
-    v(int32, thresholdForOMGOptimizeSoon, 500, Normal, nullptr) \
-    v(int32, omgTierUpCounterIncrementForLoop, 1, Normal, "The amount the tier up counter is incremented on each loop backedge.") \
-    v(int32, omgTierUpCounterIncrementForEntry, 15, Normal, "The amount the tier up counter is incremented on each function entry.") \
-    /* FIXME: enable fast memories on iOS and pre-allocate them. https://bugs.webkit.org/show_bug.cgi?id=170774 */ \
-    v(bool, useWebAssemblyFastMemory, !isIOS(), Normal, "If true, we will try to use a 32-bit address space with a signal handler to bounds check wasm memory.") \
-    v(bool, logWebAssemblyMemory, false, Normal, nullptr) \
-    v(unsigned, webAssemblyFastMemoryRedzonePages, 128, Normal, "WebAssembly fast memories use 4GiB virtual allocations, plus a redzone (counted as multiple of 64KiB WebAssembly pages) at the end to catch reg+imm accesses which exceed 32-bit, anything beyond the redzone is explicitly bounds-checked") \
-    v(bool, crashIfWebAssemblyCantFastMemory, false, Normal, "If true, we will crash if we can't obtain fast memory for wasm.") \
-    v(unsigned, maxNumWebAssemblyFastMemories, 4, Normal, nullptr) \
-    v(bool, useFastTLSForWasmContext, true, Normal, "If true, we will store context in fast TLS. If false, we will pin it to a register.") \
-    v(bool, wasmBBQUsesAir, true, Normal, nullptr) \
-    v(size, webAssemblyBBQAirModeThreshold, isIOS() ? (10 * MB) : 0, Normal, "If 0, we always use BBQ Air. If Wasm module code size hits this threshold, we compile Wasm module with B3 BBQ mode.") \
-    v(bool, useWebAssemblyStreamingApi, enableWebAssemblyStreamingApi, Normal, "Allow to run WebAssembly's Streaming API") \
-    v(bool, useCallICsForWebAssemblyToJSCalls, true, Normal, "If true, we will use CallLinkInfo to inline cache Wasm to JS calls.") \
-    v(bool, useEagerWebAssemblyModuleHashing, false, Normal, "Unnamed WebAssembly modules are identified in backtraces through their hash, if available.") \
-    v(bool, useWebAssemblyReferences, true, Normal, "Allow types from the wasm references spec.") \
-    v(bool, useWeakRefs, false, Normal, "Expose the WeakRef constructor.") \
-    v(bool, useBigInt, false, Normal, "If true, we will enable BigInt support.") \
-    v(bool, useNullishAwareOperators, false, Normal, "Enable support for ?. and ?? operators.") \
-    v(bool, useArrayAllocationProfiling, true, Normal, "If true, we will use our normal array allocation profiling. If false, the allocation profile will always claim to be undecided.") \
-    v(bool, forcePolyProto, false, Normal, "If true, create_this will always create an object with a poly proto structure.") \
-    v(bool, forceMiniVMMode, false, Normal, "If true, it will force mini VM mode on.") \
-    v(bool, useTracePoints, false, Normal, nullptr) \
-    v(bool, traceLLIntExecution, false, Configurable, nullptr) \
-    v(bool, traceLLIntSlowPath, false, Configurable, nullptr) \
-    v(bool, traceBaselineJITExecution, false, Normal, nullptr) \
-    v(unsigned, thresholdForGlobalLexicalBindingEpoch, UINT_MAX, Normal, "Threshold for global lexical binding epoch. If the epoch reaches to this value, CodeBlock metadata for scope operations will be revised globally. It needs to be greater than 1.") \
-    v(optionString, diskCachePath, nullptr, Restricted, nullptr) \
-    v(bool, forceDiskCache, false, Restricted, nullptr) \
-    v(bool, validateAbstractInterpreterState, false, Restricted, nullptr) \
-    v(double, validateAbstractInterpreterStateProbability, 0.5, Normal, nullptr) \
-    v(optionString, dumpJITMemoryPath, nullptr, Restricted, nullptr) \
-    v(double, dumpJITMemoryFlushInterval, 10, Restricted, "Maximum time in between flushes of the JIT memory dump in seconds.") \
-    v(bool, useUnlinkedCodeBlockJettisoning, false, Normal, "If true, UnlinkedCodeBlock can be jettisoned.") \
-
-
-enum OptionEquivalence {
-    SameOption,
-    InvertedOption,
-};
-
-#define JSC_ALIASED_OPTIONS(v) \
-    v(enableFunctionDotArguments, useFunctionDotArguments, SameOption) \
-    v(enableTailCalls, useTailCalls, SameOption) \
-    v(showDisassembly, dumpDisassembly, SameOption) \
-    v(showDFGDisassembly, dumpDFGDisassembly, SameOption) \
-    v(showFTLDisassembly, dumpFTLDisassembly, SameOption) \
-    v(showAllDFGNodes, dumpAllDFGNodes, SameOption) \
-    v(alwaysDoFullCollection, useGenerationalGC, InvertedOption) \
-    v(enableOSREntryToDFG, useOSREntryToDFG, SameOption) \
-    v(enableOSREntryToFTL, useOSREntryToFTL, SameOption) \
-    v(enableAccessInlining, useAccessInlining, SameOption) \
-    v(enablePolyvariantDevirtualization, usePolyvariantDevirtualization, SameOption) \
-    v(enablePolymorphicAccessInlining, usePolymorphicAccessInlining, SameOption) \
-    v(enablePolymorphicCallInlining, usePolymorphicCallInlining, SameOption) \
-    v(enableMovHintRemoval, useMovHintRemoval, SameOption) \
-    v(enableObjectAllocationSinking, useObjectAllocationSinking, SameOption) \
-    v(enableConcurrentJIT, useConcurrentJIT, SameOption) \
-    v(enableProfiler, useProfiler, SameOption) \
-    v(enableArchitectureSpecificOptimizations, useArchitectureSpecificOptimizations, SameOption) \
-    v(enablePolyvariantCallInlining, usePolyvariantCallInlining, SameOption) \
-    v(enablePolyvariantByIdInlining, usePolyvariantByIdInlining, SameOption) \
-    v(objectsAreImmortal, useImmortalObjects, SameOption) \
-    v(showObjectStatistics, dumpObjectStatistics, SameOption) \
-    v(disableGC, useGC, InvertedOption) \
-    v(enableTypeProfiler, useTypeProfiler, SameOption) \
-    v(enableControlFlowProfiler, useControlFlowProfiler, SameOption) \
-    v(enableExceptionFuzz, useExceptionFuzz, SameOption) \
-    v(enableExecutableAllocationFuzz, useExecutableAllocationFuzz, SameOption) \
-    v(enableOSRExitFuzz, useOSRExitFuzz, SameOption) \
-    v(enableDollarVM, useDollarVM, SameOption) \
-    v(enableWebAssembly, useWebAssembly, SameOption) \
-    v(verboseDFGByteCodeParsing, verboseDFGBytecodeParsing, SameOption) \
-    v(maximumOptimizationCandidateInstructionCount, maximumOptimizationCandidateBytecodeCost, SameOption) \
-    v(maximumFunctionForCallInlineCandidateInstructionCount, maximumFunctionForCallInlineCandidateBytecodeCost, SameOption) \
-    v(maximumFunctionForClosureCallInlineCandidateInstructionCount, maximumFunctionForClosureCallInlineCandidateBytecodeCost, SameOption) \
-    v(maximumFunctionForConstructInlineCandidateInstructionCount, maximumFunctionForConstructInlineCandidateBytecoodeCost, SameOption) \
-    v(maximumFTLCandidateInstructionCount, maximumFTLCandidateBytecodeCost, SameOption) \
-    v(maximumInliningCallerSize, maximumInliningCallerBytecodeCost, SameOption) \
-
-
 class Options {
 public:
     enum class DumpLevel {
@@ -577,29 +94,24 @@ public:
         Configurable
     };
 
-    // This typedef is to allow us to eliminate the '_' in the field name in
-    // union inside Entry. This is needed to keep the style checker happy.
-    typedef int32_t int32;
-    typedef size_t size;
+#define DECLARE_OPTION_ID(type_, name_, defaultValue_, availability_, description_) \
+    name_##ID,
 
-    // Declare the option IDs:
     enum ID {
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
-        name_##ID,
-        JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+        FOR_EACH_JSC_OPTION(DECLARE_OPTION_ID)
         numberOfOptions
     };
+#undef DECLARE_OPTION_ID
 
     enum class Type {
-        boolType,
-        unsignedType,
-        doubleType,
-        int32Type,
-        sizeType,
-        optionRangeType,
-        optionStringType,
-        gcLogLevelType,
+        Bool,
+        Unsigned,
+        Double,
+        Int32,
+        Size,
+        OptionRange,
+        OptionString,
+        GCLogLevel,
     };
 
     JS_EXPORT_PRIVATE static void initialize();
@@ -617,30 +129,16 @@ public:
 
     JS_EXPORT_PRIVATE static void ensureOptionsAreCoherent();
 
-    JS_EXPORT_PRIVATE static void enableRestrictedOptions(bool enableOrNot);
+#define DECLARE_OPTION_ACCESSORS(type_, name_, defaultValue_, availability_, description_) \
+    ALWAYS_INLINE static OptionEntry::type_& name_() { return g_jscConfig.options[name_##ID].val##type_; }  \
+    ALWAYS_INLINE static OptionEntry::type_& name_##Default() { return g_jscConfig.defaultOptions[name_##ID].val##type_; }
 
-    // Declare accessors for each option:
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
-    ALWAYS_INLINE static type_& name_() { return s_options[name_##ID].type_##Val; } \
-    ALWAYS_INLINE static type_& name_##Default() { return s_defaultOptions[name_##ID].type_##Val; }
-
-    JSC_OPTIONS(FOR_EACH_OPTION)
-#undef FOR_EACH_OPTION
+    FOR_EACH_JSC_OPTION(DECLARE_OPTION_ACCESSORS)
+#undef DECLARE_OPTION_ACCESSORS
 
     static bool isAvailable(ID, Availability);
 
 private:
-    // For storing for an option value:
-    union Entry {
-        bool boolVal;
-        unsigned unsignedVal;
-        double doubleVal;
-        int32 int32Val;
-        size sizeVal;
-        OptionRange optionRangeVal;
-        const char* optionStringVal;
-        GCLogging::Level gcLogLevelVal;
-    };
 
     // For storing constant meta data about each option:
     struct EntryInfo {
@@ -666,9 +164,6 @@ private:
     static bool setAliasedOption(const char* arg);
     static bool overrideAliasedOptionWithHeuristic(const char* name);
 
-    // Declare the singleton instance of the options store:
-    JS_EXPORT_PRIVATE static Entry s_options[numberOfOptions];
-    JS_EXPORT_PRIVATE static Entry s_defaultOptions[numberOfOptions];
     static const EntryInfo s_optionsInfo[numberOfOptions];
 
     friend class Option;
@@ -678,7 +173,7 @@ class Option {
 public:
     Option(Options::ID id)
         : m_id(id)
-        , m_entry(Options::s_options[m_id])
+        , m_entry(g_jscConfig.options[m_id])
     {
     }
     
@@ -705,14 +200,14 @@ public:
     
 private:
     // Only used for constructing default Options.
-    Option(Options::ID id, Options::Entry& entry)
+    Option(Options::ID id, OptionEntry& entry)
         : m_id(id)
         , m_entry(entry)
     {
     }
     
     Options::ID m_id;
-    Options::Entry& m_entry;
+    OptionEntry& m_entry;
 };
 
 inline const char* Option::name() const
@@ -742,42 +237,42 @@ inline bool Option::isOverridden() const
 
 inline const Option Option::defaultOption() const
 {
-    return Option(m_id, Options::s_defaultOptions[m_id]);
+    return Option(m_id, g_jscConfig.defaultOptions[m_id]);
 }
 
 inline bool& Option::boolVal()
 {
-    return m_entry.boolVal;
+    return m_entry.valBool;
 }
 
 inline unsigned& Option::unsignedVal()
 {
-    return m_entry.unsignedVal;
+    return m_entry.valUnsigned;
 }
 
 inline double& Option::doubleVal()
 {
-    return m_entry.doubleVal;
+    return m_entry.valDouble;
 }
 
 inline int32_t& Option::int32Val()
 {
-    return m_entry.int32Val;
+    return m_entry.valInt32;
 }
 
 inline OptionRange Option::optionRangeVal()
 {
-    return m_entry.optionRangeVal;
+    return m_entry.valOptionRange;
 }
 
 inline const char* Option::optionStringVal()
 {
-    return m_entry.optionStringVal;
+    return m_entry.valOptionString;
 }
 
 inline GCLogging::Level& Option::gcLogLevelVal()
 {
-    return m_entry.gcLogLevelVal;
+    return m_entry.valGCLogLevel;
 }
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/OptionsList.h b/Source/JavaScriptCore/runtime/OptionsList.h
new file mode 100644 (file)
index 0000000..31b321a
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+namespace JSC {
+
+#define FOR_EACH_JSC_OPTION(v) \
+    v(Bool, useKernTCSM, true, Normal, "Note: this needs to go before other options since they depend on this value.") \
+    v(Bool, validateOptions, false, Normal, "crashes if mis-typed JSC options were passed to the VM") \
+    v(Unsigned, dumpOptions, 0, Normal, "dumps JSC options (0 = None, 1 = Overridden only, 2 = All, 3 = Verbose)") \
+    v(OptionString, configFile, nullptr, Normal, "file to configure JSC options and logging location") \
+    \
+    v(Bool, useLLInt,  true, Normal, "allows the LLINT to be used if true") \
+    v(Bool, useJIT, jitEnabledByDefault(), Normal, "allows the executable pages to be allocated for JIT and thunks if true") \
+    v(Bool, useBaselineJIT, true, Normal, "allows the baseline JIT to be used if true") \
+    v(Bool, useDFGJIT, true, Normal, "allows the DFG JIT to be used if true") \
+    v(Bool, useRegExpJIT, jitEnabledByDefault(), Normal, "allows the RegExp JIT to be used if true") \
+    v(Bool, useDOMJIT, is64Bit(), Normal, "allows the DOMJIT to be used if true") \
+    \
+    v(Bool, reportMustSucceedExecutableAllocations, false, Normal, nullptr) \
+    \
+    v(Unsigned, maxPerThreadStackUsage, 4 * MB, Normal, "Max allowed stack usage by the VM") \
+    v(Unsigned, softReservedZoneSize, 128 * KB, Normal, "A buffer greater than reservedZoneSize that reserves space for stringifying exceptions.") \
+    v(Unsigned, reservedZoneSize, 64 * KB, Normal, "The amount of stack space we guarantee to our clients (and to interal VM code that does not call out to clients).") \
+    \
+    v(Bool, crashIfCantAllocateJITMemory, false, Normal, nullptr) \
+    v(Unsigned, jitMemoryReservationSize, 0, Normal, "Set this number to change the executable allocation size in ExecutableAllocatorFixedVMPool. (In bytes.)") \
+    v(Bool, useSeparatedWXHeap, false, Normal, nullptr) \
+    \
+    v(Bool, forceCodeBlockLiveness, false, Normal, nullptr) \
+    v(Bool, forceICFailure, false, Normal, nullptr) \
+    \
+    v(Unsigned, repatchCountForCoolDown, 8, Normal, nullptr) \
+    v(Unsigned, initialCoolDownCount, 20, Normal, nullptr) \
+    v(Unsigned, repatchBufferingCountdown, 8, Normal, nullptr) \
+    \
+    v(Bool, dumpGeneratedBytecodes, false, Normal, nullptr) \
+    v(Bool, dumpBytecodeLivenessResults, false, Normal, nullptr) \
+    v(Bool, validateBytecode, false, Normal, nullptr) \
+    v(Bool, forceDebuggerBytecodeGeneration, false, Normal, nullptr) \
+    v(Bool, dumpBytecodesBeforeGeneratorification, false, Normal, nullptr) \
+    \
+    v(Bool, useFunctionDotArguments, true, Normal, nullptr) \
+    v(Bool, useTailCalls, true, Normal, nullptr) \
+    v(Bool, optimizeRecursiveTailCalls, true, Normal, nullptr) \
+    v(Bool, alwaysUseShadowChicken, false, Normal, nullptr) \
+    v(Unsigned, shadowChickenLogSize, 1000, Normal, nullptr) \
+    v(Unsigned, shadowChickenMaxTailDeletedFramesSize, 128, Normal, nullptr) \
+    \
+    /* dumpDisassembly implies dumpDFGDisassembly. */ \
+    v(Bool, dumpDisassembly, false, Normal, "dumps disassembly of all JIT compiled code upon compilation") \
+    v(Bool, asyncDisassembly, false, Normal, nullptr) \
+    v(Bool, dumpDFGDisassembly, false, Normal, "dumps disassembly of DFG function upon compilation") \
+    v(Bool, dumpFTLDisassembly, false, Normal, "dumps disassembly of FTL function upon compilation") \
+    v(Bool, dumpRegExpDisassembly, false, Normal, "dumps disassembly of RegExp upon compilation") \
+    v(Bool, dumpAllDFGNodes, false, Normal, nullptr) \
+    v(Bool, logJITCodeForPerf, false, Configurable, nullptr) \
+    v(OptionRange, bytecodeRangeToJITCompile, 0, Normal, "bytecode size range to allow compilation on, e.g. 1:100") \
+    v(OptionRange, bytecodeRangeToDFGCompile, 0, Normal, "bytecode size range to allow DFG compilation on, e.g. 1:100") \
+    v(OptionRange, bytecodeRangeToFTLCompile, 0, Normal, "bytecode size range to allow FTL compilation on, e.g. 1:100") \
+    v(OptionString, jitWhitelist, nullptr, Normal, "file with list of function signatures to allow compilation on") \
+    v(OptionString, dfgWhitelist, nullptr, Normal, "file with list of function signatures to allow DFG compilation on") \
+    v(OptionString, ftlWhitelist, nullptr, Normal, "file with list of function signatures to allow FTL compilation on") \
+    v(Bool, dumpSourceAtDFGTime, false, Normal, "dumps source code of JS function being DFG compiled") \
+    v(Bool, dumpBytecodeAtDFGTime, false, Normal, "dumps bytecode of JS function being DFG compiled") \
+    v(Bool, dumpGraphAfterParsing, false, Normal, nullptr) \
+    v(Bool, dumpGraphAtEachPhase, false, Normal, nullptr) \
+    v(Bool, dumpDFGGraphAtEachPhase, false, Normal, "dumps the DFG graph at each phase of DFG compilation (note this excludes DFG graphs during FTL compilation)") \
+    v(Bool, dumpDFGFTLGraphAtEachPhase, false, Normal, "dumps the DFG graph at each phase of DFG compilation when compiling FTL code") \
+    v(Bool, dumpB3GraphAtEachPhase, false, Normal, "dumps the B3 graph at each phase of compilation") \
+    v(Bool, dumpAirGraphAtEachPhase, false, Normal, "dumps the Air graph at each phase of compilation") \
+    v(Bool, verboseDFGBytecodeParsing, false, Normal, nullptr) \
+    v(Bool, safepointBeforeEachPhase, true, Normal, nullptr) \
+    v(Bool, verboseCompilation, false, Normal, nullptr) \
+    v(Bool, verboseFTLCompilation, false, Normal, nullptr) \
+    v(Bool, logCompilationChanges, false, Normal, nullptr) \
+    v(Bool, useProbeOSRExit, false, Normal, nullptr) \
+    v(Bool, printEachOSRExit, false, Normal, nullptr) \
+    v(Bool, validateGraph, false, Normal, nullptr) \
+    v(Bool, validateGraphAtEachPhase, false, Normal, nullptr) \
+    v(Bool, verboseValidationFailure, false, Normal, nullptr) \
+    v(Bool, verboseOSR, false, Normal, nullptr) \
+    v(Bool, verboseDFGOSRExit, false, Normal, nullptr) \
+    v(Bool, verboseFTLOSRExit, false, Normal, nullptr) \
+    v(Bool, verboseCallLink, false, Normal, nullptr) \
+    v(Bool, verboseCompilationQueue, false, Normal, nullptr) \
+    v(Bool, reportCompileTimes, false, Normal, "dumps JS function signature and the time it took to compile in all tiers") \
+    v(Bool, reportBaselineCompileTimes, false, Normal, "dumps JS function signature and the time it took to BaselineJIT compile") \
+    v(Bool, reportDFGCompileTimes, false, Normal, "dumps JS function signature and the time it took to DFG and FTL compile") \
+    v(Bool, reportFTLCompileTimes, false, Normal, "dumps JS function signature and the time it took to FTL compile") \
+    v(Bool, reportTotalCompileTimes, false, Normal, nullptr) \
+    v(Bool, reportParseTimes, false, Normal, "dumps JS function signature and the time it took to parse") \
+    v(Bool, reportBytecodeCompileTimes, false, Normal, "dumps JS function signature and the time it took to bytecode compile") \
+    v(Bool, countParseTimes, false, Normal, "counts parse times") \
+    v(Bool, verboseExitProfile, false, Normal, nullptr) \
+    v(Bool, verboseCFA, false, Normal, nullptr) \
+    v(Bool, verboseDFGFailure, false, Normal, nullptr) \
+    v(Bool, verboseFTLToJSThunk, false, Normal, nullptr) \
+    v(Bool, verboseFTLFailure, false, Normal, nullptr) \
+    v(Bool, alwaysComputeHash, false, Normal, nullptr) \
+    v(Bool, testTheFTL, false, Normal, nullptr) \
+    v(Bool, verboseSanitizeStack, false, Normal, nullptr) \
+    v(Bool, useGenerationalGC, true, Normal, nullptr) \
+    v(Bool, useConcurrentGC, true, Normal, nullptr) \
+    v(Bool, collectContinuously, false, Normal, nullptr) \
+    v(Double, collectContinuouslyPeriodMS, 1, Normal, nullptr) \
+    v(Bool, forceFencedBarrier, false, Normal, nullptr) \
+    v(Bool, verboseVisitRace, false, Normal, nullptr) \
+    v(Bool, optimizeParallelSlotVisitorsForStoppedMutator, false, Normal, nullptr) \
+    v(Unsigned, largeHeapSize, 32 * 1024 * 1024, Normal, nullptr) \
+    v(Unsigned, smallHeapSize, 1 * 1024 * 1024, Normal, nullptr) \
+    v(Double, smallHeapRAMFraction, 0.25, Normal, nullptr) \
+    v(Double, smallHeapGrowthFactor, 2, Normal, nullptr) \
+    v(Double, mediumHeapRAMFraction, 0.5, Normal, nullptr) \
+    v(Double, mediumHeapGrowthFactor, 1.5, Normal, nullptr) \
+    v(Double, largeHeapGrowthFactor, 1.24, Normal, nullptr) \
+    v(Double, miniVMHeapGrowthFactor, 1.27, Normal, nullptr) \
+    v(Double, criticalGCMemoryThreshold, 0.80, Normal, "percent memory in use the GC considers critical.  The collector is much more aggressive above this threshold") \
+    v(Double, minimumMutatorUtilization, 0, Normal, nullptr) \
+    v(Double, maximumMutatorUtilization, 0.7, Normal, nullptr) \
+    v(Double, epsilonMutatorUtilization, 0.01, Normal, nullptr) \
+    v(Double, concurrentGCMaxHeadroom, 1.5, Normal, nullptr) \
+    v(Double, concurrentGCPeriodMS, 2, Normal, nullptr) \
+    v(Bool, useStochasticMutatorScheduler, true, Normal, nullptr) \
+    v(Double, minimumGCPauseMS, 0.3, Normal, nullptr) \
+    v(Double, gcPauseScale, 0.3, Normal, nullptr) \
+    v(Double, gcIncrementBytes, 10000, Normal, nullptr) \
+    v(Double, gcIncrementMaxBytes, 100000, Normal, nullptr) \
+    v(Double, gcIncrementScale, 0, Normal, nullptr) \
+    v(Bool, scribbleFreeCells, false, Normal, nullptr) \
+    v(Double, sizeClassProgression, 1.4, Normal, nullptr) \
+    v(Unsigned, largeAllocationCutoff, 100000, Normal, nullptr) \
+    v(Bool, dumpSizeClasses, false, Normal, nullptr) \
+    v(Bool, useBumpAllocator, true, Normal, nullptr) \
+    v(Bool, stealEmptyBlocksFromOtherAllocators, true, Normal, nullptr) \
+    v(Bool, eagerlyUpdateTopCallFrame, false, Normal, nullptr) \
+    v(Bool, dumpZappedCellCrashData, false, Normal, nullptr) \
+    \
+    v(Bool, useOSREntryToDFG, true, Normal, nullptr) \
+    v(Bool, useOSREntryToFTL, true, Normal, nullptr) \
+    \
+    v(Bool, useFTLJIT, true, Normal, "allows the FTL JIT to be used if true") \
+    v(Bool, useFTLTBAA, true, Normal, nullptr) \
+    v(Bool, validateFTLOSRExitLiveness, false, Normal, nullptr) \
+    v(Unsigned, defaultB3OptLevel, 2, Normal, nullptr) \
+    v(Bool, b3AlwaysFailsBeforeCompile, false, Normal, nullptr) \
+    v(Bool, b3AlwaysFailsBeforeLink, false, Normal, nullptr) \
+    v(Bool, ftlCrashes, false, Normal, nullptr) /* fool-proof way of checking that you ended up in the FTL. ;-) */\
+    v(Bool, clobberAllRegsInFTLICSlowPath, !ASSERT_DISABLED, Normal, nullptr) \
+    v(Bool, enableJITDebugAssertions, !ASSERT_DISABLED, Normal, nullptr) \
+    v(Bool, useAccessInlining, true, Normal, nullptr) \
+    v(Unsigned, maxAccessVariantListSize, 8, Normal, nullptr) \
+    v(Bool, usePolyvariantDevirtualization, true, Normal, nullptr) \
+    v(Bool, usePolymorphicAccessInlining, true, Normal, nullptr) \
+    v(Unsigned, maxPolymorphicAccessInliningListSize, 8, Normal, nullptr) \
+    v(Bool, usePolymorphicCallInlining, true, Normal, nullptr) \
+    v(Bool, usePolymorphicCallInliningForNonStubStatus, false, Normal, nullptr) \
+    v(Unsigned, maxPolymorphicCallVariantListSize, 15, Normal, nullptr) \
+    v(Unsigned, maxPolymorphicCallVariantListSizeForTopTier, 5, Normal, nullptr) \
+    v(Unsigned, maxPolymorphicCallVariantListSizeForWebAssemblyToJS, 5, Normal, nullptr) \
+    v(Unsigned, maxPolymorphicCallVariantsForInlining, 5, Normal, nullptr) \
+    v(Unsigned, frequentCallThreshold, 2, Normal, nullptr) \
+    v(Double, minimumCallToKnownRate, 0.51, Normal, nullptr) \
+    v(Bool, createPreHeaders, true, Normal, nullptr) \
+    v(Bool, useMovHintRemoval, true, Normal, nullptr) \
+    v(Bool, usePutStackSinking, true, Normal, nullptr) \
+    v(Bool, useObjectAllocationSinking, true, Normal, nullptr) \
+    v(Bool, useValueRepElimination, true, Normal, nullptr) \
+    v(Bool, useArityFixupInlining, true, Normal, nullptr) \
+    v(Bool, logExecutableAllocation, false, Normal, nullptr) \
+    v(Unsigned, maxDFGNodesInBasicBlockForPreciseAnalysis, 20000, Normal, "Disable precise but costly analysis and give conservative results if the number of DFG nodes in a block exceeds this threshold") \
+    \
+    v(Bool, useConcurrentJIT, true, Normal, "allows the DFG / FTL compilation in threads other than the executing JS thread") \
+    v(Unsigned, numberOfDFGCompilerThreads, computeNumberOfWorkerThreads(3, 2) - 1, Normal, nullptr) \
+    v(Unsigned, numberOfFTLCompilerThreads, computeNumberOfWorkerThreads(MAXIMUM_NUMBER_OF_FTL_COMPILER_THREADS, 2) - 1, Normal, nullptr) \
+    v(Int32, priorityDeltaOfDFGCompilerThreads, computePriorityDeltaOfWorkerThreads(-1, 0), Normal, nullptr) \
+    v(Int32, priorityDeltaOfFTLCompilerThreads, computePriorityDeltaOfWorkerThreads(-2, 0), Normal, nullptr) \
+    v(Int32, priorityDeltaOfWasmCompilerThreads, computePriorityDeltaOfWorkerThreads(-1, 0), Normal, nullptr) \
+    \
+    v(Bool, useProfiler, false, Normal, nullptr) \
+    v(Bool, disassembleBaselineForProfiler, true, Normal, nullptr) \
+    \
+    v(Bool, useArchitectureSpecificOptimizations, true, Normal, nullptr) \
+    \
+    v(Bool, breakOnThrow, false, Normal, nullptr) \
+    \
+    v(Unsigned, maximumOptimizationCandidateBytecodeCost, 100000, Normal, nullptr) \
+    \
+    v(Unsigned, maximumFunctionForCallInlineCandidateBytecodeCost, 120, Normal, nullptr) \
+    v(Unsigned, maximumFunctionForClosureCallInlineCandidateBytecodeCost, 100, Normal, nullptr) \
+    v(Unsigned, maximumFunctionForConstructInlineCandidateBytecoodeCost, 100, Normal, nullptr) \
+    \
+    v(Unsigned, maximumFTLCandidateBytecodeCost, 20000, Normal, nullptr) \
+    \
+    /* Depth of inline stack, so 1 = no inlining, 2 = one level, etc. */ \
+    v(Unsigned, maximumInliningDepth, 5, Normal, "maximum allowed inlining depth.  Depth of 1 means no inlining") \
+    v(Unsigned, maximumInliningRecursion, 2, Normal, nullptr) \
+    \
+    /* Maximum size of a caller for enabling inlining. This is purely to protect us */\
+    /* from super long compiles that take a lot of memory. */\
+    v(Unsigned, maximumInliningCallerBytecodeCost, 10000, Normal, nullptr) \
+    \
+    v(Unsigned, maximumVarargsForInlining, 100, Normal, nullptr) \
+    \
+    v(Unsigned, maximumBinaryStringSwitchCaseLength, 50, Normal, nullptr) \
+    v(Unsigned, maximumBinaryStringSwitchTotalLength, 2000, Normal, nullptr) \
+    \
+    v(Double, jitPolicyScale, 1.0, Normal, "scale JIT thresholds to this specified ratio between 0.0 (compile ASAP) and 1.0 (compile like normal).") \
+    v(Bool, forceEagerCompilation, false, Normal, nullptr) \
+    v(Int32, thresholdForJITAfterWarmUp, 500, Normal, nullptr) \
+    v(Int32, thresholdForJITSoon, 100, Normal, nullptr) \
+    \
+    v(Int32, thresholdForOptimizeAfterWarmUp, 1000, Normal, nullptr) \
+    v(Int32, thresholdForOptimizeAfterLongWarmUp, 1000, Normal, nullptr) \
+    v(Int32, thresholdForOptimizeSoon, 1000, Normal, nullptr) \
+    v(Int32, executionCounterIncrementForLoop, 1, Normal, nullptr) \
+    v(Int32, executionCounterIncrementForEntry, 15, Normal, nullptr) \
+    \
+    v(Int32, thresholdForFTLOptimizeAfterWarmUp, 100000, Normal, nullptr) \
+    v(Int32, thresholdForFTLOptimizeSoon, 1000, Normal, nullptr) \
+    v(Int32, ftlTierUpCounterIncrementForLoop, 1, Normal, nullptr) \
+    v(Int32, ftlTierUpCounterIncrementForReturn, 15, Normal, nullptr) \
+    v(Unsigned, ftlOSREntryFailureCountForReoptimization, 15, Normal, nullptr) \
+    v(Unsigned, ftlOSREntryRetryThreshold, 100, Normal, nullptr) \
+    \
+    v(Int32, evalThresholdMultiplier, 10, Normal, nullptr) \
+    v(Unsigned, maximumEvalCacheableSourceLength, 256, Normal, nullptr) \
+    \
+    v(Bool, randomizeExecutionCountsBetweenCheckpoints, false, Normal, nullptr) \
+    v(Int32, maximumExecutionCountsBetweenCheckpointsForBaseline, 1000, Normal, nullptr) \
+    v(Int32, maximumExecutionCountsBetweenCheckpointsForUpperTiers, 50000, Normal, nullptr) \
+    \
+    v(Unsigned, likelyToTakeSlowCaseMinimumCount, 20, Normal, nullptr) \
+    v(Unsigned, couldTakeSlowCaseMinimumCount, 10, Normal, nullptr) \
+    \
+    v(Unsigned, osrExitCountForReoptimization, 100, Normal, nullptr) \
+    v(Unsigned, osrExitCountForReoptimizationFromLoop, 5, Normal, nullptr) \
+    \
+    v(Unsigned, reoptimizationRetryCounterMax, 0, Normal, nullptr)  \
+    \
+    v(Unsigned, minimumOptimizationDelay, 1, Normal, nullptr) \
+    v(Unsigned, maximumOptimizationDelay, 5, Normal, nullptr) \
+    v(Double, desiredProfileLivenessRate, 0.75, Normal, nullptr) \
+    v(Double, desiredProfileFullnessRate, 0.35, Normal, nullptr) \
+    \
+    v(Double, doubleVoteRatioForDoubleFormat, 2, Normal, nullptr) \
+    v(Double, structureCheckVoteRatioForHoisting, 1, Normal, nullptr) \
+    v(Double, checkArrayVoteRatioForHoisting, 1, Normal, nullptr) \
+    \
+    v(Unsigned, maximumDirectCallStackSize, 200, Normal, nullptr) \
+    \
+    v(Unsigned, minimumNumberOfScansBetweenRebalance, 100, Normal, nullptr) \
+    v(Unsigned, numberOfGCMarkers, computeNumberOfGCMarkers(8), Normal, nullptr) \
+    v(Bool, useParallelMarkingConstraintSolver, true, Normal, nullptr) \
+    v(Unsigned, opaqueRootMergeThreshold, 1000, Normal, nullptr) \
+    v(Double, minHeapUtilization, 0.8, Normal, nullptr) \
+    v(Double, minMarkedBlockUtilization, 0.9, Normal, nullptr) \
+    v(Unsigned, slowPathAllocsBetweenGCs, 0, Normal, "force a GC on every Nth slow path alloc, where N is specified by this option") \
+    \
+    v(Double, percentCPUPerMBForFullTimer, 0.0003125, Normal, nullptr) \
+    v(Double, percentCPUPerMBForEdenTimer, 0.0025, Normal, nullptr) \
+    v(Double, collectionTimerMaxPercentCPU, 0.05, Normal, nullptr) \
+    \
+    v(Bool, forceWeakRandomSeed, false, Normal, nullptr) \
+    v(Unsigned, forcedWeakRandomSeed, 0, Normal, nullptr) \
+    \
+    v(Bool, useZombieMode, false, Normal, "debugging option to scribble over dead objects with 0xbadbeef0") \
+    v(Bool, useImmortalObjects, false, Normal, "debugging option to keep all objects alive forever") \
+    v(Bool, sweepSynchronously, false, Normal, "debugging option to sweep all dead objects synchronously at GC end before resuming mutator") \
+    v(Unsigned, maxSingleAllocationSize, 0, Configurable, "debugging option to limit individual allocations to a max size (0 = limit not set, N = limit size in bytes)") \
+    \
+    v(GCLogLevel, logGC, GCLogging::None, Normal, "debugging option to log GC activity (0 = None, 1 = Basic, 2 = Verbose)") \
+    v(Bool, useGC, true, Normal, nullptr) \
+    v(Bool, gcAtEnd, false, Normal, "If true, the jsc CLI will do a GC before exiting") \
+    v(Bool, forceGCSlowPaths, false, Normal, "If true, we will force all JIT fast allocations down their slow paths.") \
+    v(Unsigned, gcMaxHeapSize, 0, Normal, nullptr) \
+    v(Unsigned, forceRAMSize, 0, Normal, nullptr) \
+    v(Bool, recordGCPauseTimes, false, Normal, nullptr) \
+    v(Bool, dumpHeapStatisticsAtVMDestruction, false, Normal, nullptr) \
+    v(Bool, forceCodeBlockToJettisonDueToOldAge, false, Normal, "If true, this means that anytime we can jettison a CodeBlock due to old age, we do.") \
+    v(Bool, useEagerCodeBlockJettisonTiming, false, Normal, "If true, the time slices for jettisoning a CodeBlock due to old age are shrunk significantly.") \
+    \
+    v(Bool, useTypeProfiler, false, Normal, nullptr) \
+    v(Bool, useControlFlowProfiler, false, Normal, nullptr) \
+    \
+    v(Bool, useSamplingProfiler, false, Normal, nullptr) \
+    v(Unsigned, sampleInterval, 1000, Normal, "Time between stack traces in microseconds.") \
+    v(Bool, collectSamplingProfilerDataForJSCShell, false, Normal, "This corresponds to the JSC shell's --sample option.") \
+    v(Unsigned, samplingProfilerTopFunctionsCount, 12, Normal, "Number of top functions to report when using the command line interface.") \
+    v(Unsigned, samplingProfilerTopBytecodesCount, 40, Normal, "Number of top bytecodes to report when using the command line interface.") \
+    v(OptionString, samplingProfilerPath, nullptr, Normal, "The path to the directory to write sampiling profiler output to. This probably will not work with WK2 unless the path is in the whitelist.") \
+    v(Bool, sampleCCode, false, Normal, "Causes the sampling profiler to record profiling data for C frames.") \
+    \
+    v(Bool, alwaysGeneratePCToCodeOriginMap, false, Normal, "This will make sure we always generate a PCToCodeOriginMap for JITed code.") \
+    \
+    v(Bool, verifyHeap, false, Normal, nullptr) \
+    v(Unsigned, numberOfGCCyclesToRecordForVerification, 3, Normal, nullptr) \
+    \
+    v(Unsigned, exceptionStackTraceLimit, 100, Normal, "Stack trace limit for internal Exception object") \
+    v(Unsigned, defaultErrorStackTraceLimit, 100, Normal, "The default value for Error.stackTraceLimit") \
+    v(Bool, useExceptionFuzz, false, Normal, nullptr) \
+    v(Unsigned, fireExceptionFuzzAt, 0, Normal, nullptr) \
+    v(Bool, validateDFGExceptionHandling, false, Normal, "Causes the DFG to emit code validating exception handling for each node that can exit") /* This is true by default on Debug builds */\
+    v(Bool, dumpSimulatedThrows, false, Normal, "Dumps the call stack of the last simulated throw if exception scope verification fails") \
+    v(Bool, validateExceptionChecks, false, Normal, "Verifies that needed exception checks are performed.") \
+    v(Unsigned, unexpectedExceptionStackTraceLimit, 100, Normal, "Stack trace limit for debugging unexpected exceptions observed in the VM") \
+    \
+    v(Bool, useExecutableAllocationFuzz, false, Normal, nullptr) \
+    v(Unsigned, fireExecutableAllocationFuzzAt, 0, Normal, nullptr) \
+    v(Unsigned, fireExecutableAllocationFuzzAtOrAfter, 0, Normal, nullptr) \
+    v(Bool, verboseExecutableAllocationFuzz, false, Normal, nullptr) \
+    \
+    v(Bool, useOSRExitFuzz, false, Normal, nullptr) \
+    v(Unsigned, fireOSRExitFuzzAtStatic, 0, Normal, nullptr) \
+    v(Unsigned, fireOSRExitFuzzAt, 0, Normal, nullptr) \
+    v(Unsigned, fireOSRExitFuzzAtOrAfter, 0, Normal, nullptr) \
+    \
+    v(Bool, useRandomizingFuzzerAgent, false, Normal, nullptr) \
+    v(Unsigned, seedOfRandomizingFuzzerAgent, 1, Normal, nullptr) \
+    v(Bool, dumpRandomizingFuzzerAgentPredictions, false, Normal, nullptr) \
+    v(Bool, useDoublePredictionFuzzerAgent, false, Normal, nullptr) \
+    \
+    v(Bool, logPhaseTimes, false, Normal, nullptr) \
+    v(Double, rareBlockPenalty, 0.001, Normal, nullptr) \
+    v(Bool, airLinearScanVerbose, false, Normal, nullptr) \
+    v(Bool, airLinearScanSpillsEverything, false, Normal, nullptr) \
+    v(Bool, airForceBriggsAllocator, false, Normal, nullptr) \
+    v(Bool, airForceIRCAllocator, false, Normal, nullptr) \
+    v(Bool, airRandomizeRegs, false, Normal, nullptr) \
+    v(Unsigned, airRandomizeRegsSeed, 0, Normal, nullptr) \
+    v(Bool, coalesceSpillSlots, true, Normal, nullptr) \
+    v(Bool, logAirRegisterPressure, false, Normal, nullptr) \
+    v(Bool, useB3TailDup, true, Normal, nullptr) \
+    v(Unsigned, maxB3TailDupBlockSize, 3, Normal, nullptr) \
+    v(Unsigned, maxB3TailDupBlockSuccessors, 3, Normal, nullptr) \
+    \
+    v(Bool, useDollarVM, false, Restricted, "installs the $vm debugging tool in global objects") \
+    v(OptionString, functionOverrides, nullptr, Restricted, "file with debugging overrides for function bodies") \
+    v(Bool, useSigillCrashAnalyzer, false, Configurable, "logs data about SIGILL crashes") \
+    \
+    v(Unsigned, watchdog, 0, Normal, "watchdog timeout (0 = Disabled, N = a timeout period of N milliseconds)") \
+    v(Bool, usePollingTraps, false, Normal, "use polling (instead of signalling) VM traps") \
+    \
+    v(Bool, useMachForExceptions, true, Normal, "Use mach exceptions rather than signals to handle faults and pass thread messages. (This does nothing on platforms without mach)") \
+    \
+    v(Bool, useICStats, false, Normal, nullptr) \
+    \
+    v(Unsigned, prototypeHitCountForLLIntCaching, 2, Normal, "Number of prototype property hits before caching a prototype in the LLInt. A count of 0 means never cache.") \
+    \
+    v(Bool, dumpCompiledRegExpPatterns, false, Normal, nullptr) \
+    \
+    v(Bool, dumpModuleRecord, false, Normal, nullptr) \
+    v(Bool, dumpModuleLoadingState, false, Normal, nullptr) \
+    v(Bool, exposeInternalModuleLoader, false, Normal, "expose the internal module loader object to the global space for debugging") \
+    \
+    v(Bool, useSuperSampler, false, Normal, nullptr) \
+    \
+    v(Bool, useSourceProviderCache, true, Normal, "If false, the parser will not use the source provider cache. It's good to verify everything works when this is false. Because the cache is so successful, it can mask bugs.") \
+    v(Bool, useCodeCache, true, Normal, "If false, the unlinked byte code cache will not be used.") \
+    \
+    v(Bool, useWebAssembly, true, Normal, "Expose the WebAssembly global object.") \
+    \
+    v(Bool, enableSpectreMitigations, true, Restricted, "Enable Spectre mitigations.") \
+    v(Bool, enableSpectreGadgets, false, Restricted, "enable gadgets to test Spectre mitigations.") \
+    v(Bool, zeroStackFrame, false, Normal, "Zero stack frame on entry to a function.") \
+    \
+    v(Bool, failToCompileWebAssemblyCode, false, Normal, "If true, no Wasm::Plan will sucessfully compile a function.") \
+    v(Size, webAssemblyPartialCompileLimit, 5000, Normal, "Limit on the number of bytes a Wasm::Plan::compile should attempt before checking for other work.") \
+    v(Unsigned, webAssemblyBBQAirOptimizationLevel, 0, Normal, "Air Optimization level for BBQ Web Assembly module compilations.") \
+    v(Unsigned, webAssemblyBBQB3OptimizationLevel, 1, Normal, "B3 Optimization level for BBQ Web Assembly module compilations.") \
+    v(Unsigned, webAssemblyOMGOptimizationLevel, Options::defaultB3OptLevel(), Normal, "B3 Optimization level for OMG Web Assembly module compilations.") \
+    \
+    v(Bool, useBBQTierUpChecks, true, Normal, "Enables tier up checks for our BBQ code.") \
+    v(Bool, useWebAssemblyOSR, true, Normal, nullptr) \
+    v(Int32, thresholdForOMGOptimizeAfterWarmUp, 50000, Normal, "The count before we tier up a function to OMG.") \
+    v(Int32, thresholdForOMGOptimizeSoon, 500, Normal, nullptr) \
+    v(Int32, omgTierUpCounterIncrementForLoop, 1, Normal, "The amount the tier up counter is incremented on each loop backedge.") \
+    v(Int32, omgTierUpCounterIncrementForEntry, 15, Normal, "The amount the tier up counter is incremented on each function entry.") \
+    /* FIXME: enable fast memories on iOS and pre-allocate them. https://bugs.webkit.org/show_bug.cgi?id=170774 */ \
+    v(Bool, useWebAssemblyFastMemory, !isIOS(), Normal, "If true, we will try to use a 32-bit address space with a signal handler to bounds check wasm memory.") \
+    v(Bool, logWebAssemblyMemory, false, Normal, nullptr) \
+    v(Unsigned, webAssemblyFastMemoryRedzonePages, 128, Normal, "WebAssembly fast memories use 4GiB virtual allocations, plus a redzone (counted as multiple of 64KiB WebAssembly pages) at the end to catch reg+imm accesses which exceed 32-bit, anything beyond the redzone is explicitly bounds-checked") \
+    v(Bool, crashIfWebAssemblyCantFastMemory, false, Normal, "If true, we will crash if we can't obtain fast memory for wasm.") \
+    v(Unsigned, maxNumWebAssemblyFastMemories, 4, Normal, nullptr) \
+    v(Bool, useFastTLSForWasmContext, true, Normal, "If true, we will store context in fast TLS. If false, we will pin it to a register.") \
+    v(Bool, wasmBBQUsesAir, true, Normal, nullptr) \
+    v(Size, webAssemblyBBQAirModeThreshold, isIOS() ? (10 * MB) : 0, Normal, "If 0, we always use BBQ Air. If Wasm module code size hits this threshold, we compile Wasm module with B3 BBQ mode.") \
+    v(Bool, useWebAssemblyStreamingApi, enableWebAssemblyStreamingApi, Normal, "Allow to run WebAssembly's Streaming API") \
+    v(Bool, useCallICsForWebAssemblyToJSCalls, true, Normal, "If true, we will use CallLinkInfo to inline cache Wasm to JS calls.") \
+    v(Bool, useEagerWebAssemblyModuleHashing, false, Normal, "Unnamed WebAssembly modules are identified in backtraces through their hash, if available.") \
+    v(Bool, useWebAssemblyReferences, true, Normal, "Allow types from the wasm references spec.") \
+    v(Bool, useWeakRefs, false, Normal, "Expose the WeakRef constructor.") \
+    v(Bool, useBigInt, false, Normal, "If true, we will enable BigInt support.") \
+    v(Bool, useNullishAwareOperators, false, Normal, "Enable support for ?. and ?? operators.") \
+    v(Bool, useArrayAllocationProfiling, true, Normal, "If true, we will use our normal array allocation profiling. If false, the allocation profile will always claim to be undecided.") \
+    v(Bool, forcePolyProto, false, Normal, "If true, create_this will always create an object with a poly proto structure.") \
+    v(Bool, forceMiniVMMode, false, Normal, "If true, it will force mini VM mode on.") \
+    v(Bool, useTracePoints, false, Normal, nullptr) \
+    v(Bool, traceLLIntExecution, false, Configurable, nullptr) \
+    v(Bool, traceLLIntSlowPath, false, Configurable, nullptr) \
+    v(Bool, traceBaselineJITExecution, false, Normal, nullptr) \
+    v(Unsigned, thresholdForGlobalLexicalBindingEpoch, UINT_MAX, Normal, "Threshold for global lexical binding epoch. If the epoch reaches to this value, CodeBlock metadata for scope operations will be revised globally. It needs to be greater than 1.") \
+    v(OptionString, diskCachePath, nullptr, Restricted, nullptr) \
+    v(Bool, forceDiskCache, false, Restricted, nullptr) \
+    v(Bool, validateAbstractInterpreterState, false, Restricted, nullptr) \
+    v(Double, validateAbstractInterpreterStateProbability, 0.5, Normal, nullptr) \
+    v(OptionString, dumpJITMemoryPath, nullptr, Restricted, nullptr) \
+    v(Double, dumpJITMemoryFlushInterval, 10, Restricted, "Maximum time in between flushes of the JIT memory dump in seconds.") \
+    v(Bool, useUnlinkedCodeBlockJettisoning, false, Normal, "If true, UnlinkedCodeBlock can be jettisoned.") \
+
+enum OptionEquivalence {
+    SameOption,
+    InvertedOption,
+};
+
+#define FOR_EACH_JSC_ALIASED_OPTION(v) \
+    v(enableFunctionDotArguments, useFunctionDotArguments, SameOption) \
+    v(enableTailCalls, useTailCalls, SameOption) \
+    v(showDisassembly, dumpDisassembly, SameOption) \
+    v(showDFGDisassembly, dumpDFGDisassembly, SameOption) \
+    v(showFTLDisassembly, dumpFTLDisassembly, SameOption) \
+    v(showAllDFGNodes, dumpAllDFGNodes, SameOption) \
+    v(alwaysDoFullCollection, useGenerationalGC, InvertedOption) \
+    v(enableOSREntryToDFG, useOSREntryToDFG, SameOption) \
+    v(enableOSREntryToFTL, useOSREntryToFTL, SameOption) \
+    v(enableAccessInlining, useAccessInlining, SameOption) \
+    v(enablePolyvariantDevirtualization, usePolyvariantDevirtualization, SameOption) \
+    v(enablePolymorphicAccessInlining, usePolymorphicAccessInlining, SameOption) \
+    v(enablePolymorphicCallInlining, usePolymorphicCallInlining, SameOption) \
+    v(enableMovHintRemoval, useMovHintRemoval, SameOption) \
+    v(enableObjectAllocationSinking, useObjectAllocationSinking, SameOption) \
+    v(enableConcurrentJIT, useConcurrentJIT, SameOption) \
+    v(enableProfiler, useProfiler, SameOption) \
+    v(enableArchitectureSpecificOptimizations, useArchitectureSpecificOptimizations, SameOption) \
+    v(enablePolyvariantCallInlining, usePolyvariantCallInlining, SameOption) \
+    v(enablePolyvariantByIdInlining, usePolyvariantByIdInlining, SameOption) \
+    v(objectsAreImmortal, useImmortalObjects, SameOption) \
+    v(showObjectStatistics, dumpObjectStatistics, SameOption) \
+    v(disableGC, useGC, InvertedOption) \
+    v(enableTypeProfiler, useTypeProfiler, SameOption) \
+    v(enableControlFlowProfiler, useControlFlowProfiler, SameOption) \
+    v(enableExceptionFuzz, useExceptionFuzz, SameOption) \
+    v(enableExecutableAllocationFuzz, useExecutableAllocationFuzz, SameOption) \
+    v(enableOSRExitFuzz, useOSRExitFuzz, SameOption) \
+    v(enableDollarVM, useDollarVM, SameOption) \
+    v(enableWebAssembly, useWebAssembly, SameOption) \
+    v(verboseDFGByteCodeParsing, verboseDFGBytecodeParsing, SameOption) \
+    v(maximumOptimizationCandidateInstructionCount, maximumOptimizationCandidateBytecodeCost, SameOption) \
+    v(maximumFunctionForCallInlineCandidateInstructionCount, maximumFunctionForCallInlineCandidateBytecodeCost, SameOption) \
+    v(maximumFunctionForClosureCallInlineCandidateInstructionCount, maximumFunctionForClosureCallInlineCandidateBytecodeCost, SameOption) \
+    v(maximumFunctionForConstructInlineCandidateInstructionCount, maximumFunctionForConstructInlineCandidateBytecoodeCost, SameOption) \
+    v(maximumFTLCandidateInstructionCount, maximumFTLCandidateBytecodeCost, SameOption) \
+    v(maximumInliningCallerSize, maximumInliningCallerBytecodeCost, SameOption) \
+
+
+constexpr size_t countNumberOfJSCOptions()
+{
+#define COUNT_OPTION(type_, name_, defaultValue_, availability_, description_) count++;
+    size_t count = 0;
+    FOR_EACH_JSC_OPTION(COUNT_OPTION);
+    return count;
+#undef COUNT_OPTION
+}
+
+constexpr size_t NumberOfOptions = countNumberOfJSCOptions();
+
+} // namespace JSC
+
index dff8af4..01364ed 100644 (file)
@@ -470,6 +470,9 @@ VM::VM(VMType vmType, HeapType heapType)
         ensureShadowChicken();
 
     VMInspector::instance().add(this);
+
+    if (!g_jscConfig.disabledFreezingForTesting)
+        Config::permanentlyFreeze();
 }
 
 static ReadWriteLock s_destructionLock;
index fffa4a1..926381e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -102,11 +102,13 @@ FunctionOverrides& FunctionOverrides::overrides()
     
 FunctionOverrides::FunctionOverrides(const char* overridesFileName)
 {
+    RELEASE_ASSERT(g_jscConfig.restrictedOptionsEnabled);
     parseOverridesInFile(holdLock(m_lock), overridesFileName);
 }
 
 void FunctionOverrides::reinstallOverrides()
 {
+    RELEASE_ASSERT(g_jscConfig.restrictedOptionsEnabled);
     FunctionOverrides& overrides = FunctionOverrides::overrides();
     auto locker = holdLock(overrides.m_lock);
     const char* overridesFileName = Options::functionOverrides();
@@ -143,7 +145,8 @@ static void initializeOverrideInfo(const SourceCode& origCode, const String& new
     
 bool FunctionOverrides::initializeOverrideFor(const SourceCode& origCode, FunctionOverrides::OverrideInfo& result)
 {
-    ASSERT(Options::functionOverrides());
+    RELEASE_ASSERT(g_jscConfig.restrictedOptionsEnabled);
+    RELEASE_ASSERT(Options::functionOverrides());
     FunctionOverrides& overrides = FunctionOverrides::overrides();
 
     String sourceString = origCode.view().toString();
@@ -235,6 +238,7 @@ static String parseClause(const char* keyword, size_t keywordLength, FILE* file,
 
 void FunctionOverrides::parseOverridesInFile(const AbstractLocker&, const char* fileName)
 {
+    RELEASE_ASSERT(g_jscConfig.restrictedOptionsEnabled);
     if (!fileName)
         return;
     
index 4d62fb5..de8571d 100644 (file)
@@ -30,6 +30,7 @@
 #include "CodeBlock.h"
 #include "DOMAttributeGetterSetter.h"
 #include "DOMJITGetterSetter.h"
+#include "Debugger.h"
 #include "FrameTracers.h"
 #include "FunctionCodeBlock.h"
 #include "GetterSetter.h"
@@ -40,6 +41,7 @@
 #include "JSONObject.h"
 #include "JSProxy.h"
 #include "JSString.h"
+#include "Options.h"
 #include "Parser.h"
 #include "ShadowChicken.h"
 #include "Snippet.h"
@@ -62,20 +64,37 @@ using namespace JSC;
 
 namespace {
 
+// We must RELEASE_ASSERT(Options::useDollarVM()) in all JSDollarVM functions
+// that are non-trivial at an eye's glance. This includes (but is not limited to):
+//      constructors
+//      create() factory
+//      createStructure() factory
+//      finishCreation()
+//      HOST_CALL or operation functions
+//      Constructors and methods of utility and test classes
+//
+// The only exception are some constexpr constructors used for instantiating
+// globals (since these must have trivial constructors) e.g. DOMJITAttribute.
+// Instead, these constructors should always be ALWAYS_INLINE.
+
 class JSDollarVMCallFrame : public JSDestructibleObject {
     using Base = JSDestructibleObject;
 public:
     JSDollarVMCallFrame(VM& vm, Structure* structure)
         : Base(vm, structure)
-    { }
+    {
+        RELEASE_ASSERT(Options::useDollarVM());
+    }
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     }
 
     static JSDollarVMCallFrame* create(ExecState* exec, unsigned requestedFrameIndex)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         JSGlobalObject* globalObject = exec->lexicalGlobalObject();
         Structure* structure = createStructure(vm, globalObject, jsNull());
@@ -86,6 +105,7 @@ public:
 
     void finishCreation(VM& vm, CallFrame* frame, unsigned requestedFrameIndex)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         Base::finishCreation(vm);
 
         auto addProperty = [&] (VM& vm, const char* name, JSValue value) {
@@ -123,6 +143,7 @@ public:
 private:
     void addProperty(VM& vm, const char* name, JSValue value)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         Identifier identifier = Identifier::fromString(vm, name);
         putDirect(vm, identifier, value);
     }
@@ -138,6 +159,7 @@ public:
     Element(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     typedef JSNonFinalObject Base;
@@ -147,6 +169,7 @@ public:
 
     static Element* create(VM& vm, JSGlobalObject* globalObject, Root* root)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         Structure* structure = createStructure(vm, globalObject, jsNull());
         Element* element = new (NotNull, allocateCell<Element>(vm.heap)) Element(vm, structure);
         element->finishCreation(vm, root);
@@ -167,6 +190,7 @@ public:
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     }
 
@@ -193,6 +217,7 @@ public:
     Root(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     Element* element()
@@ -208,6 +233,7 @@ public:
 
     static Root* create(VM& vm, JSGlobalObject* globalObject)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         Structure* structure = createStructure(vm, globalObject, jsNull());
         Root* root = new (NotNull, allocateCell<Root>(vm.heap)) Root(vm, structure);
         root->finishCreation(vm);
@@ -220,6 +246,7 @@ public:
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     }
 
@@ -239,6 +266,7 @@ public:
     SimpleObject(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     typedef JSNonFinalObject Base;
@@ -246,6 +274,7 @@ public:
 
     static SimpleObject* create(VM& vm, JSGlobalObject* globalObject)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         Structure* structure = createStructure(vm, globalObject, jsNull());
         SimpleObject* simpleObject = new (NotNull, allocateCell<SimpleObject>(vm.heap)) SimpleObject(vm, structure);
         simpleObject->finishCreation(vm);
@@ -262,6 +291,7 @@ public:
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     }
 
@@ -287,6 +317,7 @@ public:
     ImpureGetter(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     DECLARE_INFO;
@@ -295,11 +326,13 @@ public:
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     }
 
     static ImpureGetter* create(VM& vm, Structure* structure, JSObject* delegate)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         ImpureGetter* getter = new (NotNull, allocateCell<ImpureGetter>(vm.heap)) ImpureGetter(vm, structure);
         getter->finishCreation(vm, delegate);
         return getter;
@@ -307,6 +340,7 @@ public:
 
     void finishCreation(VM& vm, JSObject* delegate)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         Base::finishCreation(vm);
         if (delegate)
             m_delegate.set(vm, this, delegate);
@@ -314,6 +348,7 @@ public:
 
     static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName name, PropertySlot& slot)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         auto scope = DECLARE_THROW_SCOPE(vm);
         ImpureGetter* thisObject = jsCast<ImpureGetter*>(object);
@@ -349,6 +384,7 @@ public:
     CustomGetter(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     DECLARE_INFO;
@@ -357,11 +393,13 @@ public:
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     }
 
     static CustomGetter* create(VM& vm, Structure* structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         CustomGetter* getter = new (NotNull, allocateCell<CustomGetter>(vm.heap)) CustomGetter(vm, structure);
         getter->finishCreation(vm);
         return getter;
@@ -369,6 +407,7 @@ public:
 
     static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         CustomGetter* thisObject = jsCast<CustomGetter*>(object);
         if (propertyName == PropertyName(Identifier::fromString(vm, "customGetter"))) {
@@ -387,6 +426,7 @@ public:
 private:
     static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -402,6 +442,7 @@ private:
     
     static EncodedJSValue customGetterAcessor(ExecState* exec, EncodedJSValue thisValue, PropertyName)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         auto scope = DECLARE_THROW_SCOPE(vm);
         
@@ -423,6 +464,7 @@ public:
 
     static RuntimeArray* create(ExecState* exec)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         JSGlobalObject* globalObject = exec->lexicalGlobalObject();
         Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject));
@@ -436,6 +478,7 @@ public:
 
     static void destroy(JSCell* cell)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         static_cast<RuntimeArray*>(cell)->RuntimeArray::~RuntimeArray();
     }
 
@@ -443,6 +486,7 @@ public:
 
     static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
         if (propertyName == vm.propertyNames->length) {
@@ -461,6 +505,7 @@ public:
 
     static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
         if (index < thisObject->getLength()) {
             slot.setValue(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::DontEnum, jsNumber(thisObject->m_vector[index]));
@@ -486,17 +531,20 @@ public:
 
     static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return globalObject->arrayPrototype();
     }
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(DerivedArrayType, StructureFlags), info(), ArrayClass);
     }
 
 protected:
     void finishCreation(ExecState* exec)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         Base::finishCreation(vm);
         ASSERT(inherits(vm, info()));
@@ -509,10 +557,12 @@ private:
     RuntimeArray(ExecState* exec, Structure* structure)
         : JSArray(exec->vm(), structure, 0)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     static EncodedJSValue lengthGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -530,6 +580,7 @@ public:
     DOMJITNode(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     DECLARE_INFO;
@@ -538,12 +589,14 @@ public:
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
     }
 
 #if ENABLE(JIT)
     static Ref<Snippet> checkSubClassSnippet()
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         Ref<Snippet> snippet = Snippet::create();
         snippet->setGenerator([=](CCallHelpers& jit, SnippetParams& params) {
             CCallHelpers::JumpList failureCases;
@@ -556,6 +609,7 @@ public:
 
     static DOMJITNode* create(VM& vm, Structure* structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         DOMJITNode* getter = new (NotNull, allocateCell<DOMJITNode>(vm.heap)) DOMJITNode(vm, structure);
         getter->finishCreation(vm);
         return getter;
@@ -577,6 +631,7 @@ public:
     DOMJITGetter(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     DECLARE_INFO;
@@ -585,11 +640,13 @@ public:
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
     }
 
     static DOMJITGetter* create(VM& vm, Structure* structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         DOMJITGetter* getter = new (NotNull, allocateCell<DOMJITGetter>(vm.heap)) DOMJITGetter(vm, structure);
         getter->finishCreation(vm);
         return getter;
@@ -597,7 +654,7 @@ public:
 
     class DOMJITAttribute : public DOMJIT::GetterSetter {
     public:
-        constexpr DOMJITAttribute()
+        ALWAYS_INLINE constexpr DOMJITAttribute()
             : DOMJIT::GetterSetter(
                 DOMJITGetter::customGetter,
 #if ENABLE(JIT)
@@ -612,6 +669,7 @@ public:
 #if ENABLE(JIT)
         static EncodedJSValue JIT_OPERATION slowCall(ExecState* exec, void* pointer)
         {
+            RELEASE_ASSERT(Options::useDollarVM());
             VM& vm = exec->vm();
             NativeCallFrameTracer tracer(vm, exec);
             return JSValue::encode(jsNumber(static_cast<DOMJITGetter*>(pointer)->value()));
@@ -619,6 +677,7 @@ public:
 
         static Ref<DOMJIT::CallDOMGetterSnippet> callDOMGetter()
         {
+            RELEASE_ASSERT(Options::useDollarVM());
             Ref<DOMJIT::CallDOMGetterSnippet> snippet = DOMJIT::CallDOMGetterSnippet::create();
             snippet->requireGlobalObject = false;
             snippet->setGenerator([=](CCallHelpers& jit, SnippetParams& params) {
@@ -638,6 +697,7 @@ private:
 
     static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         DOMJITNode* thisObject = jsDynamicCast<DOMJITNode*>(vm, JSValue::decode(thisValue));
         ASSERT(thisObject);
@@ -649,6 +709,7 @@ static const DOMJITGetter::DOMJITAttribute DOMJITGetterDOMJIT;
 
 void DOMJITGetter::finishCreation(VM& vm)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     Base::finishCreation(vm);
     const DOMJIT::GetterSetter* domJIT = &DOMJITGetterDOMJIT;
     auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, domJIT->getter(), nullptr, DOMAttributeAnnotation { DOMJITNode::info(), domJIT });
@@ -660,6 +721,7 @@ public:
     DOMJITGetterComplex(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     DECLARE_INFO;
@@ -668,11 +730,13 @@ public:
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
     }
 
     static DOMJITGetterComplex* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         DOMJITGetterComplex* getter = new (NotNull, allocateCell<DOMJITGetterComplex>(vm.heap)) DOMJITGetterComplex(vm, structure);
         getter->finishCreation(vm, globalObject);
         return getter;
@@ -680,7 +744,7 @@ public:
 
     class DOMJITAttribute : public DOMJIT::GetterSetter {
     public:
-        constexpr DOMJITAttribute()
+        ALWAYS_INLINE constexpr DOMJITAttribute()
             : DOMJIT::GetterSetter(
                 DOMJITGetterComplex::customGetter,
 #if ENABLE(JIT)
@@ -695,6 +759,7 @@ public:
 #if ENABLE(JIT)
         static EncodedJSValue JIT_OPERATION slowCall(ExecState* exec, void* pointer)
         {
+            RELEASE_ASSERT(Options::useDollarVM());
             VM& vm = exec->vm();
             NativeCallFrameTracer tracer(vm, exec);
             auto scope = DECLARE_THROW_SCOPE(vm);
@@ -709,6 +774,7 @@ public:
 
         static Ref<DOMJIT::CallDOMGetterSnippet> callDOMGetter()
         {
+            RELEASE_ASSERT(Options::useDollarVM());
             Ref<DOMJIT::CallDOMGetterSnippet> snippet = DOMJIT::CallDOMGetterSnippet::create();
             static_assert(GPRInfo::numberOfRegisters >= 4, "Number of registers should be larger or equal to 4.");
             unsigned numGPScratchRegisters = GPRInfo::numberOfRegisters - 4;
@@ -733,6 +799,7 @@ private:
 
     static EncodedJSValue JSC_HOST_CALL functionEnableException(ExecState* exec)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         auto* object = jsDynamicCast<DOMJITGetterComplex*>(vm, exec->thisValue());
         if (object)
@@ -742,6 +809,7 @@ private:
 
     static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -759,6 +827,7 @@ static const DOMJITGetterComplex::DOMJITAttribute DOMJITGetterComplexDOMJIT;
 
 void DOMJITGetterComplex::finishCreation(VM& vm, JSGlobalObject* globalObject)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     Base::finishCreation(vm);
     const DOMJIT::GetterSetter* domJIT = &DOMJITGetterComplexDOMJIT;
     auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, domJIT->getter(), nullptr, DOMAttributeAnnotation { DOMJITGetterComplex::info(), domJIT });
@@ -771,20 +840,22 @@ public:
     DOMJITFunctionObject(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     DECLARE_INFO;
     typedef DOMJITNode Base;
     static const unsigned StructureFlags = Base::StructureFlags;
 
-
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
     }
 
     static DOMJITFunctionObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         DOMJITFunctionObject* object = new (NotNull, allocateCell<DOMJITFunctionObject>(vm.heap)) DOMJITFunctionObject(vm, structure);
         object->finishCreation(vm, globalObject);
         return object;
@@ -792,7 +863,9 @@ public:
 
     static EncodedJSValue JSC_HOST_CALL functionWithTypeCheck(ExecState* exec)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
+        NativeCallFrameTracer tracer(vm, exec);
         auto scope = DECLARE_THROW_SCOPE(vm);
 
         DOMJITNode* thisObject = jsDynamicCast<DOMJITNode*>(vm, exec->thisValue());
@@ -803,6 +876,7 @@ public:
 
     static EncodedJSValue JIT_OPERATION functionWithoutTypeCheck(ExecState* exec, DOMJITNode* node)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         NativeCallFrameTracer tracer(vm, exec);
         return JSValue::encode(jsNumber(node->value()));
@@ -811,6 +885,7 @@ public:
 #if ENABLE(JIT)
     static Ref<Snippet> checkSubClassSnippet()
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         Ref<Snippet> snippet = Snippet::create();
         snippet->numFPScratchRegisters = 1;
         snippet->setGenerator([=](CCallHelpers& jit, SnippetParams& params) {
@@ -833,6 +908,7 @@ static const DOMJIT::Signature DOMJITFunctionObjectSignature(DOMJITFunctionObjec
 
 void DOMJITFunctionObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     Base::finishCreation(vm);
     putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "func"), 0, functionWithTypeCheck, NoIntrinsic, &DOMJITFunctionObjectSignature, static_cast<unsigned>(PropertyAttribute::ReadOnly));
 }
@@ -842,20 +918,22 @@ public:
     DOMJITCheckSubClassObject(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     DECLARE_INFO;
     typedef DOMJITNode Base;
     static const unsigned StructureFlags = Base::StructureFlags;
 
-
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
     }
 
     static DOMJITCheckSubClassObject* create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         DOMJITCheckSubClassObject* object = new (NotNull, allocateCell<DOMJITCheckSubClassObject>(vm.heap)) DOMJITCheckSubClassObject(vm, structure);
         object->finishCreation(vm, globalObject);
         return object;
@@ -863,6 +941,7 @@ public:
 
     static EncodedJSValue JSC_HOST_CALL functionWithTypeCheck(ExecState* exec)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -874,6 +953,7 @@ public:
 
     static EncodedJSValue JIT_OPERATION functionWithoutTypeCheck(ExecState* exec, DOMJITNode* node)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         NativeCallFrameTracer tracer(vm, exec);
         return JSValue::encode(jsNumber(node->value()));
@@ -887,6 +967,7 @@ static const DOMJIT::Signature DOMJITCheckSubClassObjectSignature(DOMJITCheckSub
 
 void DOMJITCheckSubClassObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     Base::finishCreation(vm);
     putDirectNativeFunction(vm, globalObject, Identifier::fromString(vm, "func"), 0, functionWithTypeCheck, NoIntrinsic, &DOMJITCheckSubClassObjectSignature, static_cast<unsigned>(PropertyAttribute::ReadOnly));
 }
@@ -896,6 +977,7 @@ public:
     DOMJITGetterBaseJSObject(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     DECLARE_INFO;
@@ -904,11 +986,13 @@ public:
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(JSC::JSType(LastJSCObjectType + 1), StructureFlags), info());
     }
 
     static DOMJITGetterBaseJSObject* create(VM& vm, Structure* structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         DOMJITGetterBaseJSObject* getter = new (NotNull, allocateCell<DOMJITGetterBaseJSObject>(vm.heap)) DOMJITGetterBaseJSObject(vm, structure);
         getter->finishCreation(vm);
         return getter;
@@ -916,7 +1000,7 @@ public:
 
     class DOMJITAttribute : public DOMJIT::GetterSetter {
     public:
-        constexpr DOMJITAttribute()
+        ALWAYS_INLINE constexpr DOMJITAttribute()
             : DOMJIT::GetterSetter(
                 DOMJITGetterBaseJSObject::customGetter,
 #if ENABLE(JIT)
@@ -931,6 +1015,7 @@ public:
 #if ENABLE(JIT)
         static EncodedJSValue JIT_OPERATION slowCall(ExecState* exec, void* pointer)
         {
+            RELEASE_ASSERT(Options::useDollarVM());
             VM& vm = exec->vm();
             NativeCallFrameTracer tracer(vm, exec);
             JSObject* object = static_cast<JSObject*>(pointer);
@@ -939,6 +1024,7 @@ public:
 
         static Ref<DOMJIT::CallDOMGetterSnippet> callDOMGetter()
         {
+            RELEASE_ASSERT(Options::useDollarVM());
             Ref<DOMJIT::CallDOMGetterSnippet> snippet = DOMJIT::CallDOMGetterSnippet::create();
             snippet->requireGlobalObject = false;
             snippet->setGenerator([=](CCallHelpers& jit, SnippetParams& params) {
@@ -958,6 +1044,7 @@ private:
 
     static EncodedJSValue customGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         VM& vm = exec->vm();
         JSObject* thisObject = jsDynamicCast<JSObject*>(vm, JSValue::decode(thisValue));
         RELEASE_ASSERT(thisObject);
@@ -969,6 +1056,7 @@ static const DOMJITGetterBaseJSObject::DOMJITAttribute DOMJITGetterBaseJSObjectD
 
 void DOMJITGetterBaseJSObject::finishCreation(VM& vm)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     Base::finishCreation(vm);
     const DOMJIT::GetterSetter* domJIT = &DOMJITGetterBaseJSObjectDOMJIT;
     auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, domJIT->getter(), nullptr, DOMAttributeAnnotation { JSObject::info(), domJIT });
@@ -995,10 +1083,13 @@ public:
 
     JSTestCustomGetterSetter(VM& vm, Structure* structure)
         : Base(vm, structure)
-    { }
+    {
+        RELEASE_ASSERT(Options::useDollarVM());
+    }
 
     static JSTestCustomGetterSetter* create(VM& vm, JSGlobalObject*, Structure* structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         JSTestCustomGetterSetter* result = new (NotNull, allocateCell<JSTestCustomGetterSetter>(vm.heap)) JSTestCustomGetterSetter(vm, structure);
         result->finishCreation(vm);
         return result;
@@ -1008,6 +1099,7 @@ public:
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, globalObject->objectPrototype(), TypeInfo(ObjectType, StructureFlags), info());
     }
 
@@ -1030,6 +1122,7 @@ static EncodedJSValue customGetValue(ExecState* exec, EncodedJSValue slotValue,
 
 static bool customSetAccessor(ExecState* exec, EncodedJSValue thisObject, EncodedJSValue encodedValue)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
 
     JSValue value = JSValue::decode(encodedValue);
@@ -1043,6 +1136,7 @@ static bool customSetAccessor(ExecState* exec, EncodedJSValue thisObject, Encode
 
 static bool customSetValue(ExecState* exec, EncodedJSValue slotValue, EncodedJSValue encodedValue)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
 
     RELEASE_ASSERT(JSValue::decode(slotValue).inherits<JSTestCustomGetterSetter>(exec->vm()));
@@ -1058,6 +1152,7 @@ static bool customSetValue(ExecState* exec, EncodedJSValue slotValue, EncodedJSV
 
 void JSTestCustomGetterSetter::finishCreation(VM& vm)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     Base::finishCreation(vm);
 
     putDirectCustomAccessor(vm, Identifier::fromString(vm, "customValue"),
@@ -1090,6 +1185,7 @@ const ClassInfo JSTestCustomGetterSetter::s_info = { "JSTestCustomGetterSetter",
 
 ElementHandleOwner* Element::handleOwner()
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     static ElementHandleOwner* owner = 0;
     if (!owner)
         owner = new ElementHandleOwner();
@@ -1098,6 +1194,7 @@ ElementHandleOwner* Element::handleOwner()
 
 void Element::finishCreation(VM& vm, Root* root)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     Base::finishCreation(vm);
     setRoot(vm, root);
     m_root->setElement(this);
@@ -1130,12 +1227,14 @@ public:
         , m_client(this)
         , m_streamingParser(m_info.get(), m_client)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     using Base = JSDestructibleObject;
 
     static WasmStreamingParser* create(VM& vm, JSGlobalObject* globalObject)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         Structure* structure = createStructure(vm, globalObject, jsNull());
         WasmStreamingParser* result = new (NotNull, allocateCell<WasmStreamingParser>(vm.heap)) WasmStreamingParser(vm, structure);
         result->finishCreation(vm);
@@ -1144,6 +1243,7 @@ public:
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     }
 
@@ -1151,6 +1251,7 @@ public:
 
     void finishCreation(VM& vm)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         Base::finishCreation(vm);
 
         JSGlobalObject* globalObject = this->globalObject(vm);
@@ -1169,8 +1270,10 @@ const ClassInfo WasmStreamingParser::s_info = { "WasmStreamingParser", &Base::s_
 
 EncodedJSValue JSC_HOST_CALL functionWasmStreamingParserAddBytes(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(exec->vm());
+
     auto* thisObject = jsDynamicCast<WasmStreamingParser*>(vm, exec->thisValue());
     if (!thisObject)
         RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(false)));
@@ -1182,6 +1285,7 @@ EncodedJSValue JSC_HOST_CALL functionWasmStreamingParserAddBytes(ExecState* exec
 
 EncodedJSValue JSC_HOST_CALL functionWasmStreamingParserFinalize(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     auto* thisObject = jsDynamicCast<WasmStreamingParser*>(vm, exec->thisValue());
     if (!thisObject)
@@ -1201,6 +1305,7 @@ const ClassInfo JSDollarVM::s_info = { "DollarVM", &Base::s_info, nullptr, nullp
 // Usage: $vm.crash()
 static NO_RETURN_DUE_TO_CRASH EncodedJSValue JSC_HOST_CALL functionCrash(ExecState*)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     CRASH();
 }
 
@@ -1208,6 +1313,7 @@ static NO_RETURN_DUE_TO_CRASH EncodedJSValue JSC_HOST_CALL functionCrash(ExecSta
 // Usage: $vm.breakpoint(<condition>)
 static EncodedJSValue JSC_HOST_CALL functionBreakpoint(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     // Nothing should throw here but we might as well double check...
     VM& vm = exec->vm();
     auto scope = DECLARE_CATCH_SCOPE(vm);
@@ -1222,6 +1328,7 @@ static EncodedJSValue JSC_HOST_CALL functionBreakpoint(ExecState* exec)
 // Usage: isDFG = $vm.dfgTrue()
 static EncodedJSValue JSC_HOST_CALL functionDFGTrue(ExecState*)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     return JSValue::encode(jsBoolean(false));
 }
 
@@ -1229,11 +1336,13 @@ static EncodedJSValue JSC_HOST_CALL functionDFGTrue(ExecState*)
 // Usage: isFTL = $vm.ftlTrue()
 static EncodedJSValue JSC_HOST_CALL functionFTLTrue(ExecState*)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     return JSValue::encode(jsBoolean(false));
 }
 
 static EncodedJSValue JSC_HOST_CALL functionCpuMfence(ExecState*)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
 #if CPU(X86_64) && !OS(WINDOWS)
     asm volatile("mfence" ::: "memory");
 #endif
@@ -1242,6 +1351,7 @@ static EncodedJSValue JSC_HOST_CALL functionCpuMfence(ExecState*)
 
 static EncodedJSValue JSC_HOST_CALL functionCpuRdtsc(ExecState*)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
 #if CPU(X86_64) && !OS(WINDOWS)
     unsigned high;
     unsigned low;
@@ -1254,6 +1364,7 @@ static EncodedJSValue JSC_HOST_CALL functionCpuRdtsc(ExecState*)
 
 static EncodedJSValue JSC_HOST_CALL functionCpuCpuid(ExecState*)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
 #if CPU(X86_64) && !OS(WINDOWS)
     WTF::x86_cpuid();
 #endif
@@ -1262,6 +1373,7 @@ static EncodedJSValue JSC_HOST_CALL functionCpuCpuid(ExecState*)
 
 static EncodedJSValue JSC_HOST_CALL functionCpuPause(ExecState*)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
 #if CPU(X86_64) && !OS(WINDOWS)
     asm volatile ("pause" ::: "memory");
 #endif
@@ -1279,6 +1391,7 @@ static EncodedJSValue JSC_HOST_CALL functionCpuPause(ExecState*)
 // and clflush at the address of the butterfly.
 static EncodedJSValue JSC_HOST_CALL functionCpuClflush(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
 #if CPU(X86_64) && !OS(WINDOWS)
     VM& vm = exec->vm();
 
@@ -1324,6 +1437,7 @@ public:
         : m_currentFrame(0)
         , m_jitType(JITType::None)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
     StackVisitor::Status operator()(StackVisitor& visitor) const
@@ -1344,6 +1458,7 @@ private:
 
 static FunctionExecutable* getExecutableForFunction(JSValue theFunctionValue)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     if (!theFunctionValue.isCell())
         return nullptr;
     
@@ -1362,6 +1477,7 @@ static FunctionExecutable* getExecutableForFunction(JSValue theFunctionValue)
 // Usage: isLLInt = $vm.llintTrue()
 static EncodedJSValue JSC_HOST_CALL functionLLintTrue(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     if (!exec)
         return JSValue::encode(jsUndefined());
     CallerFrameJITTypeFunctor functor;
@@ -1373,6 +1489,7 @@ static EncodedJSValue JSC_HOST_CALL functionLLintTrue(ExecState* exec)
 // Usage: isBaselineJIT = $vm.jitTrue()
 static EncodedJSValue JSC_HOST_CALL functionJITTrue(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     if (!exec)
         return JSValue::encode(jsUndefined());
     CallerFrameJITTypeFunctor functor;
@@ -1386,6 +1503,7 @@ static EncodedJSValue JSC_HOST_CALL functionJITTrue(ExecState* exec)
 // $vm.noInline(f);
 static EncodedJSValue JSC_HOST_CALL functionNoInline(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     if (exec->argumentCount() < 1)
         return JSValue::encode(jsUndefined());
     
@@ -1401,6 +1519,7 @@ static EncodedJSValue JSC_HOST_CALL functionNoInline(ExecState* exec)
 // Usage: $vm.gc()
 static EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VMInspector::gc(exec);
     return JSValue::encode(jsUndefined());
 }
@@ -1409,6 +1528,7 @@ static EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
 // Usage: $vm.edenGC()
 static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VMInspector::edenGC(exec);
     return JSValue::encode(jsUndefined());
 }
@@ -1417,6 +1537,7 @@ static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec)
 // Usage: $vm.dumpSubspaceHashes()
 static EncodedJSValue JSC_HOST_CALL functionDumpSubspaceHashes(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     VMInspector::dumpSubspaceHashes(&vm);
     return JSValue::encode(jsUndefined());
@@ -1438,6 +1559,7 @@ static EncodedJSValue JSC_HOST_CALL functionDumpSubspaceHashes(ExecState* exec)
 // concatenation with them.
 static EncodedJSValue JSC_HOST_CALL functionCallFrame(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     unsigned frameNumber = 1;
     if (exec->argumentCount() >= 1) {
         JSValue value = exec->uncheckedArgument(0);
@@ -1458,6 +1580,7 @@ static EncodedJSValue JSC_HOST_CALL functionCallFrame(ExecState* exec)
 // Usage: codeBlockToken = $vm.codeBlockForFrame() // implies frame 0 i.e. current frame.
 static EncodedJSValue JSC_HOST_CALL functionCodeBlockForFrame(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     unsigned frameNumber = 1;
     if (exec->argumentCount() >= 1) {
         JSValue value = exec->uncheckedArgument(0);
@@ -1478,6 +1601,7 @@ static EncodedJSValue JSC_HOST_CALL functionCodeBlockForFrame(ExecState* exec)
 
 static CodeBlock* codeBlockFromArg(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     if (exec->argumentCount() < 1)
         return nullptr;
@@ -1511,6 +1635,7 @@ static CodeBlock* codeBlockFromArg(ExecState* exec)
 // a JS object. Hence, you cannot do string concatenation with it.
 static EncodedJSValue JSC_HOST_CALL functionCodeBlockFor(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     CodeBlock* codeBlock = codeBlockFromArg(exec);
     WTF::StringPrintStream stream;
     if (codeBlock) {
@@ -1524,6 +1649,7 @@ static EncodedJSValue JSC_HOST_CALL functionCodeBlockFor(ExecState* exec)
 // Usage: $vm.dumpSourceFor(codeBlockToken)
 static EncodedJSValue JSC_HOST_CALL functionDumpSourceFor(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     CodeBlock* codeBlock = codeBlockFromArg(exec);
     if (codeBlock)
         codeBlock->dumpSource();
@@ -1534,6 +1660,7 @@ static EncodedJSValue JSC_HOST_CALL functionDumpSourceFor(ExecState* exec)
 // Usage: $vm.dumpBytecodeFor(codeBlock)
 static EncodedJSValue JSC_HOST_CALL functionDumpBytecodeFor(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     CodeBlock* codeBlock = codeBlockFromArg(exec);
     if (codeBlock)
         codeBlock->dumpBytecode();
@@ -1542,6 +1669,7 @@ static EncodedJSValue JSC_HOST_CALL functionDumpBytecodeFor(ExecState* exec)
 
 static EncodedJSValue doPrint(ExecState* exec, bool addLineFeed)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     auto scope = DECLARE_THROW_SCOPE(exec->vm());
     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
         JSValue arg = exec->uncheckedArgument(i);
@@ -1565,6 +1693,7 @@ static EncodedJSValue doPrint(ExecState* exec, bool addLineFeed)
 // Usage: $vm.dataLog(str1, str2, str3)
 static EncodedJSValue JSC_HOST_CALL functionDataLog(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     const bool addLineFeed = false;
     return doPrint(exec, addLineFeed);
 }
@@ -1573,6 +1702,7 @@ static EncodedJSValue JSC_HOST_CALL functionDataLog(ExecState* exec)
 // Usage: $vm.print(str1, str2, str3)
 static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     const bool addLineFeed = true;
     return doPrint(exec, addLineFeed);
 }
@@ -1581,6 +1711,7 @@ static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
 // Usage: $vm.dumpCallFrame()
 static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     // When the callers call this function, they are expecting to dump their
     // own frame. So skip 1 for this frame.
     VMInspector::dumpCallFrame(exec, 1);
@@ -1591,6 +1722,7 @@ static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
 // Usage: $vm.printStack()
 static EncodedJSValue JSC_HOST_CALL functionDumpStack(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     // When the callers call this function, they are expecting to dump the
     // stack starting their own frame. So skip 1 for this frame.
     VMInspector::dumpStack(exec, 1);
@@ -1604,6 +1736,7 @@ static EncodedJSValue JSC_HOST_CALL functionDumpStack(ExecState* exec)
 // it dump the logical frame (i.e. be able to dump inlined frames as well).
 static EncodedJSValue JSC_HOST_CALL functionDumpRegisters(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     unsigned requestedFrameIndex = 1;
     if (exec->argumentCount() >= 1) {
         JSValue value = exec->uncheckedArgument(0);
@@ -1631,6 +1764,7 @@ static EncodedJSValue JSC_HOST_CALL functionDumpRegisters(ExecState* exec)
 // Usage: $vm.dumpCell(cell)
 static EncodedJSValue JSC_HOST_CALL functionDumpCell(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     JSValue value = exec->argument(0);
     if (!value.isCell())
         return encodedJSUndefined();
@@ -1643,6 +1777,7 @@ static EncodedJSValue JSC_HOST_CALL functionDumpCell(ExecState* exec)
 // Usage: $vm.print("indexingMode = " + $vm.indexingMode(jsValue))
 static EncodedJSValue JSC_HOST_CALL functionIndexingMode(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     if (!exec->argument(0).isObject())
         return encodedJSUndefined();
 
@@ -1653,6 +1788,7 @@ static EncodedJSValue JSC_HOST_CALL functionIndexingMode(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionInlineCapacity(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     if (auto* object = jsDynamicCast<JSObject*>(vm, exec->argument(0)))
         return JSValue::encode(jsNumber(object->structure(vm)->inlineCapacity()));
@@ -1664,6 +1800,7 @@ static EncodedJSValue JSC_HOST_CALL functionInlineCapacity(ExecState* exec)
 // Usage: $vm.print("value = " + $vm.value(jsValue))
 static EncodedJSValue JSC_HOST_CALL functionValue(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     WTF::StringPrintStream stream;
     for (unsigned i = 0; i < exec->argumentCount(); ++i) {
         if (i)
@@ -1678,6 +1815,7 @@ static EncodedJSValue JSC_HOST_CALL functionValue(ExecState* exec)
 // Usage: $vm.print("pid = " + $vm.getpid())
 static EncodedJSValue JSC_HOST_CALL functionGetPID(ExecState*)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     return JSValue::encode(jsNumber(getCurrentProcessID()));
 }
 
@@ -1685,6 +1823,7 @@ static EncodedJSValue JSC_HOST_CALL functionGetPID(ExecState*)
 // Usage: $vm.haveABadTime(globalObject)
 static EncodedJSValue JSC_HOST_CALL functionHaveABadTime(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     JSValue objValue = exec->argument(0);
@@ -1704,6 +1843,7 @@ static EncodedJSValue JSC_HOST_CALL functionHaveABadTime(ExecState* exec)
 // Usage: $vm.isHavingABadTime(obj)
 static EncodedJSValue JSC_HOST_CALL functionIsHavingABadTime(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     JSValue objValue = exec->argument(0);
@@ -1726,6 +1866,7 @@ static EncodedJSValue JSC_HOST_CALL functionIsHavingABadTime(ExecState* exec)
 // Usage: $vm.createGlobalObject()
 static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     JSGlobalObject* globalObject = JSGlobalObject::create(vm, JSGlobalObject::createStructure(vm, jsNull()));
@@ -1734,6 +1875,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     JSValue target = exec->argument(0);
@@ -1747,6 +1889,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     JSLockHolder lock(exec);
     RuntimeArray* array = RuntimeArray::create(exec);
     return JSValue::encode(array);
@@ -1754,6 +1897,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionCreateNullRopeString(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     return JSValue::encode(JSRopeString::createNullForTesting(vm));
@@ -1761,6 +1905,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateNullRopeString(ExecState* exec
 
 static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     JSValue target = exec->argument(0);
@@ -1774,6 +1919,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     Structure* structure = CustomGetter::createStructure(vm, exec->lexicalGlobalObject(), jsNull());
@@ -1783,6 +1929,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateCustomGetterObject(ExecState*
 
 static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     Structure* structure = DOMJITNode::createStructure(vm, exec->lexicalGlobalObject(), DOMJITGetter::create(vm, DOMJITGetter::createStructure(vm, exec->lexicalGlobalObject(), jsNull())));
@@ -1792,6 +1939,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITNodeObject(ExecState* ex
 
 static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     Structure* structure = DOMJITGetter::createStructure(vm, exec->lexicalGlobalObject(), jsNull());
@@ -1801,6 +1949,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterObject(ExecState*
 
 static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     Structure* structure = DOMJITGetterComplex::createStructure(vm, exec->lexicalGlobalObject(), jsNull());
@@ -1810,6 +1959,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterComplexObject(Exec
 
 static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITFunctionObject(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     Structure* structure = DOMJITFunctionObject::createStructure(vm, exec->lexicalGlobalObject(), jsNull());
@@ -1819,6 +1969,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITFunctionObject(ExecState
 
 static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITCheckSubClassObject(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     Structure* structure = DOMJITCheckSubClassObject::createStructure(vm, exec->lexicalGlobalObject(), jsNull());
@@ -1828,6 +1979,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITCheckSubClassObject(Exec
 
 static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterBaseJSObject(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     Structure* structure = DOMJITGetterBaseJSObject::createStructure(vm, exec->lexicalGlobalObject(), jsNull());
@@ -1838,6 +1990,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterBaseJSObject(ExecS
 #if ENABLE(WEBASSEMBLY)
 static EncodedJSValue JSC_HOST_CALL functionCreateWasmStreamingParser(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     return JSValue::encode(WasmStreamingParser::create(vm, exec->lexicalGlobalObject()));
@@ -1846,6 +1999,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateWasmStreamingParser(ExecState*
 
 static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -1867,6 +2021,7 @@ static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* e
 
 static EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -1884,6 +2039,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateBuiltin(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionGetPrivateProperty(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -1901,6 +2057,7 @@ static EncodedJSValue JSC_HOST_CALL functionGetPrivateProperty(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     return JSValue::encode(Root::create(vm, exec->lexicalGlobalObject()));
@@ -1908,6 +2065,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateRoot(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -1920,6 +2078,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     Root* root = jsDynamicCast<Root*>(vm, exec->argument(0));
@@ -1931,6 +2090,7 @@ static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionCreateSimpleObject(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     return JSValue::encode(SimpleObject::create(vm, exec->lexicalGlobalObject()));
@@ -1938,6 +2098,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateSimpleObject(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionGetHiddenValue(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -1952,6 +2113,7 @@ static EncodedJSValue JSC_HOST_CALL functionGetHiddenValue(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionSetHiddenValue(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSLockHolder lock(vm);
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -1968,6 +2130,7 @@ static EncodedJSValue JSC_HOST_CALL functionSetHiddenValue(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionShadowChickenFunctionsOnStack(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
     if (auto* shadowChicken = vm.shadowChicken()) {
@@ -1992,6 +2155,7 @@ static EncodedJSValue JSC_HOST_CALL functionShadowChickenFunctionsOnStack(ExecSt
 
 static EncodedJSValue JSC_HOST_CALL functionSetGlobalConstRedeclarationShouldNotThrow(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     vm.setGlobalConstRedeclarationShouldThrow(false);
     return JSValue::encode(jsUndefined());
@@ -1999,6 +2163,7 @@ static EncodedJSValue JSC_HOST_CALL functionSetGlobalConstRedeclarationShouldNot
 
 static EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     RELEASE_ASSERT(vm.typeProfiler());
     vm.typeProfilerLog()->processLogEntries(vm, "jsc Testing API: functionFindTypeForExpression"_s);
@@ -2018,6 +2183,7 @@ static EncodedJSValue JSC_HOST_CALL functionFindTypeForExpression(ExecState* exe
 
 static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     RELEASE_ASSERT(vm.typeProfiler());
     vm.typeProfilerLog()->processLogEntries(vm, "jsc Testing API: functionReturnTypeFor"_s);
@@ -2033,6 +2199,7 @@ static EncodedJSValue JSC_HOST_CALL functionReturnTypeFor(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionFlattenDictionaryObject(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSValue value = exec->argument(0);
     RELEASE_ASSERT(value.isObject() && value.getObject()->structure()->isDictionary());
@@ -2042,6 +2209,7 @@ static EncodedJSValue JSC_HOST_CALL functionFlattenDictionaryObject(ExecState* e
 
 static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     RELEASE_ASSERT(vm.controlFlowProfiler());
     vm.controlFlowProfiler()->dumpData();
@@ -2050,6 +2218,7 @@ static EncodedJSValue JSC_HOST_CALL functionDumpBasicBlockExecutionRanges(ExecSt
 
 static EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     RELEASE_ASSERT(vm.controlFlowProfiler());
 
@@ -2069,6 +2238,7 @@ static EncodedJSValue JSC_HOST_CALL functionHasBasicBlockExecuted(ExecState* exe
 
 static EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     RELEASE_ASSERT(vm.controlFlowProfiler());
 
@@ -2088,38 +2258,69 @@ static EncodedJSValue JSC_HOST_CALL functionBasicBlockExecutionCount(ExecState*
 
 static EncodedJSValue JSC_HOST_CALL functionEnableExceptionFuzz(ExecState*)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     Options::useExceptionFuzz() = true;
     return JSValue::encode(jsUndefined());
 }
 
+class DoNothingDebugger final : public Debugger {
+    WTF_MAKE_NONCOPYABLE(DoNothingDebugger);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    DoNothingDebugger(VM& vm)
+        : Debugger(vm)
+    {
+        RELEASE_ASSERT(Options::useDollarVM());
+        setSuppressAllPauses(true);
+    }
+
+private:
+    void sourceParsed(ExecState*, SourceProvider*, int, const WTF::String&) override
+    {
+        RELEASE_ASSERT(Options::useDollarVM());
+    }
+};
+
 static EncodedJSValue changeDebuggerModeWhenIdle(ExecState* exec, OptionSet<CodeGenerationMode> codeGenerationMode)
 {
-    bool newDebuggerMode = codeGenerationMode.contains(CodeGenerationMode::Debugger);
-    if (Options::forceDebuggerBytecodeGeneration() == newDebuggerMode)
+    RELEASE_ASSERT(Options::useDollarVM());
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+
+    bool debuggerRequested = codeGenerationMode.contains(CodeGenerationMode::Debugger);
+    if (debuggerRequested == globalObject->hasDebugger())
         return JSValue::encode(jsUndefined());
 
     VM* vm = &exec->vm();
     vm->whenIdle([=] () {
-        Options::forceDebuggerBytecodeGeneration() = newDebuggerMode;
-        vm->deleteAllCode(PreventCollectionAndDeleteAllCode);
-        if (newDebuggerMode)
-            vm->ensureShadowChicken();
+        if (debuggerRequested) {
+            Debugger* debugger = new DoNothingDebugger(globalObject->vm());
+            globalObject->setDebugger(debugger);
+            debugger->activateBreakpoints(); // Also deletes all code.
+        } else {
+            Debugger* debugger = globalObject->debugger();
+            debugger->deactivateBreakpoints(); // Also deletes all code.
+            globalObject->setDebugger(nullptr);
+            delete debugger;
+        }
     });
     return JSValue::encode(jsUndefined());
 }
 
 static EncodedJSValue JSC_HOST_CALL functionEnableDebuggerModeWhenIdle(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     return changeDebuggerModeWhenIdle(exec, { CodeGenerationMode::Debugger });
 }
 
 static EncodedJSValue JSC_HOST_CALL functionDisableDebuggerModeWhenIdle(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     return changeDebuggerModeWhenIdle(exec, { });
 }
 
 static EncodedJSValue JSC_HOST_CALL functionDeleteAllCodeWhenIdle(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM* vm = &exec->vm();
     vm->whenIdle([=] () {
         vm->deleteAllCode(PreventCollectionAndDeleteAllCode);
@@ -2129,11 +2330,13 @@ static EncodedJSValue JSC_HOST_CALL functionDeleteAllCodeWhenIdle(ExecState* exe
 
 static EncodedJSValue JSC_HOST_CALL functionGlobalObjectCount(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     return JSValue::encode(jsNumber(exec->vm().heap.globalObjectCount()));
 }
 
 static EncodedJSValue JSC_HOST_CALL functionGlobalObjectForObject(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     JSValue value = exec->argument(0);
     RELEASE_ASSERT(value.isObject());
     JSGlobalObject* globalObject = jsCast<JSObject*>(value)->globalObject(exec->vm());
@@ -2143,6 +2346,7 @@ static EncodedJSValue JSC_HOST_CALL functionGlobalObjectForObject(ExecState* exe
 
 static EncodedJSValue JSC_HOST_CALL functionGetGetterSetter(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -2172,6 +2376,7 @@ static EncodedJSValue JSC_HOST_CALL functionGetGetterSetter(ExecState* exec)
 
 static EncodedJSValue JSC_HOST_CALL functionLoadGetterFromGetterSetter(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -2188,6 +2393,7 @@ static EncodedJSValue JSC_HOST_CALL functionLoadGetterFromGetterSetter(ExecState
 
 static EncodedJSValue JSC_HOST_CALL functionCreateCustomTestGetterSetter(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
     return JSValue::encode(JSTestCustomGetterSetter::create(vm, globalObject, JSTestCustomGetterSetter::createStructure(vm, globalObject)));
@@ -2195,6 +2401,7 @@ static EncodedJSValue JSC_HOST_CALL functionCreateCustomTestGetterSetter(ExecSta
 
 static EncodedJSValue JSC_HOST_CALL functionDeltaBetweenButterflies(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     JSObject* a = jsDynamicCast<JSObject*>(vm, exec->argument(0));
     JSObject* b = jsDynamicCast<JSObject*>(vm, exec->argument(1));
@@ -2211,17 +2418,20 @@ static EncodedJSValue JSC_HOST_CALL functionDeltaBetweenButterflies(ExecState* e
 
 static EncodedJSValue JSC_HOST_CALL functionTotalGCTime(ExecState* exec)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     VM& vm = exec->vm();
     return JSValue::encode(jsNumber(vm.heap.totalGCTime().seconds()));
 }
 
 static EncodedJSValue JSC_HOST_CALL functionParseCount(ExecState*)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     return JSValue::encode(jsNumber(globalParseCount.load()));
 }
 
 static EncodedJSValue JSC_HOST_CALL functionIsWasmSupported(ExecState*)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
 #if ENABLE(WEBASSEMBLY)
     return JSValue::encode(jsBoolean(Wasm::isSupported()));
 #else
@@ -2231,6 +2441,7 @@ static EncodedJSValue JSC_HOST_CALL functionIsWasmSupported(ExecState*)
 
 void JSDollarVM::finishCreation(VM& vm)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     Base::finishCreation(vm);
 
     JSGlobalObject* globalObject = this->globalObject(vm);
@@ -2351,12 +2562,14 @@ void JSDollarVM::finishCreation(VM& vm)
 
 void JSDollarVM::addFunction(VM& vm, JSGlobalObject* globalObject, const char* name, NativeFunction function, unsigned arguments)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     Identifier identifier = Identifier::fromString(vm, name);
     putDirect(vm, identifier, JSFunction::create(vm, globalObject, arguments, identifier.string(), function));
 }
 
 void JSDollarVM::addConstructibleFunction(VM& vm, JSGlobalObject* globalObject, const char* name, NativeFunction function, unsigned arguments)
 {
+    RELEASE_ASSERT(Options::useDollarVM());
     Identifier identifier = Identifier::fromString(vm, name);
     putDirect(vm, identifier, JSFunction::create(vm, globalObject, arguments, identifier.string(), function, NoIntrinsic, function));
 }
index 7bedb0c..b402d6f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #pragma once
 
 #include "JSObject.h"
+#include "Options.h"
 
 namespace JSC {
-    
+
 class JSDollarVM final : public JSNonFinalObject {
 public:
     typedef JSNonFinalObject Base;
@@ -37,11 +38,13 @@ public:
     
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     }
 
     static JSDollarVM* create(VM& vm, Structure* structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
         JSDollarVM* instance = new (NotNull, allocateCell<JSDollarVM>(vm.heap)) JSDollarVM(vm, structure);
         instance->finishCreation(vm);
         return instance;
@@ -51,8 +54,10 @@ private:
     JSDollarVM(VM& vm, Structure* structure)
         : Base(vm, structure)
     {
+        RELEASE_ASSERT(Options::useDollarVM());
     }
 
+
     void finishCreation(VM&);
     void addFunction(VM&, JSGlobalObject*, const char* name, NativeFunction, unsigned arguments);
     void addConstructibleFunction(VM&, JSGlobalObject*, const char* name, NativeFunction, unsigned arguments);
index a6e2c27..016e570 100644 (file)
@@ -1,3 +1,15 @@
+2019-09-12  Mark Lam  <mark.lam@apple.com>
+
+        Harden JSC against the abuse of runtime options.
+        https://bugs.webkit.org/show_bug.cgi?id=201597
+        <rdar://problem/55167068>
+
+        Reviewed by Filip Pizlo.
+
+        Add a source file that was missing so that Xcode can search its contents too.
+
+        * WTF.xcodeproj/project.pbxproj:
+
 2019-09-09  Tim Horton  <timothy_horton@apple.com>
 
         Clarify some macCatalyst feature flags
index 1b191fc..2dfc903 100644 (file)
                FE05FAFE1FE5007500093230 /* WTFAssertions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WTFAssertions.cpp; sourceTree = "<group>"; };
                FE1E2C392240C05400F6B729 /* PtrTag.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PtrTag.cpp; sourceTree = "<group>"; };
                FE1E2C41224187C600F6B729 /* PlatformRegisters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformRegisters.cpp; sourceTree = "<group>"; };
+               FE3842342325CC80009DD445 /* ResourceUsage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResourceUsage.h; sourceTree = "<group>"; };
                FE7497E4208FFCAA0003565B /* PtrTag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PtrTag.h; sourceTree = "<group>"; };
                FE7497ED209163060003565B /* MetaAllocatorPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MetaAllocatorPtr.h; sourceTree = "<group>"; };
                FE8225301B2A1E5B00BA68FD /* NakedPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NakedPtr.h; sourceTree = "<group>"; };
                                A8A47302151A825B004123FF /* RefCountedLeakCounter.h */,
                                86F46F5F1A2840EE00CCBF22 /* RefCounter.h */,
                                A8A47303151A825B004123FF /* RefPtr.h */,
+                               FE3842342325CC80009DD445 /* ResourceUsage.h */,
                                A8A47305151A825B004123FF /* RetainPtr.h */,
                                2CDED0F118115C85004DBA70 /* RunLoop.cpp */,
                                2CDED0F218115C85004DBA70 /* RunLoop.h */,
index 07c1be9..7a4dc10 100644 (file)
@@ -1,3 +1,20 @@
+2019-09-12  Mark Lam  <mark.lam@apple.com>
+
+        Harden JSC against the abuse of runtime options.
+        https://bugs.webkit.org/show_bug.cgi?id=201597
+        <rdar://problem/55167068>
+
+        Reviewed by Filip Pizlo.
+
+        No new tests.  Covered by existing tests.
+
+        Enable Options::useDollarVM before we tell the JSGlobalObject to exposeDollarVM().
+        The $vm utility is now hardened to require that Options::useDollarVM be
+        enabled in order for it to be used.
+
+        * testing/js/WebCoreTestSupport.cpp:
+        (WebCoreTestSupport::injectInternalsObject):
+
 2019-09-12  Youenn Fablet  <youenn@apple.com>
 
         Use typed identifiers for IDB connection identifiers
index a710af0..d1d434e 100644 (file)
@@ -63,6 +63,7 @@ void injectInternalsObject(JSContextRef context)
     ScriptExecutionContext* scriptContext = globalObject->scriptExecutionContext();
     if (is<Document>(*scriptContext)) {
         globalObject->putDirect(vm, Identifier::fromString(vm, Internals::internalsId), toJS(exec, globalObject, Internals::create(downcast<Document>(*scriptContext))));
+        Options::useDollarVM() = true;
         globalObject->exposeDollarVM(vm);
     }
 }
index 851558c..9df1549 100644 (file)
@@ -1,3 +1,46 @@
+2019-09-12  Mark Lam  <mark.lam@apple.com>
+
+        Harden JSC against the abuse of runtime options.
+        https://bugs.webkit.org/show_bug.cgi?id=201597
+        <rdar://problem/55167068>
+
+        Reviewed by Filip Pizlo.
+
+        Linux parts contributed by Carlos Garcia Campos <cgarcia@igalia.com>.
+
+        1. Add plumbing to allow WK2 tests to configureJSCForTesting().
+        2. Removed the call enable Options::useBigInt in WebInspectorUI.
+           WebInspectorUI doesn't really need it for now.
+
+        * PluginProcess/unix/PluginProcessMainUnix.cpp:
+        * Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceEntryPoint.h:
+        (WebKit::XPCServiceInitializer):
+        * Shared/unix/AuxiliaryProcessMain.cpp:
+        (WebKit::AuxiliaryProcessMainBase::parseCommandLine):
+        * Shared/unix/AuxiliaryProcessMain.h:
+        (WebKit::AuxiliaryProcessMain):
+        * UIProcess/API/APIProcessPoolConfiguration.cpp:
+        (API::ProcessPoolConfiguration::copy):
+        * UIProcess/API/APIProcessPoolConfiguration.h:
+        * UIProcess/API/C/WKContextConfigurationRef.cpp:
+        (WKContextConfigurationSetShouldConfigureJSCForTesting):
+        * UIProcess/API/C/WKContextConfigurationRef.h:
+        * UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h:
+        * UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm:
+        (-[_WKProcessPoolConfiguration configureJSCForTesting]):
+        (-[_WKProcessPoolConfiguration setConfigureJSCForTesting:]):
+        * UIProcess/Launcher/ProcessLauncher.h:
+        (WebKit::ProcessLauncher::Client::shouldConfigureJSCForTesting const):
+        * UIProcess/Launcher/glib/ProcessLauncherGLib.cpp:
+        (WebKit::ProcessLauncher::launchProcess):
+        * UIProcess/Launcher/mac/ProcessLauncherMac.mm:
+        (WebKit::ProcessLauncher::launchProcess):
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::shouldConfigureJSCForTesting const):
+        * UIProcess/WebProcessProxy.h:
+        * WebProcess/WebPage/WebInspectorUI.cpp:
+        (WebKit::WebInspectorUI::WebInspectorUI):
+
 2019-09-12  Michael Catanzaro  <mcatanzaro@igalia.com>
 
         Fix accidental copies in NetworkLoadChecker.cpp
index 48398e0..a7f093b 100644 (file)
@@ -73,6 +73,7 @@ public:
         if (!strcmp(argv[1], "-scanPlugin")) {
             ASSERT(argc == 3);
 #if PLUGIN_ARCHITECTURE(UNIX)
+            InitializeWebKit2();
             exit(NetscapePluginModule::scanPlugin(argv[2]) ? EXIT_SUCCESS : EXIT_FAILURE);
 #else
             exit(EXIT_FAILURE);
index c563273..9098936 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -76,8 +76,12 @@ void initializeAuxiliaryProcess(AuxiliaryProcessInitializationParameters&& param
 template<typename XPCServiceType, typename XPCServiceInitializerDelegateType>
 void XPCServiceInitializer(OSObjectPtr<xpc_connection_t> connection, xpc_object_t initializerMessage, xpc_object_t priorityBoostMessage)
 {
-    if (initializerMessage && xpc_dictionary_get_bool(initializerMessage, "disable-jit"))
-        JSC::ExecutableAllocator::setJITEnabled(false);
+    if (initializerMessage) {
+        if (xpc_dictionary_get_bool(initializerMessage, "configure-jsc-for-testing"))
+            JSC::Config::configureForTesting();
+        if (xpc_dictionary_get_bool(initializerMessage, "disable-jit"))
+            JSC::ExecutableAllocator::setJITEnabled(false);
+    }
 
     XPCServiceInitializerDelegateType delegate(WTFMove(connection), initializerMessage);
 
index dbcbcda..2fb92b3 100644 (file)
 #include "config.h"
 #include "AuxiliaryProcessMain.h"
 
+#include <JavaScriptCore/Options.h>
 #include <WebCore/ProcessIdentifier.h>
 #include <stdlib.h>
+#include <string.h>
 
 namespace WebKit {
 
@@ -39,6 +41,10 @@ bool AuxiliaryProcessMainBase::parseCommandLine(int argc, char** argv)
 
     m_parameters.processIdentifier = makeObjectIdentifier<WebCore::ProcessIdentifierType>(atoll(argv[1]));
     m_parameters.connectionIdentifier = atoi(argv[2]);
+#if ENABLE(DEVELOPER_MODE)
+    if (argc > 3 && !strcmp(argv[3], "--configure-jsc-for-testing"))
+        JSC::Config::configureForTesting();
+#endif
     return true;
 }
 
index 9086846..0cade42 100644 (file)
@@ -57,11 +57,11 @@ int AuxiliaryProcessMain(int argc, char** argv)
     if (!auxiliaryMain.platformInitialize())
         return EXIT_FAILURE;
 
-    InitializeWebKit2();
-
     if (!auxiliaryMain.parseCommandLine(argc, argv))
         return EXIT_FAILURE;
 
+    InitializeWebKit2();
+
     initializeAuxiliaryProcess<AuxiliaryProcessType>(auxiliaryMain.takeInitializationParameters());
     RunLoop::run();
     auxiliaryMain.platformFinalize();
index 6b8d1e8..7e42dd6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -100,6 +100,7 @@ Ref<ProcessPoolConfiguration> ProcessPoolConfiguration::copy()
     copy->m_shouldTakeUIBackgroundAssertion = this->m_shouldTakeUIBackgroundAssertion;
     copy->m_shouldCaptureAudioInUIProcess = this->m_shouldCaptureAudioInUIProcess;
     copy->m_shouldCaptureDisplayInUIProcess = this->m_shouldCaptureDisplayInUIProcess;
+    copy->m_shouldConfigureJSCForTesting = this->m_shouldConfigureJSCForTesting;
     copy->m_isJITEnabled = this->m_isJITEnabled;
     copy->m_downloadMonitorSpeedMultiplier = this->m_downloadMonitorSpeedMultiplier;
 #if PLATFORM(IOS_FAMILY)
index 79698a8..d8bd2f1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -147,6 +147,8 @@ public:
     bool shouldCaptureDisplayInUIProcess() const { return m_shouldCaptureDisplayInUIProcess; }
     void setShouldCaptureDisplayInUIProcess(bool shouldCaptureDisplayInUIProcess) { m_shouldCaptureDisplayInUIProcess = shouldCaptureDisplayInUIProcess; }
 
+    bool shouldConfigureJSCForTesting() const { return m_shouldConfigureJSCForTesting; }
+    void setShouldConfigureJSCForTesting(bool value) { m_shouldConfigureJSCForTesting = value; }
     bool isJITEnabled() const { return m_isJITEnabled; }
     void setJITEnabled(bool enabled) { m_isJITEnabled = enabled; }
     
@@ -218,6 +220,7 @@ private:
     bool m_usesWebProcessCache { false };
     bool m_clientWouldBenefitFromAutomaticProcessPrewarming { false };
     WTF::String m_customWebContentServiceBundleIdentifier;
+    bool m_shouldConfigureJSCForTesting { false };
     bool m_isJITEnabled { true };
     bool m_usesSingleWebProcess { false };
     uint32_t m_downloadMonitorSpeedMultiplier { 1 };
index e248fdd..e310e74 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -214,3 +214,7 @@ void WKContextConfigurationSetDiskCacheSizeOverride(WKContextConfigurationRef co
 {
 }
 
+void WKContextConfigurationSetShouldConfigureJSCForTesting(WKContextConfigurationRef configuration, bool value)
+{
+    toImpl(configuration)->setShouldConfigureJSCForTesting(value);
+}
index b53a822..ba5b978 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -90,6 +90,8 @@ WK_EXPORT void WKContextConfigurationSetProcessSwapsOnWindowOpenWithOpener(WKCon
 WK_EXPORT int64_t WKContextConfigurationDiskCacheSizeOverride(WKContextConfigurationRef configuration) WK_C_API_DEPRECATED;
 WK_EXPORT void WKContextConfigurationSetDiskCacheSizeOverride(WKContextConfigurationRef configuration, int64_t size) WK_C_API_DEPRECATED;
     
+WK_EXPORT void WKContextConfigurationSetShouldConfigureJSCForTesting(WKContextConfigurationRef configuration, bool value);
+
 #ifdef __cplusplus
 }
 #endif
index fdd411f..dc25e91 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -72,6 +72,8 @@ WK_CLASS_AVAILABLE(macos(10.10), ios(8.0))
 @property (nonatomic) NSUInteger downloadMonitorSpeedMultiplierForTesting WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 @property (nonatomic, nullable, copy, setter=setHSTSStorageDirectory:) NSURL *hstsStorageDirectory WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
+@property (nonatomic) BOOL configureJSCForTesting WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 @end
 
 NS_ASSUME_NONNULL_END
index dec574c..15caf6f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
     _processPoolConfiguration->setCustomWebContentServiceBundleIdentifier(customWebContentServiceBundleIdentifier);
 }
 
+- (BOOL)configureJSCForTesting
+{
+    return _processPoolConfiguration->shouldConfigureJSCForTesting();
+}
+
+- (void)setConfigureJSCForTesting:(BOOL)value
+{
+    _processPoolConfiguration->setShouldConfigureJSCForTesting(value);
+}
+
 #pragma mark WKObject protocol implementation
 
 - (API::Object&)_apiObject
index 317a0c0..346c5f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -55,6 +55,7 @@ public:
         virtual ~Client() { }
         
         virtual void didFinishLaunching(ProcessLauncher*, IPC::Connection::Identifier) = 0;
+        virtual bool shouldConfigureJSCForTesting() const { return false; }
         virtual bool isJITEnabled() const { return true; }
     };
     
index 8de1b21..8a2f813 100644 (file)
@@ -113,6 +113,12 @@ void ProcessLauncher::launchProcess()
             prefixArgs.append(arg.utf8());
         nargs += prefixArgs.size();
     }
+
+    bool configureJSCForTesting = false;
+    if (m_launchOptions.processType == ProcessLauncher::ProcessType::Web && m_client && m_client->shouldConfigureJSCForTesting()) {
+        configureJSCForTesting = true;
+        nargs++;
+    }
 #endif
 
     char** argv = g_newa(char*, nargs);
@@ -125,6 +131,10 @@ void ProcessLauncher::launchProcess()
     argv[i++] = const_cast<char*>(realExecutablePath.data());
     argv[i++] = processIdentifier.get();
     argv[i++] = webkitSocket.get();
+#if ENABLE(DEVELOPER_MODE)
+    if (configureJSCForTesting)
+        argv[i++] = const_cast<char*>("--configure-jsc-for-testing");
+#endif
 #if ENABLE(NETSCAPE_PLUGIN_API)
     argv[i++] = const_cast<char*>(realPluginPath.data());
 #else
index 824e387..5bb5ca6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -174,8 +174,12 @@ void ProcessLauncher::launchProcess()
     // FIXME: Switch to xpc_connection_set_bootstrap once it's available everywhere we need.
     auto bootstrapMessage = adoptOSObject(xpc_dictionary_create(nullptr, nullptr, 0));
     
-    if (m_client && !m_client->isJITEnabled())
-        xpc_dictionary_set_bool(bootstrapMessage.get(), "disable-jit", true);
+    if (m_client) {
+        if (m_client->shouldConfigureJSCForTesting())
+            xpc_dictionary_set_bool(bootstrapMessage.get(), "configure-jsc-for-testing", true);
+        if (!m_client->isJITEnabled())
+            xpc_dictionary_set_bool(bootstrapMessage.get(), "disable-jit", true);
+    }
 
     xpc_dictionary_set_string(bootstrapMessage.get(), "message-name", "bootstrap");
 
index 9e06b21..31fee59 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1313,6 +1313,11 @@ void WebProcessProxy::isResponsiveWithLazyStop()
     }
 }
 
+bool WebProcessProxy::shouldConfigureJSCForTesting() const
+{
+    return processPool().configuration().shouldConfigureJSCForTesting();
+}
+
 bool WebProcessProxy::isJITEnabled() const
 {
     return processPool().configuration().isJITEnabled();
index b7f10b6..5d435bf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -335,6 +335,7 @@ protected:
     void cacheMediaMIMETypesInternal(const Vector<String>&);
 #endif
 
+    bool shouldConfigureJSCForTesting() const final;
     bool isJITEnabled() const final;
 
     void validateFreezerStatus();
index 6b669a7..8f6e355 100644 (file)
@@ -51,8 +51,6 @@ WebInspectorUI::WebInspectorUI(WebPage& page)
     : m_page(page)
     , m_frontendAPIDispatcher(page)
 {
-    JSC::Options::useBigInt() = true;
-        
     RuntimeEnabledFeatures::sharedFeatures().setInspectorAdditionsEnabled(true);
     RuntimeEnabledFeatures::sharedFeatures().setImageBitmapOffscreenCanvasEnabled(true);
 #if ENABLE(WEBGL2)
index 5effec2..a2cf5a4 100644 (file)
@@ -1,3 +1,42 @@
+2019-09-12  Mark Lam  <mark.lam@apple.com>
+
+        Harden JSC against the abuse of runtime options.
+        https://bugs.webkit.org/show_bug.cgi?id=201597
+        <rdar://problem/55167068>
+
+        Reviewed by Filip Pizlo.
+
+        Linux parts contributed by Carlos Garcia Campos <cgarcia@igalia.com>.
+        Windows parts contributed by Fujii Hironori <Hironori.Fujii@sony.com>.
+
+        Call JSC::Config::configureForTesting() in test harnesses or at the top of tests
+        to disable the hardening on test runs.  Tests rely on setting options to enable
+        test features.
+
+        * DumpRenderTree/mac/DumpRenderTree.mm:
+        (dumpRenderTree):
+        * DumpRenderTree/win/DumpRenderTree.cpp:
+        (initialize):
+        * TestWebKitAPI/PlatformUtilities.cpp:
+        (TestWebKitAPI::Util::createContextWithInjectedBundle):
+        * TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp:
+        (main):
+        * TestWebKitAPI/Tests/WebKitCocoa/ApplePay.mm:
+        (TestWebKitAPI::TEST):
+        (TestWebKitAPI::runActiveSessionTest):
+        * TestWebKitAPI/Tests/WebKitCocoa/WKWebViewDiagnosticLogging.mm:
+        (TEST):
+        * TestWebKitAPI/Tests/WebKitCocoa/WebsiteDataStoreCustomPaths.mm:
+        (TEST):
+        * TestWebKitAPI/Tests/mac/MediaPlaybackSleepAssertion.mm:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/WKWebViewConfigurationExtras.h:
+        * TestWebKitAPI/WKWebViewConfigurationExtras.mm:
+        (+[WKWebViewConfiguration _test_configurationWithTestPlugInClassName:]):
+        (+[WKWebViewConfiguration _test_configurationWithTestPlugInClassName:configureJSCForTesting:]):
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::generateContextConfiguration const):
+
 2019-09-12  Keith Rollin  <krollin@apple.com>
 
         Fix PDFKit references in TestWebKitAPI
index 47c0f88..e1717e1 100644 (file)
@@ -57,6 +57,7 @@
 #import "WorkQueue.h"
 #import "WorkQueueItem.h"
 #import <CoreFoundation/CoreFoundation.h>
+#import <JavaScriptCore/JSCConfig.h>
 #import <JavaScriptCore/Options.h>
 #import <JavaScriptCore/TestRunnerUtils.h>
 #import <WebCore/LogInitialization.h>
@@ -1283,6 +1284,8 @@ void writeCrashedMessageOnFatalError(int signalCode)
 
 void dumpRenderTree(int argc, const char *argv[])
 {
+    JSC::Config::configureForTesting();
+
 #if PLATFORM(IOS_FAMILY)
     setUpIOSLayoutTestCommunication();
     [UIApplication sharedApplication].idleTimerDisabled = YES;
index 1d555c4..6574032 100644 (file)
@@ -314,6 +314,8 @@ static const wstring& fontsPath()
 
 static void initialize()
 {
+    JSC::Config::configureForTesting();
+
     if (HMODULE webKitModule = LoadLibrary(WEBKITDLL))
         if (FARPROC dllRegisterServer = GetProcAddress(webKitModule, "DllRegisterServer"))
             dllRegisterServer();
index 05f0d4f..2e7a88e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -40,6 +40,7 @@ WKContextRef createContextWithInjectedBundle()
     WKRetainPtr<WKStringRef> injectedBundlePath = adoptWK(createInjectedBundlePath());
     auto configuration = adoptWK(WKContextConfigurationCreate());
     WKContextConfigurationSetInjectedBundlePath(configuration.get(), injectedBundlePath.get());
+    WKContextConfigurationSetShouldConfigureJSCForTesting(configuration.get(), true);
     return WKContextCreateWithConfiguration(configuration.get());
 }
 
index 5e75f9a..2a5be43 100644 (file)
@@ -3741,6 +3741,9 @@ int main(int argc, char** argv)
 {
     g_test_init(&argc, &argv, nullptr);
 
+    // options should always be the first test, since changing options
+    // is not allowed after the first VM instance is created.
+    g_test_add_func("/jsc/options", testsJSCOptions);
     g_test_add_func("/jsc/basic", testJSCBasic);
     g_test_add_func("/jsc/types", testJSCTypes);
     g_test_add_func("/jsc/global-object", testJSCGlobalObject);
@@ -3755,7 +3758,6 @@ int main(int argc, char** argv)
     g_test_add_func("/jsc/garbage-collector", testJSCGarbageCollector);
     g_test_add_func("/jsc/weak-value", testJSCWeakValue);
     g_test_add_func("/jsc/vm", testsJSCVirtualMachine);
-    g_test_add_func("/jsc/options", testsJSCOptions);
 #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
     g_test_add_func("/jsc/autocleanups", testsJSCAutocleanups);
 #endif
index 17a1ae0..98253b4 100644 (file)
@@ -94,7 +94,7 @@ TEST(ApplePay, ApplePayAvailableByDefault)
 
     auto messageHandler = adoptNS([[TestApplePayAvailableScriptMessageHandler alloc] initWithAPIsAvailableExpectation:YES canMakePaymentsExpectation:YES]);
 
-    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"];
+    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"];
 
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
@@ -112,7 +112,7 @@ TEST(ApplePay, ApplePayAvailableInUnrestrictedClients)
     auto messageHandler = adoptNS([[TestApplePayAvailableScriptMessageHandler alloc] initWithAPIsAvailableExpectation:YES canMakePaymentsExpectation:YES]);
     auto userScript = adoptNS([[WKUserScript alloc] initWithSource:userScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]);
 
-    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"];
+    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     [configuration.userContentController addUserScript:userScript.get()];
     [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"];
 
@@ -135,7 +135,7 @@ TEST(ApplePay, UserScriptAtDocumentStartDisablesApplePay)
     auto messageHandler = adoptNS([[TestApplePayAvailableScriptMessageHandler alloc] initWithAPIsAvailableExpectation:NO canMakePaymentsExpectation:NO]);
     auto userScript = adoptNS([[WKUserScript alloc] initWithSource:userScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]);
 
-    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"];
+    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     [configuration.userContentController addUserScript:userScript.get()];
     [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"];
 
@@ -156,7 +156,7 @@ TEST(ApplePay, UserScriptAtDocumentEndDisablesApplePay)
     auto messageHandler = adoptNS([[TestApplePayAvailableScriptMessageHandler alloc] initWithAPIsAvailableExpectation:NO canMakePaymentsExpectation:NO]);
     auto userScript = adoptNS([[WKUserScript alloc] initWithSource:userScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES]);
     
-    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"];
+    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     [configuration.userContentController addUserScript:userScript.get()];
     [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"];
     
@@ -176,7 +176,7 @@ TEST(ApplePay, UserAgentScriptEvaluationDisablesApplePay)
 
     auto messageHandler = adoptNS([[TestApplePayAvailableScriptMessageHandler alloc] initWithAPIsAvailableExpectation:YES canMakePaymentsExpectation:NO]);
 
-    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"];
+    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"];
 
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
@@ -197,7 +197,7 @@ TEST(ApplePay, UserAgentScriptEvaluationDisablesApplePayInExistingObjects)
 
     auto messageHandler = adoptNS([[TestApplePayAvailableScriptMessageHandler alloc] initWithAPIsAvailableExpectation:YES canMakePaymentsExpectation:NO]);
 
-    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"];
+    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"];
 
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
@@ -221,7 +221,7 @@ static void runActiveSessionTest(NSURL *url, BOOL shouldBlockScripts)
     auto messageHandler = adoptNS([[TestApplePayActiveSessionScriptMessageHandler alloc] init]);
     auto userScript = adoptNS([[WKUserScript alloc] initWithSource:userScriptSource injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES]);
 
-    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"];
+    WKWebViewConfiguration *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
     [configuration.userContentController addScriptMessageHandler:messageHandler.get() name:@"testApplePay"];
 
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]);
index e1625dd..e601adb 100644 (file)
@@ -87,7 +87,7 @@ TEST(WKWebView, DiagnosticLoggingDelegateAfterClose)
 
 TEST(WKWebView, DiagnosticLoggingDictionary)
 {
-    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:[WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals"]]);
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:[WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]]);
     auto testLoggingDelegate = adoptNS([TestLoggingDelegate new]);
     [webView _setDiagnosticLoggingDelegate:testLoggingDelegate.get()];
     [webView configuration].preferences._diagnosticLoggingEnabled = YES;
index 947cde1..ee56aa4 100644 (file)
@@ -30,6 +30,7 @@
 #import "Test.h"
 #import "TestNavigationDelegate.h"
 #import "TestWKWebView.h"
+#import <JavaScriptCore/JSCConfig.h>
 #import <WebKit/WKPreferencesRef.h>
 #import <WebKit/WKProcessPoolPrivate.h>
 #import <WebKit/WKUserContentControllerPrivate.h>
@@ -617,6 +618,8 @@ TEST(WebKit, ApplicationCacheDirectories)
 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || PLATFORM(IOS_FAMILY)
 TEST(WebKit, MediaCache)
 {
+    JSC::Config::configureForTesting();
+
     std::atomic<bool> done = false;
     using namespace TestWebKitAPI;
     RetainPtr<NSData> data = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"test" withExtension:@"mp4" subdirectory:@"TestWebKitAPI.resources"]];
index b793a22..4fb2688 100644 (file)
@@ -31,6 +31,7 @@
 #import "WebCoreTestSupport.h"
 #import <Carbon/Carbon.h>
 #import <IOKit/pwr_mgt/IOPMLib.h>
+#import <JavaScriptCore/JSCConfig.h>
 #import <JavaScriptCore/JSContext.h>
 #import <WebCore/Settings.h>
 #import <WebKit/WebKitLegacy.h>
@@ -142,6 +143,8 @@ static bool hasAssertionType(CFStringRef type)
 
 TEST(WebKitLegacy, MediaPlaybackSleepAssertion)
 {
+    JSC::Config::configureForTesting();
+
     didFinishLoad = false;
     didBeginPlaying = false;
     didStopPlaying = false;
index e761ce0..d681207 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,4 +27,5 @@
 
 @interface WKWebViewConfiguration (TestWebKitAPIExtras)
 + (instancetype)_test_configurationWithTestPlugInClassName:(NSString *)className;
++ (instancetype)_test_configurationWithTestPlugInClassName:(NSString *)className configureJSCForTesting:(BOOL)value;
 @end
index f2a3fc2..7ddbd8c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 + (instancetype)_test_configurationWithTestPlugInClassName:(NSString *)className
 {
+    return [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:className configureJSCForTesting:NO];
+}
+
++ (instancetype)_test_configurationWithTestPlugInClassName:(NSString *)className configureJSCForTesting:(BOOL)value
+{
     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
     [processPoolConfiguration setInjectedBundleURL:[[NSBundle mainBundle] URLForResource:@"TestWebKitAPI" withExtension:@"wkbundle"]];
+    [processPoolConfiguration setConfigureJSCForTesting:value];
 
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
     [processPool _setObject:className forBundleParameter:TestWebKitAPI::Util::TestPlugInClassNameParameter];
index 5c66846..9a91f5d 100644 (file)
@@ -503,6 +503,8 @@ WKRetainPtr<WKContextConfigurationRef> TestController::generateContextConfigurat
             WKContextConfigurationSetProcessSwapsOnWindowOpenWithOpener(configuration.get(), true);
     }
 
+    WKContextConfigurationSetShouldConfigureJSCForTesting(configuration.get(), true);
+
     return configuration;
 }