Chromium Code Reviews| Index: third_party/WebKit/Source/wtf/StackUtil.cpp |
| diff --git a/third_party/WebKit/Source/platform/heap/StackFrameDepth.cpp b/third_party/WebKit/Source/wtf/StackUtil.cpp |
| similarity index 58% |
| copy from third_party/WebKit/Source/platform/heap/StackFrameDepth.cpp |
| copy to third_party/WebKit/Source/wtf/StackUtil.cpp |
| index 1d164f510a36de4ecb3328e6c80065f4913eca5d..52eff68b07ddf7919677e845896be26f54445f97 100644 |
| --- a/third_party/WebKit/Source/platform/heap/StackFrameDepth.cpp |
| +++ b/third_party/WebKit/Source/wtf/StackUtil.cpp |
| @@ -1,10 +1,12 @@ |
| -// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "platform/heap/StackFrameDepth.h" |
| +#include "wtf/StackUtil.h" |
| -#include "public/platform/Platform.h" |
| +#include "wtf/Assertions.h" |
| +#include "wtf/Threading.h" |
| +#include "wtf/WTFThreadData.h" |
| #if OS(WIN) |
| #include <stddef.h> |
| @@ -14,51 +16,30 @@ |
| extern "C" void* __libc_stack_end; // NOLINT |
| #endif |
| -namespace blink { |
| +namespace WTF { |
| -static const char* s_avoidOptimization = nullptr; |
| +namespace { |
| -// NEVER_INLINE ensures that |dummy| array on configureLimit() is not optimized |
| -// away, and the stack frame base register is adjusted |kSafeStackFrameSize|. |
| -NEVER_INLINE static uintptr_t currentStackFrameBaseOnCallee(const char* dummy) { |
| - s_avoidOptimization = dummy; |
| - return StackFrameDepth::currentStackFrame(); |
| +uintptr_t mainThreadStackStart() { |
| + static uintptr_t s_mainThreadStackStart = |
| + reinterpret_cast<uintptr_t>(WTF::getStackStart()) - sizeof(void*); |
|
haraken
2017/01/18 05:29:42
Add a comment why we're subtracting sizeof(void*).
Charlie Harrison
2017/01/18 16:29:55
I had to look at historical blame to figure this o
|
| + return s_mainThreadStackStart; |
| } |
| -uintptr_t StackFrameDepth::getFallbackStackLimit() { |
| - // Allocate an |kSafeStackFrameSize|-sized object on stack and query |
| - // stack frame base after it. |
| - char dummy[kSafeStackFrameSize]; |
| - |
| - // Check that the stack frame can be used. |
| - dummy[sizeof(dummy) - 1] = 0; |
| - return currentStackFrameBaseOnCallee(dummy); |
| -} |
| - |
| -void StackFrameDepth::enableStackLimit() { |
| - // All supported platforms will currently return a non-zero estimate, |
| - // except if ASan is enabled. |
| - size_t stackSize = getUnderestimatedStackSize(); |
| - if (!stackSize) { |
| - m_stackFrameLimit = getFallbackStackLimit(); |
| - return; |
| +uintptr_t mainThreadUnderestimatedStackSize() { |
| + static uintptr_t s_underestimatedStackSize; |
| + if (s_underestimatedStackSize) |
| + return s_underestimatedStackSize; |
| + size_t underestimatedStackSize = getUnderestimatedStackSize(); |
| + if (underestimatedStackSize > sizeof(void*)) { |
| + s_underestimatedStackSize = underestimatedStackSize - sizeof(void*); |
|
haraken
2017/01/18 05:29:42
Ditto.
Charlie Harrison
2017/01/18 16:29:55
Done.
|
| } |
| - |
| - static const int kStackRoomSize = 1024; |
| - |
| - Address stackBase = reinterpret_cast<Address>(getStackStart()); |
| - RELEASE_ASSERT(stackSize > static_cast<const size_t>(kStackRoomSize)); |
| - size_t stackRoom = stackSize - kStackRoomSize; |
| - RELEASE_ASSERT(stackBase > reinterpret_cast<Address>(stackRoom)); |
| - m_stackFrameLimit = reinterpret_cast<uintptr_t>(stackBase - stackRoom); |
| - |
| - // If current stack use is already exceeding estimated limit, mark as |
| - // disabled. |
| - if (!isSafeToRecurse()) |
| - disableStackLimit(); |
| + return s_underestimatedStackSize; |
| } |
| -size_t StackFrameDepth::getUnderestimatedStackSize() { |
| +} // namespace |
| + |
| +size_t getUnderestimatedStackSize() { |
| // FIXME: ASAN bot uses a fake stack as a thread stack frame, |
| // and its size is different from the value which APIs tells us. |
| #if defined(ADDRESS_SANITIZER) |
| @@ -127,14 +108,14 @@ size_t StackFrameDepth::getUnderestimatedStackSize() { |
| } |
| return pthread_get_stacksize_np(pthread_self()); |
| #elif OS(WIN) && COMPILER(MSVC) |
| - return ThreadState::current()->threadStackSize(); |
| + return WTFThreadData::threadStackSize(); |
| #else |
| #error "Stack frame size estimation not supported on this platform." |
| return 0; |
| #endif |
| } |
| -void* StackFrameDepth::getStackStart() { |
| +void* getStackStart() { |
| #if defined(__GLIBC__) || OS(ANDROID) || OS(FREEBSD) |
| pthread_attr_t attr; |
| int error; |
| @@ -162,7 +143,7 @@ void* StackFrameDepth::getStackStart() { |
| // See https://code.google.com/p/nativeclient/issues/detail?id=3431. |
| return __libc_stack_end; |
| #else |
| - ASSERT_NOT_REACHED(); |
| + NOTREACHED(); |
| return nullptr; |
| #endif |
| #elif OS(MACOSX) |
| @@ -181,4 +162,51 @@ void* StackFrameDepth::getStackStart() { |
| #endif |
| } |
| -} // namespace blink |
| +namespace internal { |
| + |
| +bool mayNotBeMainThread() { |
|
haraken
2017/01/18 05:29:42
Can we move this function (and all functions calle
Charlie Harrison
2017/01/18 16:29:55
Done, though I haven't inlined the initializers to
|
| + uintptr_t dummy; |
| + uintptr_t addressDiff = |
| + mainThreadStackStart() - reinterpret_cast<uintptr_t>(&dummy); |
| + // This is a fast way to judge if we are in the main thread. |
| + // If |&dummy| is within |s_mainThreadUnderestimatedStackSize| byte from |
| + // the stack start of the main thread, we judge that we are in |
| + // the main thread. |
| + return addressDiff >= mainThreadUnderestimatedStackSize(); |
| +} |
| + |
| +#if OS(WIN) && COMPILER(MSVC) |
| +size_t threadStackSize() { |
| + // Notice that we cannot use the TIB's StackLimit for the stack end, as i |
| + // tracks the end of the committed range. We're after the end of the reserved |
| + // stack area (most of which will be uncommitted, most times.) |
| + MEMORY_BASIC_INFORMATION stackInfo; |
| + memset(&stackInfo, 0, sizeof(MEMORY_BASIC_INFORMATION)); |
| + size_t resultSize = |
| + VirtualQuery(&stackInfo, &stackInfo, sizeof(MEMORY_BASIC_INFORMATION)); |
| + DCHECK_GE(resultSize, sizeof(MEMORY_BASIC_INFORMATION)); |
| + uint8_t* stackEnd = reinterpret_cast<uint8_t*>(stackInfo.AllocationBase); |
| + |
| + uint8_t* stackStart = reinterpret_cast<uint8_t*>(WTF::getStackStart()); |
| + RELEASE_ASSERT(stackStart && stackStart > stackEnd); |
| + size_t s_threadStackSize = static_cast<size_t>(stackStart - stackEnd); |
| + // When the third last page of the reserved stack is accessed as a |
| + // guard page, the second last page will be committed (along with removing |
| + // the guard bit on the third last) _and_ a stack overflow exception |
| + // is raised. |
| + // |
| + // We have zero interest in running into stack overflow exceptions while |
| + // marking objects, so simply consider the last three pages + one above |
| + // as off-limits and adjust the reported stack size accordingly. |
| + // |
| + // http://blogs.msdn.com/b/satyem/archive/2012/08/13/thread-s-stack-memory-management.aspx |
| + // explains the details. |
| + RELEASE_ASSERT(s_threadStackSize > 4 * 0x1000); |
| + s_threadStackSize -= 4 * 0x1000; |
| + return s_threadStackSize; |
| +} |
| +#endif |
| + |
| +} // namespace internal |
| + |
| +} // namespace WTF |