blob: f2679cfa79f9c390bbf7443215b698ce118b6cd9 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeBasePch.h"
/*
* The following diagram depicts the layout of the user-mode stack. To the left is what the stack
* looks like to the OS. To the right are the logical partitions Chakra divides the usable stack into.
* The goal of SO checks in the runtime is to never touch a guard page. i.e. we always detect
* that we might run out of stack space (at specific points in code) and raise a stack overflow
* exception. We thus guarantee that our data structures are consistent even when a SO exception is raised.
*
* All stack probes check if the current stack pointer - requested size > current stack limit.
*
* stack start (low) +----------------------+
* | MEM_RESERVE |
* +----------------------+
* | Thread stack |
* ~ guarantee ~
* | (PAGE_GUARD) |
* +----------------------+ <--------------> +----------------------+
* | MEM_RESERVE | | |
* ~ ~ ~ overflow handling | (B)
* | | | buffer |
* +----------------------+ +----------------------+ <---- stackLimit
* | PAGE_GUARD | | |
* +----------------------+ | |
* | MEM_COMMIT | | | script region |
* ~ PAGE_READWRITE ~ ~ ~ (A)
* | | | |
* (high) +----------------------+ <--------------> +----------------------+
*/
void
StackProber::Initialize()
{
// NumGuardPages is 2 on x86/x86-64
// 1 MEM_RESERVE page at the bottom of the stack
// 1 PAGE_GUARD | PAGE_READWRITE page that serves as the guard page
const size_t guardPageSize = Js::Constants::NumGuardPages * AutoSystemInfo::PageSize;
const size_t stackOverflowBuffer = Js::Constants::StackOverflowHandlingBufferPages * AutoSystemInfo::PageSize;
size_t stackBottom = 0; // This is the low address limit (here we consider stack growing down).
ULONG stackGuarantee = 0;
#if defined(_M_IX86) && defined(_MSC_VER)
stackBottom = __readfsdword(0xE0C); // points to the DeAllocationStack on the TEB - which turns to be the stack bottom.
#elif defined(_M_AMD64) && defined(_MSC_VER)
stackBottom = __readgsqword(0x1478);
#elif defined(_M_ARM)
ULONG lowLimit, highLimit;
::GetCurrentThreadStackLimits(&lowLimit, &highLimit);
stackBottom = lowLimit;
#elif defined(_M_ARM64)
ULONG64 lowLimit, highLimit;
::GetCurrentThreadStackLimits(&lowLimit, &highLimit);
stackBottom = lowLimit;
#elif !defined(_MSC_VER)
ULONG_PTR lowLimit = 0;
ULONG_PTR highLimit = 0;
::GetCurrentThreadStackLimits(&lowLimit, &highLimit);
stackBottom = lowLimit;
#else
stackBottom = NULL;
Js::Throw::NotImplemented();
#endif
Assert(stackBottom);
#ifdef _WIN32
// Calling this API with stackGuarantee == 0 *gets* current stack guarantee.
SetThreadStackGuarantee(&stackGuarantee);
#endif
stackLimit = stackBottom + guardPageSize + stackGuarantee + stackOverflowBuffer;
}