Changeset 219647 in webkit


Ignore:
Timestamp:
Jul 18, 2017 9:53:59 PM (7 years ago)
Author:
Yusuke Suzuki
Message:

WTF::Thread should have the threads stack bounds.
https://bugs.webkit.org/show_bug.cgi?id=173975

Reviewed by Mark Lam.

Source/JavaScriptCore:

There is a site in JSC that try to walk another thread's stack.
Currently, stack bounds are stored in WTFThreadData which is located
in TLS. Thus, only the thread itself can access its own WTFThreadData.
We workaround this situation by holding StackBounds in MachineThread in JSC,
but StackBounds should be put in WTF::Thread instead.

This patch adds StackBounds to WTF::Thread. StackBounds information is tightly
coupled with Thread. Thus putting it in WTF::Thread is natural choice.

  • heap/MachineStackMarker.cpp:

(JSC::MachineThreads::MachineThread::MachineThread):
(JSC::MachineThreads::MachineThread::captureStack):

  • heap/MachineStackMarker.h:

(JSC::MachineThreads::MachineThread::stackBase):
(JSC::MachineThreads::MachineThread::stackEnd):

  • runtime/VMTraps.cpp:

Source/WebCore:

When creating WebThread, we first allocate WebCore::ThreadGlobalData in UI thread
and share it with WebThread.
The problem is that WebCore::ThreadGlobalData has CachedResourceRequestInitiators.
It allocates AtomicString, which requires WTFThreadData.

In this patch, we call WTF::initializeThreading() before allocating WebCore::ThreadGlobalData.
And we also call AtomicString::init() before calling WebCore::ThreadGlobalData since
WebCore::ThreadGlobalData allocates AtomicString.

  • platform/ios/wak/WebCoreThread.mm:

(StartWebThread):

Source/WTF:

We move StackBounds from WTFThreadData to WTF::Thread.
One important thing is that we should make valid StackBounds
visible to Thread::create() caller. When the caller get
WTF::Thread from Thread::create(), this WTF::Thread should
have a valid StackBounds. But StackBounds information can be
retrived only in the WTF::Thread's thread itself.

We also clean up WTF::initializeThreading. StringImpl::empty()
is now statically initialized by using constexpr constructor.
Thus we do not need to call StringImpl::empty() explicitly here.
And WTF::initializeThreading() does not have any main thread
affinity right now in all the platforms. So we fix the comment
in Threading.h. Then, now, WTF::initializeThreading() is called
in UI thread when using Web thread in iOS.

  • wtf/StackBounds.h:

(WTF::StackBounds::emptyBounds):
(WTF::StackBounds::StackBounds):

  • wtf/Threading.cpp:

(WTF::threadEntryPoint):
(WTF::Thread::create):
(WTF::Thread::currentMayBeNull):
(WTF::Thread::initialize):
(WTF::initializeThreading):

  • wtf/Threading.h:

(WTF::Thread::stack):

  • wtf/ThreadingPthreads.cpp:

(WTF::Thread::initializeCurrentThreadEvenIfNonWTFCreated):
(WTF::Thread::current):
(WTF::initializeCurrentThreadEvenIfNonWTFCreated): Deleted.
(WTF::Thread::currentMayBeNull): Deleted.

  • wtf/ThreadingWin.cpp:

(WTF::Thread::initializeCurrentThreadEvenIfNonWTFCreated):
(WTF::Thread::initializeCurrentThreadInternal):
(WTF::Thread::current):

  • wtf/WTFThreadData.cpp:

(WTF::WTFThreadData::WTFThreadData):

  • wtf/WTFThreadData.h:

(WTF::WTFThreadData::stack):

