Commit 4547c5ef authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[compiler] Allow deopts to slightly exceed the stack limit

We recently extended function-entry stack checks by an offset
representing the difference in optimized and unoptimized frame sizes,
with the intent of avoiding stack overflows during deopts. Although
the generated code is very efficient (just a single additional
register subtraction, executed exactly once per call), perf impact
is measurable.

To avoid the overhead in most cases, this CL adds a stack slack,
currently set to 256 bytes, by which deopts are allowed to exceed the
real V8 stack limit. For function-entry stack checks with an offset
less than stack slack, the offset is not applied and the more
efficient version of the stack check is emitted.

The V8 limit is chosen to be smaller than OS stack size (assumed to
be at least 1 MB). This guarantee is upheld even with slack.

Bug: chromium:1020989,v8:9534
Change-Id: Idee2e7ad1fa7810bf086a9f72ce00a9717010310
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1910099Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65025}
parent 8a91cb2c
......@@ -29,6 +29,10 @@ class RecursiveMutex;
namespace internal {
constexpr int KB = 1024;
constexpr int MB = KB * 1024;
constexpr int GB = MB * 1024;
// Determine whether we are running in a simulated environment.
// Setting USE_SIMULATOR explicitly from the build script will force
// the use of a simulated environment.
......@@ -75,6 +79,17 @@ namespace internal {
// Minimum stack size in KB required by compilers.
constexpr int kStackSpaceRequiredForCompilation = 40;
// In order to emit more efficient stack checks in optimized code,
// deoptimization may implicitly exceed the V8 stack limit by this many bytes.
// Stack checks in functions with `difference between optimized and unoptimized
// stack frame sizes <= slack` can simply emit the simple stack check.
constexpr int kStackLimitSlackForDeoptimizationInBytes = 256;
// Sanity-check, assuming that we aim for a real OS stack size of at least 1MB.
STATIC_ASSERT(V8_DEFAULT_STACK_SIZE_KB* KB +
kStackLimitSlackForDeoptimizationInBytes <=
MB);
// Determine whether double field unboxing feature is enabled.
#if V8_TARGET_ARCH_64_BIT && !defined(V8_COMPRESS_POINTERS)
#define V8_DOUBLE_FIELDS_UNBOXING false
......@@ -123,9 +138,6 @@ using byte = uint8_t;
// -----------------------------------------------------------------------------
// Constants
constexpr int KB = 1024;
constexpr int MB = KB * KB;
constexpr int GB = KB * KB * KB;
constexpr int kMaxInt = 0x7FFFFFFF;
constexpr int kMinInt = -kMaxInt - 1;
constexpr int kMaxInt8 = (1 << 7) - 1;
......
......@@ -125,7 +125,7 @@ bool CodeGenerator::ShouldApplyOffsetToStackCheck(Instruction* instr,
if (kind != StackCheckKind::kJSFunctionEntry) return false;
uint32_t stack_check_offset = *offset = GetStackCheckOffset();
return stack_check_offset > 0;
return stack_check_offset > kStackLimitSlackForDeoptimizationInBytes;
}
uint32_t CodeGenerator::GetStackCheckOffset() {
......
......@@ -822,8 +822,11 @@ void Deoptimizer::DoComputeOutputFrames() {
// the optimized frame in stack checks in optimized code. We do this by
// applying an offset to stack checks (see kArchStackPointerGreaterThan in the
// code generator).
CHECK_GT(static_cast<uintptr_t>(caller_frame_top_) - total_output_frame_size,
stack_guard->real_jslimit());
// Note that we explicitly allow deopts to exceed the limit by a certain
// number of slack bytes.
CHECK_GT(
static_cast<uintptr_t>(caller_frame_top_) - total_output_frame_size,
stack_guard->real_jslimit() - kStackLimitSlackForDeoptimizationInBytes);
}
void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment