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
|
|
|
/*
|
2021-03-25 02:53:03 +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)
|
2021-03-12 05:43:53 +00:00
|
|
|
#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
|
|
|
|
|
2021-03-12 05:43:53 +00:00
|
|
|
#include <mutex>
|
|
|
|
|
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 {
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
2021-03-12 05:43:53 +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
|
|
|
|
|
2021-03-23 20:55:20 +00:00
|
|
|
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();
|
|
|
|
|
2021-03-25 02:53:03 +00:00
|
|
|
#if HAVE(VM_FLAGS_PERMANENT)
|
2021-03-23 20:55:20 +00:00
|
|
|
if (result != KERN_SUCCESS) {
|
|
|
|
flags &= ~VM_FLAGS_PERMANENT;
|
|
|
|
result = attemptVMMapping();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-03-12 05:43:53 +00:00
|
|
|
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;
|
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;
|
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.
|
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
|
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
|