Location:
trunk/Source
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r219644 r219647  
     12017-07-18  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        WTF::Thread should have the threads stack bounds.
     4        https://bugs.webkit.org/show_bug.cgi?id=173975
     5
     6        Reviewed by Mark Lam.
     7
     8        There is a site in JSC that try to walk another thread's stack.
     9        Currently, stack bounds are stored in WTFThreadData which is located
     10        in TLS. Thus, only the thread itself can access its own WTFThreadData.
     11        We workaround this situation by holding StackBounds in MachineThread in JSC,
     12        but StackBounds should be put in WTF::Thread instead.
     13
     14        This patch adds StackBounds to WTF::Thread. StackBounds information is tightly
     15        coupled with Thread. Thus putting it in WTF::Thread is natural choice.
     16
     17        * heap/MachineStackMarker.cpp:
     18        (JSC::MachineThreads::MachineThread::MachineThread):
     19        (JSC::MachineThreads::MachineThread::captureStack):
     20        * heap/MachineStackMarker.h:
     21        (JSC::MachineThreads::MachineThread::stackBase):
     22        (JSC::MachineThreads::MachineThread::stackEnd):
     23        * runtime/VMTraps.cpp:
     24
    1252017-07-18  Andy Estes  <aestes@apple.com>
    226
  • trunk/Source/JavaScriptCore/heap/MachineStackMarker.cpp

    r219595 r219647  
    239239    : m_thread(WTF::Thread::current())
    240240{
    241     auto stackBounds = wtfThreadData().stack();
    242     m_stackBase = stackBounds.origin();
    243     m_stackEnd = stackBounds.end();
    244241}
    245242
     
    302299std::pair<void*, size_t> MachineThreads::MachineThread::captureStack(void* stackTop)
    303300{
    304     char* begin = reinterpret_cast_ptr<char*>(m_stackBase);
     301    char* begin = reinterpret_cast_ptr<char*>(stackBase());
    305302    char* end = bitwise_cast<char*>(WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(stackTop)));
    306303    ASSERT(begin >= end);
     
    309306    ASSERT(WTF::roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(endWithRedZone)) == reinterpret_cast<uintptr_t>(endWithRedZone));
    310307
    311     if (endWithRedZone < m_stackEnd)
    312         endWithRedZone = reinterpret_cast_ptr<char*>(m_stackEnd);
     308    if (endWithRedZone < stackEnd())
     309        endWithRedZone = reinterpret_cast_ptr<char*>(stackEnd());
    313310
    314311    std::swap(begin, endWithRedZone);
  • trunk/Source/JavaScriptCore/heap/MachineStackMarker.h

    r219427 r219647  
    7373
    7474        WTF::ThreadIdentifier threadID() const { return m_thread->id(); }
    75         void* stackBase() const { return m_stackBase; }
    76         void* stackEnd() const { return m_stackEnd; }
     75        void* stackBase() const { return m_thread->stack().origin(); }
     76        void* stackEnd() const { return m_thread->stack().end(); }
    7777
    7878        Ref<WTF::Thread> m_thread;
    79         void* m_stackBase;
    80         void* m_stackEnd;
    8179        MachineThread* m_next { nullptr };
    8280        MachineThread* m_prev { nullptr };
     
    105103    CurrentThreadState stateName; \
    106104    stateName.stackTop = &stateName; \
    107     stateName.stackOrigin = wtfThreadData().stack().origin(); \
     105    stateName.stackOrigin = Thread::current().stack().origin(); \
    108106    ALLOCATE_AND_GET_REGISTER_STATE(stateName ## _registerState); \
    109107    stateName.registerState = &stateName ## _registerState
  • trunk/Source/JavaScriptCore/runtime/VMTraps.cpp

    r219427 r219647  
    268268
    269269                Thread& thread = *ownerThread->get();
    270                 StackBounds stackBounds = StackBounds::emptyBounds();
    271                 {
    272                     // FIXME: We need to use the machine threads because it is the only non-TLS source
    273                     // for the stack bounds of this thread. We should keep in on the WTF::Thread instead.
    274                     // see: https://bugs.webkit.org/show_bug.cgi?id=173975
    275                     MachineThreads& machineThreads = vm.heap.machineThreads();
    276                     auto machineThreadsLock = tryHoldLock(machineThreads.getLock());
    277                     if (!machineThreadsLock)
    278                         return; // Try again later.
    279 
    280                     auto& threadList = machineThreads.threadsListHead(machineThreadsLock);
    281                     for (MachineThreads::MachineThread* machineThread = threadList.head(); machineThread; machineThread = machineThread->next()) {
    282                         if (machineThread->m_thread.get() == thread)
    283                             stackBounds = StackBounds(machineThread->stackBase(), machineThread->stackEnd());
    284                     }
    285                     RELEASE_ASSERT(!stackBounds.isEmpty());
    286                 }
    287 
    288                 vm.traps().tryInstallTrapBreakpoints(context, stackBounds);
     270                vm.traps().tryInstallTrapBreakpoints(context, thread.stack());
    289271            });
    290272        }
  • trunk/Source/WTF/ChangeLog

    r219644 r219647  
     12017-07-18  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        WTF::Thread should have the threads stack bounds.
     4        https://bugs.webkit.org/show_bug.cgi?id=173975
     5
     6        Reviewed by Mark Lam.
     7
     8        We move StackBounds from WTFThreadData to WTF::Thread.
     9        One important thing is that we should make valid StackBounds
     10        visible to Thread::create() caller. When the caller get
     11        WTF::Thread from Thread::create(), this WTF::Thread should
     12        have a valid StackBounds. But StackBounds information can be
     13        retrived only in the WTF::Thread's thread itself.
     14
     15        We also clean up WTF::initializeThreading. StringImpl::empty()
     16        is now statically initialized by using constexpr constructor.
     17        Thus we do not need to call StringImpl::empty() explicitly here.
     18        And WTF::initializeThreading() does not have any main thread
     19        affinity right now in all the platforms. So we fix the comment
     20        in Threading.h. Then, now, WTF::initializeThreading() is called
     21        in UI thread when using Web thread in iOS.
     22
     23        * wtf/StackBounds.h:
     24        (WTF::StackBounds::emptyBounds):
     25        (WTF::StackBounds::StackBounds):
     26        * wtf/Threading.cpp:
     27        (WTF::threadEntryPoint):
     28        (WTF::Thread::create):
     29        (WTF::Thread::currentMayBeNull):
     30        (WTF::Thread::initialize):
     31        (WTF::initializeThreading):
     32        * wtf/Threading.h:
     33        (WTF::Thread::stack):
     34        * wtf/ThreadingPthreads.cpp:
     35        (WTF::Thread::initializeCurrentThreadEvenIfNonWTFCreated):
     36        (WTF::Thread::current):
     37        (WTF::initializeCurrentThreadEvenIfNonWTFCreated): Deleted.
     38        (WTF::Thread::currentMayBeNull): Deleted.
     39        * wtf/ThreadingWin.cpp:
     40        (WTF::Thread::initializeCurrentThreadEvenIfNonWTFCreated):
     41        (WTF::Thread::initializeCurrentThreadInternal):
     42        (WTF::Thread::current):
     43        * wtf/WTFThreadData.cpp:
     44        (WTF::WTFThreadData::WTFThreadData):
     45        * wtf/WTFThreadData.h:
     46        (WTF::WTFThreadData::stack):
     47
    1482017-07-18  Andy Estes  <aestes@apple.com>
    249
  • trunk/Source/WTF/wtf/StackBounds.h

    r219427 r219647  
    4141
    4242public:
    43     static StackBounds emptyBounds() { return StackBounds(); }
     43    static constexpr StackBounds emptyBounds() { return StackBounds(); }
    4444
    4545    static StackBounds currentThreadStackBounds()
     
    128128
    129129private:
    130     StackBounds()
    131         : m_origin(0)
    132         , m_bound(0)
     130    constexpr StackBounds()
     131        : m_origin(nullptr)
     132        , m_bound(nullptr)
    133133    {
    134134    }
  • trunk/Source/WTF/wtf/Threading.cpp

    r219427 r219647  
    4747namespace WTF {
    4848
     49enum class Stage {
     50    Start, Initialized
     51};
     52
    4953struct NewThreadContext {
    50     WTF_MAKE_FAST_ALLOCATED;
    51 public:
    5254    const char* name;
    5355    Function<void()> entryPoint;
    54     Mutex creationMutex;
     56    Stage stage;
     57    Mutex mutex;
     58    ThreadCondition condition;
    5559};
    5660
     
    8589{
    8690    NewThreadContext* context = static_cast<NewThreadContext*>(contextData);
     91    Function<void()> entryPoint;
     92    {
     93        // Block until our creating thread has completed any extra setup work, including establishing ThreadIdentifier.
     94        MutexLocker locker(context->mutex);
    8795
    88     // Block until our creating thread has completed any extra setup work, including
    89     // establishing ThreadIdentifier.
    90     {
    91         MutexLocker locker(context->creationMutex);
     96        Thread::initializeCurrentThreadInternal(context->name);
     97        entryPoint = WTFMove(context->entryPoint);
     98
     99        // Ack completion of initialization to the creating thread.
     100        context->stage = Stage::Initialized;
     101        context->condition.signal();
    92102    }
    93 
    94     Thread::initializeCurrentThreadInternal(context->name);
    95 
    96     auto entryPoint = WTFMove(context->entryPoint);
    97 
    98     // Delete the context before starting the thread.
    99     delete context;
    100103
    101104    entryPoint();
     
    104107RefPtr<Thread> Thread::create(const char* name, Function<void()>&& entryPoint)
    105108{
    106     NewThreadContext* context = new NewThreadContext { name, WTFMove(entryPoint), { } };
     109    NewThreadContext context { name, WTFMove(entryPoint), Stage::Start, { }, { } };
    107110
    108     // Prevent the thread body from executing until we've established the thread identifier.
    109     MutexLocker locker(context->creationMutex);
     111    MutexLocker locker(context.mutex);
     112    RefPtr<Thread> result = Thread::createInternal(threadEntryPoint, &context, name);
     113    // After establishing Thread, release the mutex and wait for completion of initialization.
     114    while (context.stage != Stage::Initialized)
     115        context.condition.wait(context.mutex);
    110116
    111     return Thread::createInternal(threadEntryPoint, context, name);
     117    return result;
     118}
     119
     120Thread* Thread::currentMayBeNull()
     121{
     122    ThreadHolder* data = ThreadHolder::current();
     123    if (data)
     124        return &data->thread();
     125    return nullptr;
     126}
     127
     128void Thread::initialize()
     129{
     130    m_stack = StackBounds::currentThreadStackBounds();
    112131}
    113132
     
    167186    std::call_once(initializeKey, [] {
    168187        ThreadHolder::initializeOnce();
    169         // StringImpl::empty() does not construct its static string in a threadsafe fashion,
    170         // so ensure it has been initialized from here.
    171         StringImpl::empty();
    172188        initializeRandomNumberGenerator();
    173189        wtfThreadData();
  • trunk/Source/WTF/wtf/Threading.h

    r219427 r219647  
    3939#include <wtf/PlatformRegisters.h>
    4040#include <wtf/RefPtr.h>
     41#include <wtf/StackBounds.h>
    4142#include <wtf/ThreadSafeRefCounted.h>
    4243
     
    6869    // Returns Thread object.
    6970    WTF_EXPORT_PRIVATE static Thread& current();
    70     WTF_EXPORT_PRIVATE static Thread* currentMayBeNull();
     71    static Thread* currentMayBeNull();
    7172
    7273    // Returns ThreadIdentifier directly. It is useful if the user only cares about identity
     
    109110    // Helpful for platforms where the thread name must be set from within the thread.
    110111    static void initializeCurrentThreadInternal(const char* threadName);
     112    static void initializeCurrentThreadEvenIfNonWTFCreated();
    111113
    112114    WTF_EXPORT_PRIVATE void dump(PrintStream& out) const;
     
    126128    static void initializePlatformThreading();
    127129
     130    const StackBounds& stack() const
     131    {
     132        return m_stack;
     133    }
     134
    128135#if OS(DARWIN)
    129136    mach_port_t machThread() { return m_platformThread; }
     
    141148    void establish(HANDLE, ThreadIdentifier);
    142149#endif
     150    void initialize();
    143151
    144152#if USE(PTHREADS) && !OS(DARWIN)
     
    172180    ThreadIdentifier m_id { 0 };
    173181    JoinableState m_joinableState { Joinable };
     182    StackBounds m_stack { StackBounds::emptyBounds() };
    174183    bool m_didExit { false };
    175184#if USE(PTHREADS)
     
    191200};
    192201
    193 // This function must be called from the main thread. It is safe to call it repeatedly.
    194 // Darwin is an exception to this rule: it is OK to call it from any thread, the only
    195 // requirement is that the calls are not reentrant.
     202// This function can be called from any threads.
    196203WTF_EXPORT_PRIVATE void initializeThreading();
    197204
  • trunk/Source/WTF/wtf/ThreadingPthreads.cpp

    r219595 r219647  
    188188}
    189189
    190 static void initializeCurrentThreadEvenIfNonWTFCreated()
    191 {
     190void Thread::initializeCurrentThreadEvenIfNonWTFCreated()
     191{
     192    Thread::current().initialize();
    192193#if !OS(DARWIN)
    193194    sigset_t mask;
     
    299300}
    300301
    301 Thread* Thread::currentMayBeNull()
    302 {
    303     ThreadHolder* data = ThreadHolder::current();
    304     if (data)
    305         return &data->thread();
    306     return nullptr;
    307 }
    308 
    309302Thread& Thread::current()
    310303{
     
    313306
    314307    // Not a WTF-created thread, ThreadIdentifier is not established yet.
    315     RefPtr<Thread> thread = adoptRef(new Thread());
     308    Ref<Thread> thread = adoptRef(*new Thread());
    316309    thread->establish(pthread_self());
    317     ThreadHolder::initialize(*thread);
     310    ThreadHolder::initialize(thread.get());
    318311    initializeCurrentThreadEvenIfNonWTFCreated();
    319     return *thread;
     312    return thread.get();
    320313}
    321314
  • trunk/Source/WTF/wtf/ThreadingWin.cpp

    r219427 r219647  
    117117}
    118118
     119void Thread::initializeCurrentThreadEvenIfNonWTFCreated()
     120{
     121    Thread::current().initialize();
     122}
     123
    119124// MS_VC_EXCEPTION, THREADNAME_INFO, and setThreadNameInternal all come from <http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx>.
    120125static const DWORD MS_VC_EXCEPTION = 0x406D1388;
     
    146151    }
    147152#endif
     153    initializeCurrentThreadEvenIfNonWTFCreated();
    148154}
    149155
     
    262268Thread& Thread::current()
    263269{
    264     ThreadHolder* data = ThreadHolder::current();
    265     if (data)
    266         return data->thread();
     270    if (Thread* current = currentMayBeNull())
     271        return *current;
    267272
    268273    // Not a WTF-created thread, ThreadIdentifier is not established yet.
     
    275280    thread->establish(handle, currentID());
    276281    ThreadHolder::initialize(thread.get(), Thread::currentID());
     282    initializeCurrentThreadEvenIfNonWTFCreated();
    277283    return thread.get();
    278284}
  • trunk/Source/WTF/wtf/WTFThreadData.cpp

    r219427 r219647  
    4141
    4242WTFThreadData::WTFThreadData()
    43     : m_apiData(0)
    44     , m_currentAtomicStringTable(0)
    45     , m_defaultAtomicStringTable(0)
    46     , m_atomicStringTableDestructor(0)
    47     , m_stackBounds(StackBounds::currentThreadStackBounds())
    48 #if ENABLE(STACK_STATS)
    49     , m_stackStats()
    50 #endif
    51     , m_savedStackPointerAtVMEntry(0)
     43    : m_stackBounds(StackBounds::currentThreadStackBounds())
    5244    , m_savedLastStackTop(stack().origin())
    5345{
  • trunk/Source/WTF/wtf/WTFThreadData.h

    r219427 r219647  
    6060    const StackBounds& stack()
    6161    {
    62         // We need to always get a fresh StackBounds from the OS due to how fibers work.
    63         // See https://bugs.webkit.org/show_bug.cgi?id=102411
    64 #if OS(WINDOWS)
    65         m_stackBounds = StackBounds::currentThreadStackBounds();
    66 #endif
    6762        return m_stackBounds;
    6863    }
     
    9590    }
    9691
    97     void* m_apiData;
     92    void* m_apiData { nullptr };
    9893
    9994private:
    100     AtomicStringTable* m_currentAtomicStringTable;
    101     AtomicStringTable* m_defaultAtomicStringTable;
    102     AtomicStringTableDestructor m_atomicStringTableDestructor;
     95    AtomicStringTable* m_currentAtomicStringTable { nullptr };
     96    AtomicStringTable* m_defaultAtomicStringTable { nullptr };
     97    AtomicStringTableDestructor m_atomicStringTableDestructor { nullptr };
    10398
    10499    StackBounds m_stackBounds;
     
    106101    StackStats::PerThreadStats m_stackStats;
    107102#endif
    108     void* m_savedStackPointerAtVMEntry;
     103    void* m_savedStackPointerAtVMEntry { nullptr };
    109104    void* m_savedLastStackTop;
    110105
  • trunk/Source/WebCore/ChangeLog

    r219646 r219647  
     12017-07-18  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        WTF::Thread should have the threads stack bounds.
     4        https://bugs.webkit.org/show_bug.cgi?id=173975
     5
     6        Reviewed by Mark Lam.
     7
     8        When creating WebThread, we first allocate WebCore::ThreadGlobalData in UI thread
     9        and share it with WebThread.
     10        The problem is that WebCore::ThreadGlobalData has CachedResourceRequestInitiators.
     11        It allocates AtomicString, which requires WTFThreadData.
     12
     13        In this patch, we call WTF::initializeThreading() before allocating WebCore::ThreadGlobalData.
     14        And we also call AtomicString::init() before calling WebCore::ThreadGlobalData since
     15        WebCore::ThreadGlobalData allocates AtomicString.
     16
     17        * platform/ios/wak/WebCoreThread.mm:
     18        (StartWebThread):
     19
    1202017-07-18  Myles C. Maxfield  <mmaxfield@apple.com>
    221
  • trunk/Source/WebCore/platform/ios/wak/WebCoreThread.mm

    r219427 r219647  
    703703    webThreadStarted = TRUE;
    704704
     705    // ThreadGlobalData touches AtomicString, which requires WTFThreadData and Threading initialization.
     706    WTF::initializeThreading();
     707
     708    // Initialize AtomicString on the main thread.
     709    WTF::AtomicString::init();
     710
    705711    // Initialize ThreadGlobalData on the main UI thread so that the WebCore thread
    706712    // can later set it's thread-specific data to point to the same objects.
    707713    WebCore::ThreadGlobalData& unused = WebCore::threadGlobalData();
    708714    (void)unused;
    709 
    710     // Initialize AtomicString on the main thread.
    711     WTF::AtomicString::init();
    712715
    713716    RunLoop::initializeMainRunLoop();
Note: See TracChangeset for help on using the changeset viewer.