haikuwebkit/Source/WTF/wtf/WTFConfig.cpp

135 lines
4.3 KiB
C++
Raw Permalink Normal View History

Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
/*
* Copyright (C) 2020-2021 Apple Inc. All rights reserved.
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
*
* 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 <wtf/WTFConfig.h>
Change Gigacage::Config to use storage in WebConfig::g_config instead of its own. https://bugs.webkit.org/show_bug.cgi?id=212585 <rdar://problem/63812487> Reviewed by Yusuke Suzuki. Source/bmalloc: 1. Gigacage::Config now reserves and expect space to be available in an external WebConfig::g_config buffer. Gigacage does not allocate that buffer. 2. Moved Gigacage::Config to GigacageConfig.h. This allows WTFConfig.h to include GigacageConfig.h instead of all of Gigacage.h. 3. Moved Gigacage::Kind to GigacageKind.h. Otherwise, Gigacage::Kind would need to move to GigacageConfig.h which is a weird place to put it. 4. Removed freezeGigacageConfig(), unfreezeGigacageConfig(), and permanentlyFreezeGigacageConfig(). It is no longer possible to temporarily freeze and unfreeze the Gigacage::Config because it now share the same memory page with higher level Configs. permanentlyFreezeGigacageConfig() is no longer needed because it is subsumed by WTF::Config::permanentlyFreeze(), which will freeze the entire WebConfig::g_config buffer. One difference in behavior here is that Gigacage::Config data used to be permanently frozen as soon as forbidDisablingPrimitiveGigacage() is called. Now, it isn't permanently frozen until the end of the construction of the first JSC::VM instance in the process (just like the other Config records). This still guarantees that it is frozen before any JS script can run. 5. Previously, disablePrimitiveGigacage() works by nullifying the Primitive gigacage base pointer. We can no longer do that because the base pointer will be frozen on VM instantiation. Instead, if not forbidden, we now disable the Primitive gigacage by setting a disablePrimitiveGigacageRequested bool variable that is not frozen in the Gigacage::Config. To check if the Primitive gigacage is enabled, the LLInt, AssemblyHelpers::cageConditionally(), and runtime functions will check the following conditions: g_gigacageConfig.basePtr(Primitive) && (disablingPrimitiveGigacageIsForbidden() || disableNotRequestedForPrimitiveGigacage()) The base pointer being null means the gigacage was never set up. If disablingPrimitiveGigacageIsForbidden() is true, then we don't care whether a disable request has been received. Otherwise, the gigacage is only enabled if it has been set up, and a disable request has not been received. Note that the first 2 terms are frozen in the Gigacage::Config. Only the last term is a runtime variable. If disabling is forbidden, then the runtime variable never comes into play. The FTL does not rely on a runtime check for whether the Primitive gigacage is enabled or not. Instead, it relies on a watchpoint to handle this. So, it just works, and there's no performance penalty with adding the 2 extra terms to check. Note also that the jsc shell and the WebProcess will forbid disabling of the Primitive gigacage. This means the AssemblyHelpers::cageConditionally() will also not generate the runtime checks for the 2 extra terms. Only the LLInt and runtime functions will have to do work to check the 2 extra terms. But because these are not in perf critical paths, this is ok. Note that we're deliberately gating the disablePrimitiveGigacageRequested variable check on disablingPrimitiveGigacageIsForbidden though, logically, the isEnable check does not really depend on whether disabling is forbidden or not. We do this because disablingPrimitiveGigacageIsForbidden is frozen in the Config, and it is, therefore, a stronger guarantee of correctness whereas the variable can be corrupted. 6. Replaced isDisablingPrimitiveGigacageForbidden(), canPrimitiveGigacageBeDisabled(), and isPrimitiveGigacagePermanentlyEnabled() with disablingPrimitiveGigacageIsForbidden(). * CMakeLists.txt: * bmalloc.xcodeproj/project.pbxproj: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): (Gigacage::disablePrimitiveGigacage): (Gigacage::forbidDisablingPrimitiveGigacage): (Gigacage::bmalloc::freezeGigacageConfig): Deleted. (Gigacage::bmalloc::unfreezeGigacageConfig): Deleted. (Gigacage::bmalloc::permanentlyFreezeGigacageConfig): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::UnfreezeGigacageConfigScope): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::~UnfreezeGigacageConfigScope): Deleted. (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. * bmalloc/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::disableNotRequestedForPrimitiveGigacage): (Gigacage::isEnabled): (Gigacage::basePtr): (Gigacage::caged): (Gigacage::forbidDisablingPrimitiveGigacage): (): Deleted. (Gigacage::Config::basePtr const): Deleted. (Gigacage::Config::setBasePtr): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * bmalloc/GigacageConfig.h: Added. (Gigacage::Config::basePtr const): (Gigacage::Config::setBasePtr): * bmalloc/GigacageKind.h: Added. * bmalloc/Heap.cpp: (bmalloc::Heap::usingGigacage): * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: * assembler/testmasm.cpp: (JSC::testCagePreservesPACFailureBit): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::cageTypedArrayStorage): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::caged): * jit/AssemblyHelpers.h: (JSC::AssemblyHelpers::cageConditionally): * llint/LowLevelInterpreter64.asm: * runtime/JSCConfig.h: (JSC::Config::isPermanentlyFrozen): Source/WTF: We now think of the various Config records as being allocated from parts of a WebConfig::g_config buffer. WTF::Config will manage the mechanics of freezing that buffer. And the JSC VM is still the determiner of if/when to freeze the buffer, and it will do this at the end of the construction of the very first VM instance (as before). Gigacage::Config reserves space in WebConfig::g_config. WTF::Config will honor that reservation and place itself after that. JSC::Config will continue to place itself at WTF::Config::spaceForExtensions. The upside of this approach this is that we can now share the same memory page for all the Configs, and can freeze them in one go. The downside is that g_gigacageConfig, g_wtfConfig, and g_jscConfig now have to be macros. This results in some weirdness e.g. they are no longer qualified by namespaces: referring to WTF::g_wtfConfig is now incorrect. * wtf/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: (): Deleted. Canonical link: https://commits.webkit.org/225481@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262434 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-06-02 19:43:17 +00:00
#include <wtf/Gigacage.h>
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
#include <wtf/Lock.h>
#include <wtf/StdLibExtras.h>
#if OS(DARWIN)
#include <wtf/spi/cocoa/MachVMSPI.h>
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
#include <mach/mach.h>
#elif OS(LINUX)
#include <sys/mman.h>
#endif
#include <mutex>
Move some LLInt globals into JSC::Config. https://bugs.webkit.org/show_bug.cgi?id=216685 rdar://68964544 Reviewed by Keith Miller. Source/bmalloc: Introduce ConfigAlignment to match WTFConfig.h. Added BENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) support to match WTF. * bmalloc/BPlatform.h: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): * bmalloc/GigacageConfig.h: * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: 1. Moved the following into g_jscConfig: Data::s_exceptionInstructions ==> g_jscConfig.llint.exceptionInstructions Data::s_wasmExceptionInstructions ==> g_jscConfig.llint.wasmExceptionInstructions g_opcodeMap ==> g_jscConfig.llint.opcodeMap g_opcodeMapWide16 ==> g_jscConfig.llint.opcodeMapWide16 g_opcodeMapWide32 ==> g_jscConfig.llint.opcodeMapWide32 2. Fixed cloop.rb so that it can take an offset for the leap offlineasm instruction. 3. Fixed x86.rb so that it can take an offset for the leap offlineasm instruction. 4. Fixed arm.rb so that it can take an offset for the leap offlineasm instruction. Note: arm64.rb already does this right. 5. Added JSC::Config::singleton() to return a reference to g_jscConfig. This is useful when debugging with lldb since g_jscConfig is not an actual label, but is a macro that computes the address of the Config record. This patch has been smoke tested on arm64e, x86_64, and cloop (on x86_64 and armv7k). * llint/LLIntData.cpp: (JSC::LLInt::LLIntInitializeAssertScope::LLIntInitializeAssertScope): (JSC::LLInt::LLIntInitializeAssertScope::~LLIntInitializeAssertScope): (JSC::LLInt::LLIntInitializeAssertScope::assertInitializationIsAllowed): (JSC::LLInt::initialize): * llint/LLIntData.h: (JSC::LLInt::exceptionInstructions): (JSC::LLInt::wasmExceptionInstructions): (JSC::LLInt::opcodeMap): (JSC::LLInt::opcodeMapWide16): (JSC::LLInt::opcodeMapWide32): (JSC::LLInt::getOpcode): (JSC::LLInt::getOpcodeWide16): (JSC::LLInt::getOpcodeWide32): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter.cpp: * llint/LowLevelInterpreter64.asm: * llint/WebAssembly.asm: * offlineasm/arm.rb: * offlineasm/cloop.rb: * offlineasm/x86.rb: * runtime/JSCConfig.cpp: (JSC::Config::singleton): * runtime/JSCConfig.h: Source/WTF: 1. Introduce ConfigAlignment as a distinct value from ConfigSizeToProtect. This is because ConfigSizeToProtect is now larger than 1 CeilingOnPageSize on some platforms, but ConfigAlignment only needs to match CeilingOnPageSize. 2. Introduced ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) to disable using the unified g_config record for Windows ports. This is needed because WTF is built as a DLL on Windows. offlineasm does not know how to resolve a DLL exported variable. Additionally, the Windows ports have never supported freezing of the Config record to begin with. So, we're working around this by disabling ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) for Windows. This allows JSC to have its own g_jscConfig record, which solves this issue for now. * wtf/PlatformEnable.h: * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Canonical link: https://commits.webkit.org/229588@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@267371 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-09-21 22:01:12 +00:00
#if ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD)
Change Gigacage::Config to use storage in WebConfig::g_config instead of its own. https://bugs.webkit.org/show_bug.cgi?id=212585 <rdar://problem/63812487> Reviewed by Yusuke Suzuki. Source/bmalloc: 1. Gigacage::Config now reserves and expect space to be available in an external WebConfig::g_config buffer. Gigacage does not allocate that buffer. 2. Moved Gigacage::Config to GigacageConfig.h. This allows WTFConfig.h to include GigacageConfig.h instead of all of Gigacage.h. 3. Moved Gigacage::Kind to GigacageKind.h. Otherwise, Gigacage::Kind would need to move to GigacageConfig.h which is a weird place to put it. 4. Removed freezeGigacageConfig(), unfreezeGigacageConfig(), and permanentlyFreezeGigacageConfig(). It is no longer possible to temporarily freeze and unfreeze the Gigacage::Config because it now share the same memory page with higher level Configs. permanentlyFreezeGigacageConfig() is no longer needed because it is subsumed by WTF::Config::permanentlyFreeze(), which will freeze the entire WebConfig::g_config buffer. One difference in behavior here is that Gigacage::Config data used to be permanently frozen as soon as forbidDisablingPrimitiveGigacage() is called. Now, it isn't permanently frozen until the end of the construction of the first JSC::VM instance in the process (just like the other Config records). This still guarantees that it is frozen before any JS script can run. 5. Previously, disablePrimitiveGigacage() works by nullifying the Primitive gigacage base pointer. We can no longer do that because the base pointer will be frozen on VM instantiation. Instead, if not forbidden, we now disable the Primitive gigacage by setting a disablePrimitiveGigacageRequested bool variable that is not frozen in the Gigacage::Config. To check if the Primitive gigacage is enabled, the LLInt, AssemblyHelpers::cageConditionally(), and runtime functions will check the following conditions: g_gigacageConfig.basePtr(Primitive) && (disablingPrimitiveGigacageIsForbidden() || disableNotRequestedForPrimitiveGigacage()) The base pointer being null means the gigacage was never set up. If disablingPrimitiveGigacageIsForbidden() is true, then we don't care whether a disable request has been received. Otherwise, the gigacage is only enabled if it has been set up, and a disable request has not been received. Note that the first 2 terms are frozen in the Gigacage::Config. Only the last term is a runtime variable. If disabling is forbidden, then the runtime variable never comes into play. The FTL does not rely on a runtime check for whether the Primitive gigacage is enabled or not. Instead, it relies on a watchpoint to handle this. So, it just works, and there's no performance penalty with adding the 2 extra terms to check. Note also that the jsc shell and the WebProcess will forbid disabling of the Primitive gigacage. This means the AssemblyHelpers::cageConditionally() will also not generate the runtime checks for the 2 extra terms. Only the LLInt and runtime functions will have to do work to check the 2 extra terms. But because these are not in perf critical paths, this is ok. Note that we're deliberately gating the disablePrimitiveGigacageRequested variable check on disablingPrimitiveGigacageIsForbidden though, logically, the isEnable check does not really depend on whether disabling is forbidden or not. We do this because disablingPrimitiveGigacageIsForbidden is frozen in the Config, and it is, therefore, a stronger guarantee of correctness whereas the variable can be corrupted. 6. Replaced isDisablingPrimitiveGigacageForbidden(), canPrimitiveGigacageBeDisabled(), and isPrimitiveGigacagePermanentlyEnabled() with disablingPrimitiveGigacageIsForbidden(). * CMakeLists.txt: * bmalloc.xcodeproj/project.pbxproj: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): (Gigacage::disablePrimitiveGigacage): (Gigacage::forbidDisablingPrimitiveGigacage): (Gigacage::bmalloc::freezeGigacageConfig): Deleted. (Gigacage::bmalloc::unfreezeGigacageConfig): Deleted. (Gigacage::bmalloc::permanentlyFreezeGigacageConfig): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::UnfreezeGigacageConfigScope): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::~UnfreezeGigacageConfigScope): Deleted. (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. * bmalloc/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::disableNotRequestedForPrimitiveGigacage): (Gigacage::isEnabled): (Gigacage::basePtr): (Gigacage::caged): (Gigacage::forbidDisablingPrimitiveGigacage): (): Deleted. (Gigacage::Config::basePtr const): Deleted. (Gigacage::Config::setBasePtr): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * bmalloc/GigacageConfig.h: Added. (Gigacage::Config::basePtr const): (Gigacage::Config::setBasePtr): * bmalloc/GigacageKind.h: Added. * bmalloc/Heap.cpp: (bmalloc::Heap::usingGigacage): * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: * assembler/testmasm.cpp: (JSC::testCagePreservesPACFailureBit): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::cageTypedArrayStorage): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::caged): * jit/AssemblyHelpers.h: (JSC::AssemblyHelpers::cageConditionally): * llint/LowLevelInterpreter64.asm: * runtime/JSCConfig.h: (JSC::Config::isPermanentlyFrozen): Source/WTF: We now think of the various Config records as being allocated from parts of a WebConfig::g_config buffer. WTF::Config will manage the mechanics of freezing that buffer. And the JSC VM is still the determiner of if/when to freeze the buffer, and it will do this at the end of the construction of the very first VM instance (as before). Gigacage::Config reserves space in WebConfig::g_config. WTF::Config will honor that reservation and place itself after that. JSC::Config will continue to place itself at WTF::Config::spaceForExtensions. The upside of this approach this is that we can now share the same memory page for all the Configs, and can freeze them in one go. The downside is that g_gigacageConfig, g_wtfConfig, and g_jscConfig now have to be macros. This results in some weirdness e.g. they are no longer qualified by namespaces: referring to WTF::g_wtfConfig is now incorrect. * wtf/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: (): Deleted. Canonical link: https://commits.webkit.org/225481@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262434 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-06-02 19:43:17 +00:00
namespace WebConfig {
Move some LLInt globals into JSC::Config. https://bugs.webkit.org/show_bug.cgi?id=216685 rdar://68964544 Reviewed by Keith Miller. Source/bmalloc: Introduce ConfigAlignment to match WTFConfig.h. Added BENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) support to match WTF. * bmalloc/BPlatform.h: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): * bmalloc/GigacageConfig.h: * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: 1. Moved the following into g_jscConfig: Data::s_exceptionInstructions ==> g_jscConfig.llint.exceptionInstructions Data::s_wasmExceptionInstructions ==> g_jscConfig.llint.wasmExceptionInstructions g_opcodeMap ==> g_jscConfig.llint.opcodeMap g_opcodeMapWide16 ==> g_jscConfig.llint.opcodeMapWide16 g_opcodeMapWide32 ==> g_jscConfig.llint.opcodeMapWide32 2. Fixed cloop.rb so that it can take an offset for the leap offlineasm instruction. 3. Fixed x86.rb so that it can take an offset for the leap offlineasm instruction. 4. Fixed arm.rb so that it can take an offset for the leap offlineasm instruction. Note: arm64.rb already does this right. 5. Added JSC::Config::singleton() to return a reference to g_jscConfig. This is useful when debugging with lldb since g_jscConfig is not an actual label, but is a macro that computes the address of the Config record. This patch has been smoke tested on arm64e, x86_64, and cloop (on x86_64 and armv7k). * llint/LLIntData.cpp: (JSC::LLInt::LLIntInitializeAssertScope::LLIntInitializeAssertScope): (JSC::LLInt::LLIntInitializeAssertScope::~LLIntInitializeAssertScope): (JSC::LLInt::LLIntInitializeAssertScope::assertInitializationIsAllowed): (JSC::LLInt::initialize): * llint/LLIntData.h: (JSC::LLInt::exceptionInstructions): (JSC::LLInt::wasmExceptionInstructions): (JSC::LLInt::opcodeMap): (JSC::LLInt::opcodeMapWide16): (JSC::LLInt::opcodeMapWide32): (JSC::LLInt::getOpcode): (JSC::LLInt::getOpcodeWide16): (JSC::LLInt::getOpcodeWide32): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter.cpp: * llint/LowLevelInterpreter64.asm: * llint/WebAssembly.asm: * offlineasm/arm.rb: * offlineasm/cloop.rb: * offlineasm/x86.rb: * runtime/JSCConfig.cpp: (JSC::Config::singleton): * runtime/JSCConfig.h: Source/WTF: 1. Introduce ConfigAlignment as a distinct value from ConfigSizeToProtect. This is because ConfigSizeToProtect is now larger than 1 CeilingOnPageSize on some platforms, but ConfigAlignment only needs to match CeilingOnPageSize. 2. Introduced ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) to disable using the unified g_config record for Windows ports. This is needed because WTF is built as a DLL on Windows. offlineasm does not know how to resolve a DLL exported variable. Additionally, the Windows ports have never supported freezing of the Config record to begin with. So, we're working around this by disabling ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) for Windows. This allows JSC to have its own g_jscConfig record, which solves this issue for now. * wtf/PlatformEnable.h: * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Canonical link: https://commits.webkit.org/229588@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@267371 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-09-21 22:01:12 +00:00
alignas(WTF::ConfigAlignment) Slot g_config[WTF::ConfigSizeToProtect / sizeof(Slot)];
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
Change Gigacage::Config to use storage in WebConfig::g_config instead of its own. https://bugs.webkit.org/show_bug.cgi?id=212585 <rdar://problem/63812487> Reviewed by Yusuke Suzuki. Source/bmalloc: 1. Gigacage::Config now reserves and expect space to be available in an external WebConfig::g_config buffer. Gigacage does not allocate that buffer. 2. Moved Gigacage::Config to GigacageConfig.h. This allows WTFConfig.h to include GigacageConfig.h instead of all of Gigacage.h. 3. Moved Gigacage::Kind to GigacageKind.h. Otherwise, Gigacage::Kind would need to move to GigacageConfig.h which is a weird place to put it. 4. Removed freezeGigacageConfig(), unfreezeGigacageConfig(), and permanentlyFreezeGigacageConfig(). It is no longer possible to temporarily freeze and unfreeze the Gigacage::Config because it now share the same memory page with higher level Configs. permanentlyFreezeGigacageConfig() is no longer needed because it is subsumed by WTF::Config::permanentlyFreeze(), which will freeze the entire WebConfig::g_config buffer. One difference in behavior here is that Gigacage::Config data used to be permanently frozen as soon as forbidDisablingPrimitiveGigacage() is called. Now, it isn't permanently frozen until the end of the construction of the first JSC::VM instance in the process (just like the other Config records). This still guarantees that it is frozen before any JS script can run. 5. Previously, disablePrimitiveGigacage() works by nullifying the Primitive gigacage base pointer. We can no longer do that because the base pointer will be frozen on VM instantiation. Instead, if not forbidden, we now disable the Primitive gigacage by setting a disablePrimitiveGigacageRequested bool variable that is not frozen in the Gigacage::Config. To check if the Primitive gigacage is enabled, the LLInt, AssemblyHelpers::cageConditionally(), and runtime functions will check the following conditions: g_gigacageConfig.basePtr(Primitive) && (disablingPrimitiveGigacageIsForbidden() || disableNotRequestedForPrimitiveGigacage()) The base pointer being null means the gigacage was never set up. If disablingPrimitiveGigacageIsForbidden() is true, then we don't care whether a disable request has been received. Otherwise, the gigacage is only enabled if it has been set up, and a disable request has not been received. Note that the first 2 terms are frozen in the Gigacage::Config. Only the last term is a runtime variable. If disabling is forbidden, then the runtime variable never comes into play. The FTL does not rely on a runtime check for whether the Primitive gigacage is enabled or not. Instead, it relies on a watchpoint to handle this. So, it just works, and there's no performance penalty with adding the 2 extra terms to check. Note also that the jsc shell and the WebProcess will forbid disabling of the Primitive gigacage. This means the AssemblyHelpers::cageConditionally() will also not generate the runtime checks for the 2 extra terms. Only the LLInt and runtime functions will have to do work to check the 2 extra terms. But because these are not in perf critical paths, this is ok. Note that we're deliberately gating the disablePrimitiveGigacageRequested variable check on disablingPrimitiveGigacageIsForbidden though, logically, the isEnable check does not really depend on whether disabling is forbidden or not. We do this because disablingPrimitiveGigacageIsForbidden is frozen in the Config, and it is, therefore, a stronger guarantee of correctness whereas the variable can be corrupted. 6. Replaced isDisablingPrimitiveGigacageForbidden(), canPrimitiveGigacageBeDisabled(), and isPrimitiveGigacagePermanentlyEnabled() with disablingPrimitiveGigacageIsForbidden(). * CMakeLists.txt: * bmalloc.xcodeproj/project.pbxproj: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): (Gigacage::disablePrimitiveGigacage): (Gigacage::forbidDisablingPrimitiveGigacage): (Gigacage::bmalloc::freezeGigacageConfig): Deleted. (Gigacage::bmalloc::unfreezeGigacageConfig): Deleted. (Gigacage::bmalloc::permanentlyFreezeGigacageConfig): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::UnfreezeGigacageConfigScope): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::~UnfreezeGigacageConfigScope): Deleted. (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. * bmalloc/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::disableNotRequestedForPrimitiveGigacage): (Gigacage::isEnabled): (Gigacage::basePtr): (Gigacage::caged): (Gigacage::forbidDisablingPrimitiveGigacage): (): Deleted. (Gigacage::Config::basePtr const): Deleted. (Gigacage::Config::setBasePtr): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * bmalloc/GigacageConfig.h: Added. (Gigacage::Config::basePtr const): (Gigacage::Config::setBasePtr): * bmalloc/GigacageKind.h: Added. * bmalloc/Heap.cpp: (bmalloc::Heap::usingGigacage): * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: * assembler/testmasm.cpp: (JSC::testCagePreservesPACFailureBit): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::cageTypedArrayStorage): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::caged): * jit/AssemblyHelpers.h: (JSC::AssemblyHelpers::cageConditionally): * llint/LowLevelInterpreter64.asm: * runtime/JSCConfig.h: (JSC::Config::isPermanentlyFrozen): Source/WTF: We now think of the various Config records as being allocated from parts of a WebConfig::g_config buffer. WTF::Config will manage the mechanics of freezing that buffer. And the JSC VM is still the determiner of if/when to freeze the buffer, and it will do this at the end of the construction of the very first VM instance (as before). Gigacage::Config reserves space in WebConfig::g_config. WTF::Config will honor that reservation and place itself after that. JSC::Config will continue to place itself at WTF::Config::spaceForExtensions. The upside of this approach this is that we can now share the same memory page for all the Configs, and can freeze them in one go. The downside is that g_gigacageConfig, g_wtfConfig, and g_jscConfig now have to be macros. This results in some weirdness e.g. they are no longer qualified by namespaces: referring to WTF::g_wtfConfig is now incorrect. * wtf/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: (): Deleted. Canonical link: https://commits.webkit.org/225481@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262434 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-06-02 19:43:17 +00:00
} // namespace WebConfig
Move some LLInt globals into JSC::Config. https://bugs.webkit.org/show_bug.cgi?id=216685 rdar://68964544 Reviewed by Keith Miller. Source/bmalloc: Introduce ConfigAlignment to match WTFConfig.h. Added BENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) support to match WTF. * bmalloc/BPlatform.h: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): * bmalloc/GigacageConfig.h: * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: 1. Moved the following into g_jscConfig: Data::s_exceptionInstructions ==> g_jscConfig.llint.exceptionInstructions Data::s_wasmExceptionInstructions ==> g_jscConfig.llint.wasmExceptionInstructions g_opcodeMap ==> g_jscConfig.llint.opcodeMap g_opcodeMapWide16 ==> g_jscConfig.llint.opcodeMapWide16 g_opcodeMapWide32 ==> g_jscConfig.llint.opcodeMapWide32 2. Fixed cloop.rb so that it can take an offset for the leap offlineasm instruction. 3. Fixed x86.rb so that it can take an offset for the leap offlineasm instruction. 4. Fixed arm.rb so that it can take an offset for the leap offlineasm instruction. Note: arm64.rb already does this right. 5. Added JSC::Config::singleton() to return a reference to g_jscConfig. This is useful when debugging with lldb since g_jscConfig is not an actual label, but is a macro that computes the address of the Config record. This patch has been smoke tested on arm64e, x86_64, and cloop (on x86_64 and armv7k). * llint/LLIntData.cpp: (JSC::LLInt::LLIntInitializeAssertScope::LLIntInitializeAssertScope): (JSC::LLInt::LLIntInitializeAssertScope::~LLIntInitializeAssertScope): (JSC::LLInt::LLIntInitializeAssertScope::assertInitializationIsAllowed): (JSC::LLInt::initialize): * llint/LLIntData.h: (JSC::LLInt::exceptionInstructions): (JSC::LLInt::wasmExceptionInstructions): (JSC::LLInt::opcodeMap): (JSC::LLInt::opcodeMapWide16): (JSC::LLInt::opcodeMapWide32): (JSC::LLInt::getOpcode): (JSC::LLInt::getOpcodeWide16): (JSC::LLInt::getOpcodeWide32): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter.cpp: * llint/LowLevelInterpreter64.asm: * llint/WebAssembly.asm: * offlineasm/arm.rb: * offlineasm/cloop.rb: * offlineasm/x86.rb: * runtime/JSCConfig.cpp: (JSC::Config::singleton): * runtime/JSCConfig.h: Source/WTF: 1. Introduce ConfigAlignment as a distinct value from ConfigSizeToProtect. This is because ConfigSizeToProtect is now larger than 1 CeilingOnPageSize on some platforms, but ConfigAlignment only needs to match CeilingOnPageSize. 2. Introduced ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) to disable using the unified g_config record for Windows ports. This is needed because WTF is built as a DLL on Windows. offlineasm does not know how to resolve a DLL exported variable. Additionally, the Windows ports have never supported freezing of the Config record to begin with. So, we're working around this by disabling ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) for Windows. This allows JSC to have its own g_jscConfig record, which solves this issue for now. * wtf/PlatformEnable.h: * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Canonical link: https://commits.webkit.org/229588@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@267371 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-09-21 22:01:12 +00:00
#else // not ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD)
namespace WTF {
Config g_wtfConfig;
} // namespace WTF
#endif // ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD)
Change Gigacage::Config to use storage in WebConfig::g_config instead of its own. https://bugs.webkit.org/show_bug.cgi?id=212585 <rdar://problem/63812487> Reviewed by Yusuke Suzuki. Source/bmalloc: 1. Gigacage::Config now reserves and expect space to be available in an external WebConfig::g_config buffer. Gigacage does not allocate that buffer. 2. Moved Gigacage::Config to GigacageConfig.h. This allows WTFConfig.h to include GigacageConfig.h instead of all of Gigacage.h. 3. Moved Gigacage::Kind to GigacageKind.h. Otherwise, Gigacage::Kind would need to move to GigacageConfig.h which is a weird place to put it. 4. Removed freezeGigacageConfig(), unfreezeGigacageConfig(), and permanentlyFreezeGigacageConfig(). It is no longer possible to temporarily freeze and unfreeze the Gigacage::Config because it now share the same memory page with higher level Configs. permanentlyFreezeGigacageConfig() is no longer needed because it is subsumed by WTF::Config::permanentlyFreeze(), which will freeze the entire WebConfig::g_config buffer. One difference in behavior here is that Gigacage::Config data used to be permanently frozen as soon as forbidDisablingPrimitiveGigacage() is called. Now, it isn't permanently frozen until the end of the construction of the first JSC::VM instance in the process (just like the other Config records). This still guarantees that it is frozen before any JS script can run. 5. Previously, disablePrimitiveGigacage() works by nullifying the Primitive gigacage base pointer. We can no longer do that because the base pointer will be frozen on VM instantiation. Instead, if not forbidden, we now disable the Primitive gigacage by setting a disablePrimitiveGigacageRequested bool variable that is not frozen in the Gigacage::Config. To check if the Primitive gigacage is enabled, the LLInt, AssemblyHelpers::cageConditionally(), and runtime functions will check the following conditions: g_gigacageConfig.basePtr(Primitive) && (disablingPrimitiveGigacageIsForbidden() || disableNotRequestedForPrimitiveGigacage()) The base pointer being null means the gigacage was never set up. If disablingPrimitiveGigacageIsForbidden() is true, then we don't care whether a disable request has been received. Otherwise, the gigacage is only enabled if it has been set up, and a disable request has not been received. Note that the first 2 terms are frozen in the Gigacage::Config. Only the last term is a runtime variable. If disabling is forbidden, then the runtime variable never comes into play. The FTL does not rely on a runtime check for whether the Primitive gigacage is enabled or not. Instead, it relies on a watchpoint to handle this. So, it just works, and there's no performance penalty with adding the 2 extra terms to check. Note also that the jsc shell and the WebProcess will forbid disabling of the Primitive gigacage. This means the AssemblyHelpers::cageConditionally() will also not generate the runtime checks for the 2 extra terms. Only the LLInt and runtime functions will have to do work to check the 2 extra terms. But because these are not in perf critical paths, this is ok. Note that we're deliberately gating the disablePrimitiveGigacageRequested variable check on disablingPrimitiveGigacageIsForbidden though, logically, the isEnable check does not really depend on whether disabling is forbidden or not. We do this because disablingPrimitiveGigacageIsForbidden is frozen in the Config, and it is, therefore, a stronger guarantee of correctness whereas the variable can be corrupted. 6. Replaced isDisablingPrimitiveGigacageForbidden(), canPrimitiveGigacageBeDisabled(), and isPrimitiveGigacagePermanentlyEnabled() with disablingPrimitiveGigacageIsForbidden(). * CMakeLists.txt: * bmalloc.xcodeproj/project.pbxproj: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): (Gigacage::disablePrimitiveGigacage): (Gigacage::forbidDisablingPrimitiveGigacage): (Gigacage::bmalloc::freezeGigacageConfig): Deleted. (Gigacage::bmalloc::unfreezeGigacageConfig): Deleted. (Gigacage::bmalloc::permanentlyFreezeGigacageConfig): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::UnfreezeGigacageConfigScope): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::~UnfreezeGigacageConfigScope): Deleted. (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. * bmalloc/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::disableNotRequestedForPrimitiveGigacage): (Gigacage::isEnabled): (Gigacage::basePtr): (Gigacage::caged): (Gigacage::forbidDisablingPrimitiveGigacage): (): Deleted. (Gigacage::Config::basePtr const): Deleted. (Gigacage::Config::setBasePtr): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * bmalloc/GigacageConfig.h: Added. (Gigacage::Config::basePtr const): (Gigacage::Config::setBasePtr): * bmalloc/GigacageKind.h: Added. * bmalloc/Heap.cpp: (bmalloc::Heap::usingGigacage): * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: * assembler/testmasm.cpp: (JSC::testCagePreservesPACFailureBit): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::cageTypedArrayStorage): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::caged): * jit/AssemblyHelpers.h: (JSC::AssemblyHelpers::cageConditionally): * llint/LowLevelInterpreter64.asm: * runtime/JSCConfig.h: (JSC::Config::isPermanentlyFrozen): Source/WTF: We now think of the various Config records as being allocated from parts of a WebConfig::g_config buffer. WTF::Config will manage the mechanics of freezing that buffer. And the JSC VM is still the determiner of if/when to freeze the buffer, and it will do this at the end of the construction of the very first VM instance (as before). Gigacage::Config reserves space in WebConfig::g_config. WTF::Config will honor that reservation and place itself after that. JSC::Config will continue to place itself at WTF::Config::spaceForExtensions. The upside of this approach this is that we can now share the same memory page for all the Configs, and can freeze them in one go. The downside is that g_gigacageConfig, g_wtfConfig, and g_jscConfig now have to be macros. This results in some weirdness e.g. they are no longer qualified by namespaces: referring to WTF::g_wtfConfig is now incorrect. * wtf/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: (): Deleted. Canonical link: https://commits.webkit.org/225481@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262434 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-06-02 19:43:17 +00:00
namespace WTF {
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
#if ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD)
void setPermissionsOfConfigPage()
{
#if OS(DARWIN)
static std::once_flag onceFlag;
std::call_once(onceFlag, [] {
mach_vm_address_t addr = bitwise_cast<uintptr_t>(static_cast<void*>(WebConfig::g_config));
auto flags = VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE;
#if HAVE(VM_FLAGS_PERMANENT)
flags |= VM_FLAGS_PERMANENT;
#endif
auto attemptVMMapping = [&] {
return mach_vm_map(mach_task_self(), &addr, ConfigSizeToProtect, pageSize() - 1, flags, MEMORY_OBJECT_NULL, 0, false, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE, VM_INHERIT_DEFAULT);
};
auto result = attemptVMMapping();
#if HAVE(VM_FLAGS_PERMANENT)
if (result != KERN_SUCCESS) {
flags &= ~VM_FLAGS_PERMANENT;
result = attemptVMMapping();
}
#endif
RELEASE_ASSERT(result == KERN_SUCCESS);
});
#endif // OS(DARWIN)
}
#endif // ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD)
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
void Config::permanentlyFreeze()
{
static Lock configLock;
Stop using holdLock() in WTF as it is not compatible with Clang thread safety analysis https://bugs.webkit.org/show_bug.cgi?id=226117 Reviewed by Darin Adler. Stop using holdLock() in WTF as it is not compatible with Clang thread safety analysis (WTF::CheckedLock) and use the Locker constructor instead. This is a step towards getting rid of holdLock() completely. * benchmarks/ConditionSpeedTest.cpp: * wtf/ConcurrentPtrHashSet.cpp: (WTF::ConcurrentPtrHashSet::deleteOldTables): (WTF::ConcurrentPtrHashSet::clear): (WTF::ConcurrentPtrHashSet::containsImplSlow const): (WTF::ConcurrentPtrHashSet::sizeSlow const): (WTF::ConcurrentPtrHashSet::resizeIfNecessary): * wtf/CountingLock.h: * wtf/HashTable.cpp: (WTF::HashTableStats::recordCollisionAtCount): (WTF::HashTableStats::dumpStats): * wtf/HashTable.h: (WTF::invalidateIterators): (WTF::addIterator): (WTF::removeIterator): * wtf/LockedPrintStream.cpp: (WTF::LockedPrintStream::vprintf): (WTF::LockedPrintStream::flush): * wtf/MetaAllocator.cpp: (WTF::MetaAllocatorHandle::~MetaAllocatorHandle): * wtf/MetaAllocator.h: (WTF::MetaAllocator::allocate): (WTF::MetaAllocator::currentStatistics): * wtf/ReadWriteLock.h: * wtf/StackShotProfiler.h: (WTF::StackShotProfiler::profile): (WTF::StackShotProfiler::run): * wtf/StackStats.cpp: (WTF::StackStats::CheckPoint::CheckPoint): (WTF::StackStats::CheckPoint::~CheckPoint): (WTF::StackStats::probe): (WTF::StackStats::LayoutCheckPoint::LayoutCheckPoint): (WTF::StackStats::LayoutCheckPoint::~LayoutCheckPoint): * wtf/ThreadGroup.cpp: (WTF::ThreadGroup::~ThreadGroup): (WTF::ThreadGroup::add): * wtf/ThreadMessage.cpp: (WTF::sendMessageScoped): * wtf/Threading.cpp: (WTF::Thread::didExit): (WTF::Thread::addToThreadGroup): (WTF::Thread::removeFromThreadGroup): (WTF::Thread::numberOfThreadGroups): * wtf/TimingScope.cpp: * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFSemaphore.h: * wtf/posix/ThreadingPOSIX.cpp: (WTF::Thread::changePriority): (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::signal): (WTF::Thread::establishPlatformSpecificHandle): * wtf/threads/BinarySemaphore.cpp: (WTF::BinarySemaphore::signal): (WTF::BinarySemaphore::waitUntil): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::add): (WTF::registerThreadForMachExceptionHandling): (WTF::activateSignalHandlersFor): * wtf/win/LanguageWin.cpp: (WTF::platformLanguage): * wtf/win/ThreadingWin.cpp: (WTF::Thread::changePriority): (WTF::Thread::waitForCompletion): (WTF::Thread::detach): (WTF::Thread::establishPlatformSpecificHandle): Canonical link: https://commits.webkit.org/238033@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@277900 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2021-05-22 00:11:37 +00:00
Locker locker { configLock };
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
RELEASE_ASSERT(roundUpToMultipleOf(pageSize(), ConfigSizeToProtect) == ConfigSizeToProtect);
Change Gigacage::Config to use storage in WebConfig::g_config instead of its own. https://bugs.webkit.org/show_bug.cgi?id=212585 <rdar://problem/63812487> Reviewed by Yusuke Suzuki. Source/bmalloc: 1. Gigacage::Config now reserves and expect space to be available in an external WebConfig::g_config buffer. Gigacage does not allocate that buffer. 2. Moved Gigacage::Config to GigacageConfig.h. This allows WTFConfig.h to include GigacageConfig.h instead of all of Gigacage.h. 3. Moved Gigacage::Kind to GigacageKind.h. Otherwise, Gigacage::Kind would need to move to GigacageConfig.h which is a weird place to put it. 4. Removed freezeGigacageConfig(), unfreezeGigacageConfig(), and permanentlyFreezeGigacageConfig(). It is no longer possible to temporarily freeze and unfreeze the Gigacage::Config because it now share the same memory page with higher level Configs. permanentlyFreezeGigacageConfig() is no longer needed because it is subsumed by WTF::Config::permanentlyFreeze(), which will freeze the entire WebConfig::g_config buffer. One difference in behavior here is that Gigacage::Config data used to be permanently frozen as soon as forbidDisablingPrimitiveGigacage() is called. Now, it isn't permanently frozen until the end of the construction of the first JSC::VM instance in the process (just like the other Config records). This still guarantees that it is frozen before any JS script can run. 5. Previously, disablePrimitiveGigacage() works by nullifying the Primitive gigacage base pointer. We can no longer do that because the base pointer will be frozen on VM instantiation. Instead, if not forbidden, we now disable the Primitive gigacage by setting a disablePrimitiveGigacageRequested bool variable that is not frozen in the Gigacage::Config. To check if the Primitive gigacage is enabled, the LLInt, AssemblyHelpers::cageConditionally(), and runtime functions will check the following conditions: g_gigacageConfig.basePtr(Primitive) && (disablingPrimitiveGigacageIsForbidden() || disableNotRequestedForPrimitiveGigacage()) The base pointer being null means the gigacage was never set up. If disablingPrimitiveGigacageIsForbidden() is true, then we don't care whether a disable request has been received. Otherwise, the gigacage is only enabled if it has been set up, and a disable request has not been received. Note that the first 2 terms are frozen in the Gigacage::Config. Only the last term is a runtime variable. If disabling is forbidden, then the runtime variable never comes into play. The FTL does not rely on a runtime check for whether the Primitive gigacage is enabled or not. Instead, it relies on a watchpoint to handle this. So, it just works, and there's no performance penalty with adding the 2 extra terms to check. Note also that the jsc shell and the WebProcess will forbid disabling of the Primitive gigacage. This means the AssemblyHelpers::cageConditionally() will also not generate the runtime checks for the 2 extra terms. Only the LLInt and runtime functions will have to do work to check the 2 extra terms. But because these are not in perf critical paths, this is ok. Note that we're deliberately gating the disablePrimitiveGigacageRequested variable check on disablingPrimitiveGigacageIsForbidden though, logically, the isEnable check does not really depend on whether disabling is forbidden or not. We do this because disablingPrimitiveGigacageIsForbidden is frozen in the Config, and it is, therefore, a stronger guarantee of correctness whereas the variable can be corrupted. 6. Replaced isDisablingPrimitiveGigacageForbidden(), canPrimitiveGigacageBeDisabled(), and isPrimitiveGigacagePermanentlyEnabled() with disablingPrimitiveGigacageIsForbidden(). * CMakeLists.txt: * bmalloc.xcodeproj/project.pbxproj: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): (Gigacage::disablePrimitiveGigacage): (Gigacage::forbidDisablingPrimitiveGigacage): (Gigacage::bmalloc::freezeGigacageConfig): Deleted. (Gigacage::bmalloc::unfreezeGigacageConfig): Deleted. (Gigacage::bmalloc::permanentlyFreezeGigacageConfig): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::UnfreezeGigacageConfigScope): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::~UnfreezeGigacageConfigScope): Deleted. (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. * bmalloc/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::disableNotRequestedForPrimitiveGigacage): (Gigacage::isEnabled): (Gigacage::basePtr): (Gigacage::caged): (Gigacage::forbidDisablingPrimitiveGigacage): (): Deleted. (Gigacage::Config::basePtr const): Deleted. (Gigacage::Config::setBasePtr): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * bmalloc/GigacageConfig.h: Added. (Gigacage::Config::basePtr const): (Gigacage::Config::setBasePtr): * bmalloc/GigacageKind.h: Added. * bmalloc/Heap.cpp: (bmalloc::Heap::usingGigacage): * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: * assembler/testmasm.cpp: (JSC::testCagePreservesPACFailureBit): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::cageTypedArrayStorage): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::caged): * jit/AssemblyHelpers.h: (JSC::AssemblyHelpers::cageConditionally): * llint/LowLevelInterpreter64.asm: * runtime/JSCConfig.h: (JSC::Config::isPermanentlyFrozen): Source/WTF: We now think of the various Config records as being allocated from parts of a WebConfig::g_config buffer. WTF::Config will manage the mechanics of freezing that buffer. And the JSC VM is still the determiner of if/when to freeze the buffer, and it will do this at the end of the construction of the very first VM instance (as before). Gigacage::Config reserves space in WebConfig::g_config. WTF::Config will honor that reservation and place itself after that. JSC::Config will continue to place itself at WTF::Config::spaceForExtensions. The upside of this approach this is that we can now share the same memory page for all the Configs, and can freeze them in one go. The downside is that g_gigacageConfig, g_wtfConfig, and g_jscConfig now have to be macros. This results in some weirdness e.g. they are no longer qualified by namespaces: referring to WTF::g_wtfConfig is now incorrect. * wtf/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: (): Deleted. Canonical link: https://commits.webkit.org/225481@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262434 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-06-02 19:43:17 +00:00
if (!g_wtfConfig.isPermanentlyFrozen) {
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
g_wtfConfig.isPermanentlyFrozen = true;
Change Gigacage::Config to use storage in WebConfig::g_config instead of its own. https://bugs.webkit.org/show_bug.cgi?id=212585 <rdar://problem/63812487> Reviewed by Yusuke Suzuki. Source/bmalloc: 1. Gigacage::Config now reserves and expect space to be available in an external WebConfig::g_config buffer. Gigacage does not allocate that buffer. 2. Moved Gigacage::Config to GigacageConfig.h. This allows WTFConfig.h to include GigacageConfig.h instead of all of Gigacage.h. 3. Moved Gigacage::Kind to GigacageKind.h. Otherwise, Gigacage::Kind would need to move to GigacageConfig.h which is a weird place to put it. 4. Removed freezeGigacageConfig(), unfreezeGigacageConfig(), and permanentlyFreezeGigacageConfig(). It is no longer possible to temporarily freeze and unfreeze the Gigacage::Config because it now share the same memory page with higher level Configs. permanentlyFreezeGigacageConfig() is no longer needed because it is subsumed by WTF::Config::permanentlyFreeze(), which will freeze the entire WebConfig::g_config buffer. One difference in behavior here is that Gigacage::Config data used to be permanently frozen as soon as forbidDisablingPrimitiveGigacage() is called. Now, it isn't permanently frozen until the end of the construction of the first JSC::VM instance in the process (just like the other Config records). This still guarantees that it is frozen before any JS script can run. 5. Previously, disablePrimitiveGigacage() works by nullifying the Primitive gigacage base pointer. We can no longer do that because the base pointer will be frozen on VM instantiation. Instead, if not forbidden, we now disable the Primitive gigacage by setting a disablePrimitiveGigacageRequested bool variable that is not frozen in the Gigacage::Config. To check if the Primitive gigacage is enabled, the LLInt, AssemblyHelpers::cageConditionally(), and runtime functions will check the following conditions: g_gigacageConfig.basePtr(Primitive) && (disablingPrimitiveGigacageIsForbidden() || disableNotRequestedForPrimitiveGigacage()) The base pointer being null means the gigacage was never set up. If disablingPrimitiveGigacageIsForbidden() is true, then we don't care whether a disable request has been received. Otherwise, the gigacage is only enabled if it has been set up, and a disable request has not been received. Note that the first 2 terms are frozen in the Gigacage::Config. Only the last term is a runtime variable. If disabling is forbidden, then the runtime variable never comes into play. The FTL does not rely on a runtime check for whether the Primitive gigacage is enabled or not. Instead, it relies on a watchpoint to handle this. So, it just works, and there's no performance penalty with adding the 2 extra terms to check. Note also that the jsc shell and the WebProcess will forbid disabling of the Primitive gigacage. This means the AssemblyHelpers::cageConditionally() will also not generate the runtime checks for the 2 extra terms. Only the LLInt and runtime functions will have to do work to check the 2 extra terms. But because these are not in perf critical paths, this is ok. Note that we're deliberately gating the disablePrimitiveGigacageRequested variable check on disablingPrimitiveGigacageIsForbidden though, logically, the isEnable check does not really depend on whether disabling is forbidden or not. We do this because disablingPrimitiveGigacageIsForbidden is frozen in the Config, and it is, therefore, a stronger guarantee of correctness whereas the variable can be corrupted. 6. Replaced isDisablingPrimitiveGigacageForbidden(), canPrimitiveGigacageBeDisabled(), and isPrimitiveGigacagePermanentlyEnabled() with disablingPrimitiveGigacageIsForbidden(). * CMakeLists.txt: * bmalloc.xcodeproj/project.pbxproj: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): (Gigacage::disablePrimitiveGigacage): (Gigacage::forbidDisablingPrimitiveGigacage): (Gigacage::bmalloc::freezeGigacageConfig): Deleted. (Gigacage::bmalloc::unfreezeGigacageConfig): Deleted. (Gigacage::bmalloc::permanentlyFreezeGigacageConfig): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::UnfreezeGigacageConfigScope): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::~UnfreezeGigacageConfigScope): Deleted. (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. * bmalloc/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::disableNotRequestedForPrimitiveGigacage): (Gigacage::isEnabled): (Gigacage::basePtr): (Gigacage::caged): (Gigacage::forbidDisablingPrimitiveGigacage): (): Deleted. (Gigacage::Config::basePtr const): Deleted. (Gigacage::Config::setBasePtr): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * bmalloc/GigacageConfig.h: Added. (Gigacage::Config::basePtr const): (Gigacage::Config::setBasePtr): * bmalloc/GigacageKind.h: Added. * bmalloc/Heap.cpp: (bmalloc::Heap::usingGigacage): * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: * assembler/testmasm.cpp: (JSC::testCagePreservesPACFailureBit): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::cageTypedArrayStorage): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::caged): * jit/AssemblyHelpers.h: (JSC::AssemblyHelpers::cageConditionally): * llint/LowLevelInterpreter64.asm: * runtime/JSCConfig.h: (JSC::Config::isPermanentlyFrozen): Source/WTF: We now think of the various Config records as being allocated from parts of a WebConfig::g_config buffer. WTF::Config will manage the mechanics of freezing that buffer. And the JSC VM is still the determiner of if/when to freeze the buffer, and it will do this at the end of the construction of the very first VM instance (as before). Gigacage::Config reserves space in WebConfig::g_config. WTF::Config will honor that reservation and place itself after that. JSC::Config will continue to place itself at WTF::Config::spaceForExtensions. The upside of this approach this is that we can now share the same memory page for all the Configs, and can freeze them in one go. The downside is that g_gigacageConfig, g_wtfConfig, and g_jscConfig now have to be macros. This results in some weirdness e.g. they are no longer qualified by namespaces: referring to WTF::g_wtfConfig is now incorrect. * wtf/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: (): Deleted. Canonical link: https://commits.webkit.org/225481@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262434 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-06-02 19:43:17 +00:00
#if GIGACAGE_ENABLED
g_gigacageConfig.isPermanentlyFrozen = true;
#endif
}
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
int result = 0;
Move some LLInt globals into JSC::Config. https://bugs.webkit.org/show_bug.cgi?id=216685 rdar://68964544 Reviewed by Keith Miller. Source/bmalloc: Introduce ConfigAlignment to match WTFConfig.h. Added BENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) support to match WTF. * bmalloc/BPlatform.h: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): * bmalloc/GigacageConfig.h: * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: 1. Moved the following into g_jscConfig: Data::s_exceptionInstructions ==> g_jscConfig.llint.exceptionInstructions Data::s_wasmExceptionInstructions ==> g_jscConfig.llint.wasmExceptionInstructions g_opcodeMap ==> g_jscConfig.llint.opcodeMap g_opcodeMapWide16 ==> g_jscConfig.llint.opcodeMapWide16 g_opcodeMapWide32 ==> g_jscConfig.llint.opcodeMapWide32 2. Fixed cloop.rb so that it can take an offset for the leap offlineasm instruction. 3. Fixed x86.rb so that it can take an offset for the leap offlineasm instruction. 4. Fixed arm.rb so that it can take an offset for the leap offlineasm instruction. Note: arm64.rb already does this right. 5. Added JSC::Config::singleton() to return a reference to g_jscConfig. This is useful when debugging with lldb since g_jscConfig is not an actual label, but is a macro that computes the address of the Config record. This patch has been smoke tested on arm64e, x86_64, and cloop (on x86_64 and armv7k). * llint/LLIntData.cpp: (JSC::LLInt::LLIntInitializeAssertScope::LLIntInitializeAssertScope): (JSC::LLInt::LLIntInitializeAssertScope::~LLIntInitializeAssertScope): (JSC::LLInt::LLIntInitializeAssertScope::assertInitializationIsAllowed): (JSC::LLInt::initialize): * llint/LLIntData.h: (JSC::LLInt::exceptionInstructions): (JSC::LLInt::wasmExceptionInstructions): (JSC::LLInt::opcodeMap): (JSC::LLInt::opcodeMapWide16): (JSC::LLInt::opcodeMapWide32): (JSC::LLInt::getOpcode): (JSC::LLInt::getOpcodeWide16): (JSC::LLInt::getOpcodeWide32): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter.cpp: * llint/LowLevelInterpreter64.asm: * llint/WebAssembly.asm: * offlineasm/arm.rb: * offlineasm/cloop.rb: * offlineasm/x86.rb: * runtime/JSCConfig.cpp: (JSC::Config::singleton): * runtime/JSCConfig.h: Source/WTF: 1. Introduce ConfigAlignment as a distinct value from ConfigSizeToProtect. This is because ConfigSizeToProtect is now larger than 1 CeilingOnPageSize on some platforms, but ConfigAlignment only needs to match CeilingOnPageSize. 2. Introduced ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) to disable using the unified g_config record for Windows ports. This is needed because WTF is built as a DLL on Windows. offlineasm does not know how to resolve a DLL exported variable. Additionally, the Windows ports have never supported freezing of the Config record to begin with. So, we're working around this by disabling ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) for Windows. This allows JSC to have its own g_jscConfig record, which solves this issue for now. * wtf/PlatformEnable.h: * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Canonical link: https://commits.webkit.org/229588@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@267371 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-09-21 22:01:12 +00:00
#if ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD)
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
#if OS(DARWIN)
enum {
AllowPermissionChangesAfterThis = false,
DisallowPermissionChangesAfterThis = true
};
// There's no going back now!
Change Gigacage::Config to use storage in WebConfig::g_config instead of its own. https://bugs.webkit.org/show_bug.cgi?id=212585 <rdar://problem/63812487> Reviewed by Yusuke Suzuki. Source/bmalloc: 1. Gigacage::Config now reserves and expect space to be available in an external WebConfig::g_config buffer. Gigacage does not allocate that buffer. 2. Moved Gigacage::Config to GigacageConfig.h. This allows WTFConfig.h to include GigacageConfig.h instead of all of Gigacage.h. 3. Moved Gigacage::Kind to GigacageKind.h. Otherwise, Gigacage::Kind would need to move to GigacageConfig.h which is a weird place to put it. 4. Removed freezeGigacageConfig(), unfreezeGigacageConfig(), and permanentlyFreezeGigacageConfig(). It is no longer possible to temporarily freeze and unfreeze the Gigacage::Config because it now share the same memory page with higher level Configs. permanentlyFreezeGigacageConfig() is no longer needed because it is subsumed by WTF::Config::permanentlyFreeze(), which will freeze the entire WebConfig::g_config buffer. One difference in behavior here is that Gigacage::Config data used to be permanently frozen as soon as forbidDisablingPrimitiveGigacage() is called. Now, it isn't permanently frozen until the end of the construction of the first JSC::VM instance in the process (just like the other Config records). This still guarantees that it is frozen before any JS script can run. 5. Previously, disablePrimitiveGigacage() works by nullifying the Primitive gigacage base pointer. We can no longer do that because the base pointer will be frozen on VM instantiation. Instead, if not forbidden, we now disable the Primitive gigacage by setting a disablePrimitiveGigacageRequested bool variable that is not frozen in the Gigacage::Config. To check if the Primitive gigacage is enabled, the LLInt, AssemblyHelpers::cageConditionally(), and runtime functions will check the following conditions: g_gigacageConfig.basePtr(Primitive) && (disablingPrimitiveGigacageIsForbidden() || disableNotRequestedForPrimitiveGigacage()) The base pointer being null means the gigacage was never set up. If disablingPrimitiveGigacageIsForbidden() is true, then we don't care whether a disable request has been received. Otherwise, the gigacage is only enabled if it has been set up, and a disable request has not been received. Note that the first 2 terms are frozen in the Gigacage::Config. Only the last term is a runtime variable. If disabling is forbidden, then the runtime variable never comes into play. The FTL does not rely on a runtime check for whether the Primitive gigacage is enabled or not. Instead, it relies on a watchpoint to handle this. So, it just works, and there's no performance penalty with adding the 2 extra terms to check. Note also that the jsc shell and the WebProcess will forbid disabling of the Primitive gigacage. This means the AssemblyHelpers::cageConditionally() will also not generate the runtime checks for the 2 extra terms. Only the LLInt and runtime functions will have to do work to check the 2 extra terms. But because these are not in perf critical paths, this is ok. Note that we're deliberately gating the disablePrimitiveGigacageRequested variable check on disablingPrimitiveGigacageIsForbidden though, logically, the isEnable check does not really depend on whether disabling is forbidden or not. We do this because disablingPrimitiveGigacageIsForbidden is frozen in the Config, and it is, therefore, a stronger guarantee of correctness whereas the variable can be corrupted. 6. Replaced isDisablingPrimitiveGigacageForbidden(), canPrimitiveGigacageBeDisabled(), and isPrimitiveGigacagePermanentlyEnabled() with disablingPrimitiveGigacageIsForbidden(). * CMakeLists.txt: * bmalloc.xcodeproj/project.pbxproj: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): (Gigacage::disablePrimitiveGigacage): (Gigacage::forbidDisablingPrimitiveGigacage): (Gigacage::bmalloc::freezeGigacageConfig): Deleted. (Gigacage::bmalloc::unfreezeGigacageConfig): Deleted. (Gigacage::bmalloc::permanentlyFreezeGigacageConfig): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::UnfreezeGigacageConfigScope): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::~UnfreezeGigacageConfigScope): Deleted. (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. * bmalloc/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::disableNotRequestedForPrimitiveGigacage): (Gigacage::isEnabled): (Gigacage::basePtr): (Gigacage::caged): (Gigacage::forbidDisablingPrimitiveGigacage): (): Deleted. (Gigacage::Config::basePtr const): Deleted. (Gigacage::Config::setBasePtr): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * bmalloc/GigacageConfig.h: Added. (Gigacage::Config::basePtr const): (Gigacage::Config::setBasePtr): * bmalloc/GigacageKind.h: Added. * bmalloc/Heap.cpp: (bmalloc::Heap::usingGigacage): * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: * assembler/testmasm.cpp: (JSC::testCagePreservesPACFailureBit): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::cageTypedArrayStorage): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::caged): * jit/AssemblyHelpers.h: (JSC::AssemblyHelpers::cageConditionally): * llint/LowLevelInterpreter64.asm: * runtime/JSCConfig.h: (JSC::Config::isPermanentlyFrozen): Source/WTF: We now think of the various Config records as being allocated from parts of a WebConfig::g_config buffer. WTF::Config will manage the mechanics of freezing that buffer. And the JSC VM is still the determiner of if/when to freeze the buffer, and it will do this at the end of the construction of the very first VM instance (as before). Gigacage::Config reserves space in WebConfig::g_config. WTF::Config will honor that reservation and place itself after that. JSC::Config will continue to place itself at WTF::Config::spaceForExtensions. The upside of this approach this is that we can now share the same memory page for all the Configs, and can freeze them in one go. The downside is that g_gigacageConfig, g_wtfConfig, and g_jscConfig now have to be macros. This results in some weirdness e.g. they are no longer qualified by namespaces: referring to WTF::g_wtfConfig is now incorrect. * wtf/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: (): Deleted. Canonical link: https://commits.webkit.org/225481@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262434 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-06-02 19:43:17 +00:00
result = vm_protect(mach_task_self(), reinterpret_cast<vm_address_t>(&WebConfig::g_config), ConfigSizeToProtect, DisallowPermissionChangesAfterThis, VM_PROT_READ);
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
#elif OS(LINUX)
Change Gigacage::Config to use storage in WebConfig::g_config instead of its own. https://bugs.webkit.org/show_bug.cgi?id=212585 <rdar://problem/63812487> Reviewed by Yusuke Suzuki. Source/bmalloc: 1. Gigacage::Config now reserves and expect space to be available in an external WebConfig::g_config buffer. Gigacage does not allocate that buffer. 2. Moved Gigacage::Config to GigacageConfig.h. This allows WTFConfig.h to include GigacageConfig.h instead of all of Gigacage.h. 3. Moved Gigacage::Kind to GigacageKind.h. Otherwise, Gigacage::Kind would need to move to GigacageConfig.h which is a weird place to put it. 4. Removed freezeGigacageConfig(), unfreezeGigacageConfig(), and permanentlyFreezeGigacageConfig(). It is no longer possible to temporarily freeze and unfreeze the Gigacage::Config because it now share the same memory page with higher level Configs. permanentlyFreezeGigacageConfig() is no longer needed because it is subsumed by WTF::Config::permanentlyFreeze(), which will freeze the entire WebConfig::g_config buffer. One difference in behavior here is that Gigacage::Config data used to be permanently frozen as soon as forbidDisablingPrimitiveGigacage() is called. Now, it isn't permanently frozen until the end of the construction of the first JSC::VM instance in the process (just like the other Config records). This still guarantees that it is frozen before any JS script can run. 5. Previously, disablePrimitiveGigacage() works by nullifying the Primitive gigacage base pointer. We can no longer do that because the base pointer will be frozen on VM instantiation. Instead, if not forbidden, we now disable the Primitive gigacage by setting a disablePrimitiveGigacageRequested bool variable that is not frozen in the Gigacage::Config. To check if the Primitive gigacage is enabled, the LLInt, AssemblyHelpers::cageConditionally(), and runtime functions will check the following conditions: g_gigacageConfig.basePtr(Primitive) && (disablingPrimitiveGigacageIsForbidden() || disableNotRequestedForPrimitiveGigacage()) The base pointer being null means the gigacage was never set up. If disablingPrimitiveGigacageIsForbidden() is true, then we don't care whether a disable request has been received. Otherwise, the gigacage is only enabled if it has been set up, and a disable request has not been received. Note that the first 2 terms are frozen in the Gigacage::Config. Only the last term is a runtime variable. If disabling is forbidden, then the runtime variable never comes into play. The FTL does not rely on a runtime check for whether the Primitive gigacage is enabled or not. Instead, it relies on a watchpoint to handle this. So, it just works, and there's no performance penalty with adding the 2 extra terms to check. Note also that the jsc shell and the WebProcess will forbid disabling of the Primitive gigacage. This means the AssemblyHelpers::cageConditionally() will also not generate the runtime checks for the 2 extra terms. Only the LLInt and runtime functions will have to do work to check the 2 extra terms. But because these are not in perf critical paths, this is ok. Note that we're deliberately gating the disablePrimitiveGigacageRequested variable check on disablingPrimitiveGigacageIsForbidden though, logically, the isEnable check does not really depend on whether disabling is forbidden or not. We do this because disablingPrimitiveGigacageIsForbidden is frozen in the Config, and it is, therefore, a stronger guarantee of correctness whereas the variable can be corrupted. 6. Replaced isDisablingPrimitiveGigacageForbidden(), canPrimitiveGigacageBeDisabled(), and isPrimitiveGigacagePermanentlyEnabled() with disablingPrimitiveGigacageIsForbidden(). * CMakeLists.txt: * bmalloc.xcodeproj/project.pbxproj: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): (Gigacage::disablePrimitiveGigacage): (Gigacage::forbidDisablingPrimitiveGigacage): (Gigacage::bmalloc::freezeGigacageConfig): Deleted. (Gigacage::bmalloc::unfreezeGigacageConfig): Deleted. (Gigacage::bmalloc::permanentlyFreezeGigacageConfig): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::UnfreezeGigacageConfigScope): Deleted. (Gigacage::bmalloc::UnfreezeGigacageConfigScope::~UnfreezeGigacageConfigScope): Deleted. (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. * bmalloc/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::disableNotRequestedForPrimitiveGigacage): (Gigacage::isEnabled): (Gigacage::basePtr): (Gigacage::caged): (Gigacage::forbidDisablingPrimitiveGigacage): (): Deleted. (Gigacage::Config::basePtr const): Deleted. (Gigacage::Config::setBasePtr): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * bmalloc/GigacageConfig.h: Added. (Gigacage::Config::basePtr const): (Gigacage::Config::setBasePtr): * bmalloc/GigacageKind.h: Added. * bmalloc/Heap.cpp: (bmalloc::Heap::usingGigacage): * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: * assembler/testmasm.cpp: (JSC::testCagePreservesPACFailureBit): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::cageTypedArrayStorage): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::caged): * jit/AssemblyHelpers.h: (JSC::AssemblyHelpers::cageConditionally): * llint/LowLevelInterpreter64.asm: * runtime/JSCConfig.h: (JSC::Config::isPermanentlyFrozen): Source/WTF: We now think of the various Config records as being allocated from parts of a WebConfig::g_config buffer. WTF::Config will manage the mechanics of freezing that buffer. And the JSC VM is still the determiner of if/when to freeze the buffer, and it will do this at the end of the construction of the very first VM instance (as before). Gigacage::Config reserves space in WebConfig::g_config. WTF::Config will honor that reservation and place itself after that. JSC::Config will continue to place itself at WTF::Config::spaceForExtensions. The upside of this approach this is that we can now share the same memory page for all the Configs, and can freeze them in one go. The downside is that g_gigacageConfig, g_wtfConfig, and g_jscConfig now have to be macros. This results in some weirdness e.g. they are no longer qualified by namespaces: referring to WTF::g_wtfConfig is now incorrect. * wtf/Gigacage.h: (Gigacage::disablingPrimitiveGigacageIsForbidden): (Gigacage::isDisablingPrimitiveGigacageForbidden): Deleted. (Gigacage::isPrimitiveGigacagePermanentlyEnabled): Deleted. (Gigacage::canPrimitiveGigacageBeDisabled): Deleted. * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: (): Deleted. Canonical link: https://commits.webkit.org/225481@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262434 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-06-02 19:43:17 +00:00
result = mprotect(&WebConfig::g_config, ConfigSizeToProtect, PROT_READ);
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
#elif OS(WINDOWS)
// FIXME: Implement equivalent, maybe with VirtualProtect.
// Also need to fix WebKitTestRunner.
Move some LLInt globals into JSC::Config. https://bugs.webkit.org/show_bug.cgi?id=216685 rdar://68964544 Reviewed by Keith Miller. Source/bmalloc: Introduce ConfigAlignment to match WTFConfig.h. Added BENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) support to match WTF. * bmalloc/BPlatform.h: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): * bmalloc/GigacageConfig.h: * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: 1. Moved the following into g_jscConfig: Data::s_exceptionInstructions ==> g_jscConfig.llint.exceptionInstructions Data::s_wasmExceptionInstructions ==> g_jscConfig.llint.wasmExceptionInstructions g_opcodeMap ==> g_jscConfig.llint.opcodeMap g_opcodeMapWide16 ==> g_jscConfig.llint.opcodeMapWide16 g_opcodeMapWide32 ==> g_jscConfig.llint.opcodeMapWide32 2. Fixed cloop.rb so that it can take an offset for the leap offlineasm instruction. 3. Fixed x86.rb so that it can take an offset for the leap offlineasm instruction. 4. Fixed arm.rb so that it can take an offset for the leap offlineasm instruction. Note: arm64.rb already does this right. 5. Added JSC::Config::singleton() to return a reference to g_jscConfig. This is useful when debugging with lldb since g_jscConfig is not an actual label, but is a macro that computes the address of the Config record. This patch has been smoke tested on arm64e, x86_64, and cloop (on x86_64 and armv7k). * llint/LLIntData.cpp: (JSC::LLInt::LLIntInitializeAssertScope::LLIntInitializeAssertScope): (JSC::LLInt::LLIntInitializeAssertScope::~LLIntInitializeAssertScope): (JSC::LLInt::LLIntInitializeAssertScope::assertInitializationIsAllowed): (JSC::LLInt::initialize): * llint/LLIntData.h: (JSC::LLInt::exceptionInstructions): (JSC::LLInt::wasmExceptionInstructions): (JSC::LLInt::opcodeMap): (JSC::LLInt::opcodeMapWide16): (JSC::LLInt::opcodeMapWide32): (JSC::LLInt::getOpcode): (JSC::LLInt::getOpcodeWide16): (JSC::LLInt::getOpcodeWide32): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter.cpp: * llint/LowLevelInterpreter64.asm: * llint/WebAssembly.asm: * offlineasm/arm.rb: * offlineasm/cloop.rb: * offlineasm/x86.rb: * runtime/JSCConfig.cpp: (JSC::Config::singleton): * runtime/JSCConfig.h: Source/WTF: 1. Introduce ConfigAlignment as a distinct value from ConfigSizeToProtect. This is because ConfigSizeToProtect is now larger than 1 CeilingOnPageSize on some platforms, but ConfigAlignment only needs to match CeilingOnPageSize. 2. Introduced ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) to disable using the unified g_config record for Windows ports. This is needed because WTF is built as a DLL on Windows. offlineasm does not know how to resolve a DLL exported variable. Additionally, the Windows ports have never supported freezing of the Config record to begin with. So, we're working around this by disabling ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) for Windows. This allows JSC to have its own g_jscConfig record, which solves this issue for now. * wtf/PlatformEnable.h: * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Canonical link: https://commits.webkit.org/229588@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@267371 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-09-21 22:01:12 +00:00
// Note: the Windows port also currently does not support a unified Config
// record, which is needed for the current form of the freezing feature to
// work. See comments in PlatformEnable.h for UNIFIED_AND_FREEZABLE_CONFIG_RECORD.
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
#endif
Move some LLInt globals into JSC::Config. https://bugs.webkit.org/show_bug.cgi?id=216685 rdar://68964544 Reviewed by Keith Miller. Source/bmalloc: Introduce ConfigAlignment to match WTFConfig.h. Added BENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) support to match WTF. * bmalloc/BPlatform.h: * bmalloc/Gigacage.cpp: (Gigacage::ensureGigacage): * bmalloc/GigacageConfig.h: * bmalloc/mbmalloc.cpp: Source/JavaScriptCore: 1. Moved the following into g_jscConfig: Data::s_exceptionInstructions ==> g_jscConfig.llint.exceptionInstructions Data::s_wasmExceptionInstructions ==> g_jscConfig.llint.wasmExceptionInstructions g_opcodeMap ==> g_jscConfig.llint.opcodeMap g_opcodeMapWide16 ==> g_jscConfig.llint.opcodeMapWide16 g_opcodeMapWide32 ==> g_jscConfig.llint.opcodeMapWide32 2. Fixed cloop.rb so that it can take an offset for the leap offlineasm instruction. 3. Fixed x86.rb so that it can take an offset for the leap offlineasm instruction. 4. Fixed arm.rb so that it can take an offset for the leap offlineasm instruction. Note: arm64.rb already does this right. 5. Added JSC::Config::singleton() to return a reference to g_jscConfig. This is useful when debugging with lldb since g_jscConfig is not an actual label, but is a macro that computes the address of the Config record. This patch has been smoke tested on arm64e, x86_64, and cloop (on x86_64 and armv7k). * llint/LLIntData.cpp: (JSC::LLInt::LLIntInitializeAssertScope::LLIntInitializeAssertScope): (JSC::LLInt::LLIntInitializeAssertScope::~LLIntInitializeAssertScope): (JSC::LLInt::LLIntInitializeAssertScope::assertInitializationIsAllowed): (JSC::LLInt::initialize): * llint/LLIntData.h: (JSC::LLInt::exceptionInstructions): (JSC::LLInt::wasmExceptionInstructions): (JSC::LLInt::opcodeMap): (JSC::LLInt::opcodeMapWide16): (JSC::LLInt::opcodeMapWide32): (JSC::LLInt::getOpcode): (JSC::LLInt::getOpcodeWide16): (JSC::LLInt::getOpcodeWide32): * llint/LowLevelInterpreter.asm: * llint/LowLevelInterpreter.cpp: * llint/LowLevelInterpreter64.asm: * llint/WebAssembly.asm: * offlineasm/arm.rb: * offlineasm/cloop.rb: * offlineasm/x86.rb: * runtime/JSCConfig.cpp: (JSC::Config::singleton): * runtime/JSCConfig.h: Source/WTF: 1. Introduce ConfigAlignment as a distinct value from ConfigSizeToProtect. This is because ConfigSizeToProtect is now larger than 1 CeilingOnPageSize on some platforms, but ConfigAlignment only needs to match CeilingOnPageSize. 2. Introduced ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) to disable using the unified g_config record for Windows ports. This is needed because WTF is built as a DLL on Windows. offlineasm does not know how to resolve a DLL exported variable. Additionally, the Windows ports have never supported freezing of the Config record to begin with. So, we're working around this by disabling ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD) for Windows. This allows JSC to have its own g_jscConfig record, which solves this issue for now. * wtf/PlatformEnable.h: * wtf/WTFConfig.cpp: (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Canonical link: https://commits.webkit.org/229588@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@267371 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-09-21 22:01:12 +00:00
#endif // ENABLE(UNIFIED_AND_FREEZABLE_CONFIG_RECORD)
Introduce WTF::Config and put Signal.cpp's init-once globals in it. https://bugs.webkit.org/show_bug.cgi?id=211729 <rdar://problem/62938878> Reviewed by Keith Miller and Saam Barati. Source/JavaScriptCore: 1. Initialize VMTraps' signals early now that we'll be freezing signals at the end of the first VM initialization. 2. Move the !initializeThreadingHasBeenCalled RELEASE_ASSERT in initializeThreading() to the bottom of the function. This way, we'll also catch bugs which may cause us to jump into the middle of the function. Added a compilerFence there to ensure that the RELEASE_ASSERT is only executed after all initialization is done. This guarantees that it will only be executed at the end. 3. Call WTF::Config::permanentlyFreeze() from JSC::Config::permanentlyFreeze() for obvious reasons: freezing one should freeze the other. * runtime/InitializeThreading.cpp: (JSC::initializeThreading): * runtime/JSCConfig.cpp: (JSC::Config::permanentlyFreeze): * runtime/VMTraps.cpp: (JSC::VMTraps::initializeSignals): * runtime/VMTraps.h: Source/WTF: 1. Added WTF::Config for storing globals that effectively serve as constants i.e we'll be initializing them before or during the first VM instantiation, but should not have any reason to modify them later. The WTF::Config will be frozen (along with JSC::Config) at the end of instantiating the first VM instance. 2. Added a Config::AssertNotFrozenScope RAII object to ensure that initialization operations that should only be called at initialization time, will not be called once the Config has been frozen. 3. Moved most of Signal.cpp's globals into WTF::Config. The only globals (or statics) not moved are ones that cannot be moved because they require a non-trivial default constructor (once_flag), or need to be modifiable at runtime (e.g. Lock). Instead of freezing the once_flag, we sanity check the call_once block with the Config::AssertNotFrozenScope. 4. SignalHandler records are now allocated from arrays of SignalHandlerMemory in the WTF::Config. The number of signal handlers we will ever install is always finite. Hence, there's no reason to use a dynamic data structure like the LocklessBag to hold it. We introduce a SignalHandlers struct to manage these arrays (and all the other Signal.cpp globals that we want to move to the WTF::Config). Amongst other things, SignalHandlers provides the abstractions for: a. allocating memory for the SignalHandler instances. See SignalHandlers::alloc(). b. iterating SignalHandler instances. See SignalHandlers::forEachHandler(). To maintain the synchronization properties of the LocklessBag, SignalHandlers::alloc() uses a mutex. In practice, this mutex will never be contended on because all signal handlers are now installed at initialization time before any concurrency comes into play. 5. We now initialize activeThreads() eagerly via initializeThreading. In production configurations, this does not matter because signal handler installations will always trigger its initialization. However, in debugging configurations, we may end up disabling the use of all signal handlers. As a result, we need to do this eager initialization to ensure that it is done before we freeze the WTF::Config. * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Threading.cpp: (WTF::initializeThreading): * wtf/WTFConfig.cpp: Added. (WTF::Config::disableFreezingForTesting): (WTF::Config::permanentlyFreeze): * wtf/WTFConfig.h: Added. (WTF::Config::configureForTesting): (WTF::Config::AssertNotFrozenScope::~AssertNotFrozenScope): * wtf/threads/Signals.cpp: (WTF::SignalHandlers::alloc): (WTF::SignalHandlers::forEachHandler const): (WTF::startMachExceptionHandlerThread): (WTF::handleSignalsWithMach): (WTF::setExceptionPorts): (WTF::activeThreads): (WTF::installSignalHandler): (WTF::jscSignalHandler): (WTF::SignalHandlers::initialize): * wtf/threads/Signals.h: Canonical link: https://commits.webkit.org/224656@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@261538 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-05-12 02:10:05 +00:00
RELEASE_ASSERT(!result);
RELEASE_ASSERT(g_wtfConfig.isPermanentlyFrozen);
}
} // namespace WTF