From 45813a034212e56e5651157fec1c89e1349e7879 Mon Sep 17 00:00:00 2001 From: "trop[bot]" <37223003+trop[bot]@users.noreply.github.com> Date: Mon, 27 Sep 2021 16:54:46 -0700 Subject: [PATCH] fix: crash in v8 due to regexp reentrancy (#31144) * fix: crash in v8 due to regexp reentrancy Check failed: !regexp_stack_->is_in_use() Refs https://bugs.chromium.org/p/chromium/issues/detail?id=1250646 Refs https://bugs.chromium.org/p/v8/issues/detail?id=11382 * chore: update patches * chore: update patches Co-authored-by: deepak1556 Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com> --- patches/v8/.patches | 3 + ...iling_cctest_for_irregexp_reentrancy.patch | 109 ++ ...p_allow_reentrant_irregexp_execution.patch | 1736 +++++++++++++++++ ...stack_parameter_from_regexp_matchers.patch | 397 ++++ 4 files changed, 2245 insertions(+) create mode 100644 patches/v8/regexp_add_a_currently_failing_cctest_for_irregexp_reentrancy.patch create mode 100644 patches/v8/regexp_allow_reentrant_irregexp_execution.patch create mode 100644 patches/v8/regexp_remove_the_stack_parameter_from_regexp_matchers.patch diff --git a/patches/v8/.patches b/patches/v8/.patches index 6aec06bde0e0a..58604303265f0 100644 --- a/patches/v8/.patches +++ b/patches/v8/.patches @@ -7,3 +7,6 @@ do_not_export_private_v8_symbols_on_windows.patch fix_build_deprecated_attirbute_for_older_msvc_versions.patch fix_disable_implies_dcheck_for_node_stream_array_buffers.patch cppgc-js_support_eager_traced_value_in_ephemeron_pairs.patch +regexp_add_a_currently_failing_cctest_for_irregexp_reentrancy.patch +regexp_allow_reentrant_irregexp_execution.patch +regexp_remove_the_stack_parameter_from_regexp_matchers.patch diff --git a/patches/v8/regexp_add_a_currently_failing_cctest_for_irregexp_reentrancy.patch b/patches/v8/regexp_add_a_currently_failing_cctest_for_irregexp_reentrancy.patch new file mode 100644 index 0000000000000..cfb47865d2bcf --- /dev/null +++ b/patches/v8/regexp_add_a_currently_failing_cctest_for_irregexp_reentrancy.patch @@ -0,0 +1,109 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jakob Gruber +Date: Mon, 6 Sep 2021 08:29:33 +0200 +Subject: Add a (currently failing) cctest for irregexp reentrancy + +The test should be enabled once reentrancy is supported. + +Bug: v8:11382 +Change-Id: Ifb90d8a6fd8bf9f05e9ca2405d4e04e013ce7ee3 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3138201 +Commit-Queue: Jakob Gruber +Auto-Submit: Jakob Gruber +Reviewed-by: Patrick Thier +Cr-Commit-Position: refs/heads/main@{#76667} + +diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status +index 9b369044754443ccf5ce07c3612f0a928e565ad6..21afa5310647eb67f3fe3fc4f2e0721b4bb4e0f6 100644 +--- a/test/cctest/cctest.status ++++ b/test/cctest/cctest.status +@@ -136,6 +136,9 @@ + 'test-strings/Traverse': [PASS, HEAVY], + 'test-swiss-name-dictionary-csa/DeleteAtBoundaries': [PASS, HEAVY], + 'test-swiss-name-dictionary-csa/SameH2': [PASS, HEAVY], ++ ++ # TODO(v8:11382): Reenable once irregexp is reentrant. ++ 'test-regexp/RegExpInterruptReentrantExecution': [FAIL], + }], # ALWAYS + + ############################################################################## +@@ -666,6 +669,9 @@ + + # Instruction cache flushing is disabled in jitless mode. + 'test-icache/*': [SKIP], ++ ++ # Tests generated irregexp code. ++ 'test-regexp/RegExpInterruptReentrantExecution': [SKIP], + }], # lite_mode or variant == jitless + + ############################################################################## +diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc +index 25fba193bbcc41d127d36949e103cb59688bfed7..b21222f14c533cb630946b6066bfe24d1be49f93 100644 +--- a/test/cctest/test-api.cc ++++ b/test/cctest/test-api.cc +@@ -21658,10 +21658,6 @@ TEST(RegExpInterruptAndMakeSubjectTwoByteExternal) { + // experimental engine. + i::FLAG_enable_experimental_regexp_engine_on_excessive_backtracks = false; + RegExpInterruptTest test; +- // We want to be stuck regexp execution, so no fallback to linear-time +- // engine. +- // TODO(mbid,v8:10765): Find a way to test interrupt support of the +- // experimental engine. + test.RunTest(RegExpInterruptTest::MakeSubjectTwoByteExternal); + } + +diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc +index aa24fe3dd230ecc06d9eea2920826dc123979c58..2fb5b3d056f78d3eef3a0a1032ee99df1b2f35c5 100644 +--- a/test/cctest/test-regexp.cc ++++ b/test/cctest/test-regexp.cc +@@ -2348,6 +2348,50 @@ TEST(UnicodePropertyEscapeCodeSize) { + } + } + ++namespace { ++ ++struct RegExpExecData { ++ i::Isolate* isolate; ++ i::Handle regexp; ++ i::Handle subject; ++}; ++ ++i::Handle RegExpExec(const RegExpExecData* d) { ++ return i::RegExp::Exec(d->isolate, d->regexp, d->subject, 0, ++ d->isolate->regexp_last_match_info()) ++ .ToHandleChecked(); ++} ++ ++void ReenterRegExp(v8::Isolate* isolate, void* data) { ++ RegExpExecData* d = static_cast(data); ++ i::Handle result = RegExpExec(d); ++ CHECK(result->IsNull()); ++} ++ ++} // namespace ++ ++// Tests reentrant irregexp calls. ++TEST(RegExpInterruptReentrantExecution) { ++ CHECK(!i::FLAG_jitless); ++ i::FLAG_regexp_tier_up = false; // Enter irregexp, not the interpreter. ++ ++ LocalContext context; ++ v8::Isolate* isolate = context->GetIsolate(); ++ v8::HandleScope scope(isolate); ++ ++ RegExpExecData d; ++ d.isolate = reinterpret_cast(isolate); ++ d.regexp = v8::Utils::OpenHandle( ++ *v8::RegExp::New(context.local(), v8_str("(a*)*x"), v8::RegExp::kNone) ++ .ToLocalChecked()); ++ d.subject = v8::Utils::OpenHandle(*v8_str("aaaa")); ++ ++ isolate->RequestInterrupt(&ReenterRegExp, &d); ++ ++ i::Handle result = RegExpExec(&d); ++ CHECK(result->IsNull()); ++} ++ + #undef CHECK_PARSE_ERROR + #undef CHECK_SIMPLE + #undef CHECK_MIN_MAX diff --git a/patches/v8/regexp_allow_reentrant_irregexp_execution.patch b/patches/v8/regexp_allow_reentrant_irregexp_execution.patch new file mode 100644 index 0000000000000..1256bdf2de5f3 --- /dev/null +++ b/patches/v8/regexp_allow_reentrant_irregexp_execution.patch @@ -0,0 +1,1736 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jakob Gruber +Date: Thu, 23 Sep 2021 07:26:38 +0200 +Subject: Allow reentrant irregexp execution + +.. by reusing the regexp stack from potentially multiple nested +irregexp activations. + +To do this, we now maintain a stack pointer in RegExpStack. This stack +pointer is synchronized at all boundaries between generated irregexp +code and the outside world, i.e. when entering or returning from +irregexp code, and when calling into C functions such as GrowStack. + +Fixed: v8:11382 +Change-Id: I5ed27630c1a64ebf3afb9ddf80fb60ea067c0c40 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3162604 +Reviewed-by: Toon Verwaest +Reviewed-by: Patrick Thier +Commit-Queue: Toon Verwaest +Auto-Submit: Jakob Gruber +Cr-Commit-Position: refs/heads/main@{#77013} + +diff --git a/src/api/api.cc b/src/api/api.cc +index 041a4eaddf7856e2fd9eb3336285e7edb6774712..1e6dde1aaeab016734c3ab290c3b79a959497d92 100644 +--- a/src/api/api.cc ++++ b/src/api/api.cc +@@ -99,7 +99,6 @@ + #include "src/profiler/heap-snapshot-generator-inl.h" + #include "src/profiler/profile-generator-inl.h" + #include "src/profiler/tick-sample.h" +-#include "src/regexp/regexp-stack.h" + #include "src/regexp/regexp-utils.h" + #include "src/runtime/runtime.h" + #include "src/snapshot/code-serializer.h" +diff --git a/src/codegen/external-reference.cc b/src/codegen/external-reference.cc +index e1d8c5d96ef5cc183fe5e479bf1e4b220791100c..bdf0adf415e70c1f893bbbcb2e0e8c1b156e66ff 100644 +--- a/src/codegen/external-reference.cc ++++ b/src/codegen/external-reference.cc +@@ -738,6 +738,11 @@ ExternalReference ExternalReference::address_of_regexp_stack_memory_top_address( + isolate->regexp_stack()->memory_top_address_address()); + } + ++ExternalReference ExternalReference::address_of_regexp_stack_stack_pointer( ++ Isolate* isolate) { ++ return ExternalReference(isolate->regexp_stack()->stack_pointer_address()); ++} ++ + ExternalReference ExternalReference::javascript_execution_assert( + Isolate* isolate) { + return ExternalReference(isolate->javascript_execution_assert_address()); +diff --git a/src/codegen/external-reference.h b/src/codegen/external-reference.h +index cbc3463841332fbd3a9d40f5a1b3d3d1c3d382f7..86deb275f8b179eef7784cb30139b3c9735b7db7 100644 +--- a/src/codegen/external-reference.h ++++ b/src/codegen/external-reference.h +@@ -72,6 +72,8 @@ class StatsCounter; + "RegExpStack::limit_address_address()") \ + V(address_of_regexp_stack_memory_top_address, \ + "RegExpStack::memory_top_address_address()") \ ++ V(address_of_regexp_stack_stack_pointer, \ ++ "RegExpStack::stack_pointer_address()") \ + V(address_of_static_offsets_vector, "OffsetsVector::static_offsets_vector") \ + V(thread_in_wasm_flag_address_address, \ + "Isolate::thread_in_wasm_flag_address_address") \ +diff --git a/src/debug/debug-interface.cc b/src/debug/debug-interface.cc +index 5112c5ba73f2da26632488c26053c45ea86b51a4..a46c8b6ab955c9c6c1c873bfe4020d135683589e 100644 +--- a/src/debug/debug-interface.cc ++++ b/src/debug/debug-interface.cc +@@ -16,7 +16,6 @@ + #include "src/objects/js-generator-inl.h" + #include "src/objects/stack-frame-info-inl.h" + #include "src/profiler/heap-profiler.h" +-#include "src/regexp/regexp-stack.h" + #include "src/strings/string-builder-inl.h" + + #if V8_ENABLE_WEBASSEMBLY +@@ -303,10 +302,7 @@ void SetTerminateOnResume(Isolate* v8_isolate) { + bool CanBreakProgram(Isolate* v8_isolate) { + i::Isolate* isolate = reinterpret_cast(v8_isolate); + ENTER_V8_DO_NOT_USE(isolate); +- // We cannot break a program if we are currently running a regexp. +- // TODO(yangguo): fix this exception. +- return !isolate->regexp_stack()->is_in_use() && +- isolate->debug()->AllFramesOnStackAreBlackboxed(); ++ return isolate->debug()->AllFramesOnStackAreBlackboxed(); + } + + Isolate* Script::GetIsolate() const { +diff --git a/src/execution/isolate.cc b/src/execution/isolate.cc +index 8363c52c491e9bc6272696cae38f68b141a3e4a6..f2c6ad5167046f5c0a1141dbc9aed956b88ea143 100644 +--- a/src/execution/isolate.cc ++++ b/src/execution/isolate.cc +@@ -3626,7 +3626,6 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data, + store_stub_cache_ = new StubCache(this); + materialized_object_store_ = new MaterializedObjectStore(this); + regexp_stack_ = new RegExpStack(); +- regexp_stack_->isolate_ = this; + date_cache_ = new DateCache(); + heap_profiler_ = new HeapProfiler(heap()); + interpreter_ = new interpreter::Interpreter(this); +diff --git a/src/regexp/arm/regexp-macro-assembler-arm.cc b/src/regexp/arm/regexp-macro-assembler-arm.cc +index 6c90e00817342a115ec49a21b561a7014e0ce8f8..10766db4cf1d41ad0fee0754c6eaeebe46ace500 100644 +--- a/src/regexp/arm/regexp-macro-assembler-arm.cc ++++ b/src/regexp/arm/regexp-macro-assembler-arm.cc +@@ -6,15 +6,13 @@ + + #include "src/regexp/arm/regexp-macro-assembler-arm.h" + +-#include "src/codegen/assembler-inl.h" ++#include "src/codegen/arm/assembler-arm-inl.h" + #include "src/codegen/macro-assembler.h" + #include "src/heap/factory.h" + #include "src/logging/log.h" +-#include "src/objects/objects-inl.h" +-#include "src/regexp/regexp-macro-assembler.h" ++#include "src/objects/code-inl.h" + #include "src/regexp/regexp-stack.h" + #include "src/snapshot/embedded/embedded-data.h" +-#include "src/strings/unicode.h" + + namespace v8 { + namespace internal { +@@ -102,6 +100,7 @@ RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(Isolate* isolate, Zone* zone, + : NativeRegExpMacroAssembler(isolate, zone), + masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes, + NewAssemblerBuffer(kRegExpCodeSize))), ++ no_root_array_scope_(masm_), + mode_(mode), + num_registers_(registers_to_save), + num_saved_registers_(registers_to_save), +@@ -110,8 +109,6 @@ RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(Isolate* isolate, Zone* zone, + success_label_(), + backtrack_label_(), + exit_label_() { +- masm_->set_root_array_available(false); +- + DCHECK_EQ(0, registers_to_save % 2); + __ jmp(&entry_label_); // We'll write the entry code later. + __ bind(&start_label_); // And then continue from here. +@@ -619,6 +616,42 @@ void RegExpMacroAssemblerARM::Fail() { + __ jmp(&exit_label_); + } + ++void RegExpMacroAssemblerARM::LoadRegExpStackPointerFromMemory(Register dst) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); ++ __ mov(dst, Operand(ref)); ++ __ ldr(dst, MemOperand(dst)); ++} ++ ++void RegExpMacroAssemblerARM::StoreRegExpStackPointerToMemory( ++ Register src, Register scratch) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); ++ __ mov(scratch, Operand(ref)); ++ __ str(src, MemOperand(scratch)); ++} ++ ++void RegExpMacroAssemblerARM::PushRegExpBasePointer(Register scratch1, ++ Register scratch2) { ++ LoadRegExpStackPointerFromMemory(scratch1); ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ mov(scratch2, Operand(ref)); ++ __ ldr(scratch2, MemOperand(scratch2)); ++ __ sub(scratch2, scratch1, scratch2); ++ __ str(scratch2, MemOperand(frame_pointer(), kRegExpStackBasePointer)); ++} ++ ++void RegExpMacroAssemblerARM::PopRegExpBasePointer(Register scratch1, ++ Register scratch2) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ ldr(scratch1, MemOperand(frame_pointer(), kRegExpStackBasePointer)); ++ __ mov(scratch2, Operand(ref)); ++ __ ldr(scratch2, MemOperand(scratch2)); ++ __ add(scratch1, scratch1, scratch2); ++ StoreRegExpStackPointerToMemory(scratch1, scratch2); ++} + + Handle RegExpMacroAssemblerARM::GetCode(Handle source) { + Label return_r0; +@@ -654,6 +687,13 @@ Handle RegExpMacroAssemblerARM::GetCode(Handle source) { + __ push(r0); // Make room for "string start - 1" constant. + STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize); + __ push(r0); // The backtrack counter. ++ STATIC_ASSERT(kRegExpStackBasePointer == ++ kBacktrackCount - kSystemPointerSize); ++ __ push(r0); // The regexp stack base ptr. ++ ++ // Store the regexp base pointer - we'll later restore it / write it to ++ // memory when returning from this irregexp code object. ++ PushRegExpBasePointer(r0, r1); + + // Check if we have space on the stack for registers. + Label stack_limit_hit; +@@ -736,7 +776,7 @@ Handle RegExpMacroAssemblerARM::GetCode(Handle source) { + } + + // Initialize backtrack stack pointer. +- __ ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd)); ++ LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); + + __ jmp(&start_label_); + +@@ -834,6 +874,10 @@ Handle RegExpMacroAssemblerARM::GetCode(Handle source) { + } + + __ bind(&return_r0); ++ // Restore the original regexp stack pointer value (effectively, pop the ++ // stored base pointer). ++ PopRegExpBasePointer(r1, r2); ++ + // Skip sp past regexp registers and local variables.. + __ mov(sp, frame_pointer()); + // Restore registers r4..r11 and return (restoring lr to pc). +@@ -851,12 +895,16 @@ Handle RegExpMacroAssemblerARM::GetCode(Handle source) { + if (check_preempt_label_.is_linked()) { + SafeCallTarget(&check_preempt_label_); + ++ StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r1); ++ + CallCheckStackGuardState(); + __ cmp(r0, Operand::Zero()); + // If returning non-zero, we should end execution with the given + // result as return value. + __ b(ne, &return_r0); + ++ LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); ++ + // String might have moved: Reload end of string from frame. + __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); + SafeReturn(); +@@ -867,17 +915,18 @@ Handle RegExpMacroAssemblerARM::GetCode(Handle source) { + SafeCallTarget(&stack_overflow_label_); + // Reached if the backtrack-stack limit has been hit. + +- // Call GrowStack(backtrack_stackpointer(), &stack_base) +- static const int num_arguments = 3; +- __ PrepareCallCFunction(num_arguments); +- __ mov(r0, backtrack_stackpointer()); +- __ add(r1, frame_pointer(), Operand(kStackHighEnd)); +- __ mov(r2, Operand(ExternalReference::isolate_address(isolate()))); ++ // Call GrowStack(isolate). ++ ++ StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r1); ++ ++ static constexpr int kNumArguments = 1; ++ __ PrepareCallCFunction(kNumArguments); ++ __ mov(r0, Operand(ExternalReference::isolate_address(isolate()))); + ExternalReference grow_stack = + ExternalReference::re_grow_stack(isolate()); +- __ CallCFunction(grow_stack, num_arguments); +- // If return nullptr, we have failed to grow the stack, and +- // must exit with a stack-overflow exception. ++ __ CallCFunction(grow_stack, kNumArguments); ++ // If nullptr is returned, we have failed to grow the stack, and must exit ++ // with a stack-overflow exception. + __ cmp(r0, Operand::Zero()); + __ b(eq, &exit_with_exception); + // Otherwise use return value as new stack pointer. +@@ -984,14 +1033,24 @@ void RegExpMacroAssemblerARM::ReadCurrentPositionFromRegister(int reg) { + __ ldr(current_input_offset(), register_location(reg)); + } + ++void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ mov(r1, Operand(ref)); ++ __ ldr(r1, MemOperand(r1)); ++ __ sub(r0, backtrack_stackpointer(), r1); ++ __ str(r0, register_location(reg)); ++} + + void RegExpMacroAssemblerARM::ReadStackPointerFromRegister(int reg) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ mov(r0, Operand(ref)); ++ __ ldr(r0, MemOperand(r0)); + __ ldr(backtrack_stackpointer(), register_location(reg)); +- __ ldr(r0, MemOperand(frame_pointer(), kStackHighEnd)); +- __ add(backtrack_stackpointer(), backtrack_stackpointer(), Operand(r0)); ++ __ add(backtrack_stackpointer(), backtrack_stackpointer(), r0); + } + +- + void RegExpMacroAssemblerARM::SetCurrentPositionFromEnd(int by) { + Label after_position; + __ cmp(current_input_offset(), Operand(-by * char_size())); +@@ -1037,14 +1096,6 @@ void RegExpMacroAssemblerARM::ClearRegisters(int reg_from, int reg_to) { + } + } + +- +-void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) { +- __ ldr(r1, MemOperand(frame_pointer(), kStackHighEnd)); +- __ sub(r0, backtrack_stackpointer(), r1); +- __ str(r0, register_location(reg)); +-} +- +- + // Private methods: + + void RegExpMacroAssemblerARM::CallCheckStackGuardState() { +diff --git a/src/regexp/arm/regexp-macro-assembler-arm.h b/src/regexp/arm/regexp-macro-assembler-arm.h +index a02a4dc2af546e53a89161aad9f3500a51c062f8..a76f9dea70264d79d57ebd6c60b100bc9e0a499d 100644 +--- a/src/regexp/arm/regexp-macro-assembler-arm.h ++++ b/src/regexp/arm/regexp-macro-assembler-arm.h +@@ -5,8 +5,6 @@ + #ifndef V8_REGEXP_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_ + #define V8_REGEXP_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_ + +-#include "src/base/strings.h" +-#include "src/codegen/arm/assembler-arm.h" + #include "src/codegen/macro-assembler.h" + #include "src/regexp/regexp-macro-assembler.h" + +@@ -115,8 +113,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM + static const int kSuccessfulCaptures = kInputString - kPointerSize; + static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize; + static const int kBacktrackCount = kStringStartMinusOne - kSystemPointerSize; ++ // Stores the initial value of the regexp stack pointer in a ++ // position-independent representation (in case the regexp stack grows and ++ // thus moves). ++ static const int kRegExpStackBasePointer = ++ kBacktrackCount - kSystemPointerSize; ++ + // First register address. Following registers are below it on the stack. +- static const int kRegisterZero = kBacktrackCount - kSystemPointerSize; ++ static const int kRegisterZero = kRegExpStackBasePointer - kSystemPointerSize; + + // Initial size of code buffer. + static const int kRegExpCodeSize = 1024; +@@ -129,7 +133,6 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM + // Check whether we are exceeding the stack limit on the backtrack stack. + void CheckStackLimit(); + +- + // Generate a call to CheckStackGuardState. + void CallCheckStackGuardState(); + +@@ -138,27 +141,27 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM + + // Register holding the current input position as negative offset from + // the end of the string. +- inline Register current_input_offset() { return r6; } ++ static constexpr Register current_input_offset() { return r6; } + + // The register containing the current character after LoadCurrentCharacter. +- inline Register current_character() { return r7; } ++ static constexpr Register current_character() { return r7; } + + // Register holding address of the end of the input string. +- inline Register end_of_input_address() { return r10; } ++ static constexpr Register end_of_input_address() { return r10; } + + // Register holding the frame address. Local variables, parameters and + // regexp registers are addressed relative to this. +- inline Register frame_pointer() { return fp; } ++ static constexpr Register frame_pointer() { return fp; } + + // The register containing the backtrack stack top. Provides a meaningful + // name to the register. +- inline Register backtrack_stackpointer() { return r8; } ++ static constexpr Register backtrack_stackpointer() { return r8; } + + // Register holding pointer to the current code object. +- inline Register code_pointer() { return r5; } ++ static constexpr Register code_pointer() { return r5; } + + // Byte size of chars in the string to match (decided by the Mode argument) +- inline int char_size() { return static_cast(mode_); } ++ inline int char_size() const { return static_cast(mode_); } + + // Equivalent to a conditional branch to the label, unless the label + // is nullptr, in which case it is a conditional Backtrack. +@@ -178,19 +181,25 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM + // and increments it by a word size. + inline void Pop(Register target); + ++ void LoadRegExpStackPointerFromMemory(Register dst); ++ void StoreRegExpStackPointerToMemory(Register src, Register scratch); ++ void PushRegExpBasePointer(Register scratch1, Register scratch2); ++ void PopRegExpBasePointer(Register scratch1, Register scratch2); ++ + Isolate* isolate() const { return masm_->isolate(); } + +- MacroAssembler* masm_; ++ MacroAssembler* const masm_; ++ const NoRootArrayScope no_root_array_scope_; + + // Which mode to generate code for (Latin1 or UC16). +- Mode mode_; ++ const Mode mode_; + + // One greater than maximal register index actually used. + int num_registers_; + + // Number of registers to output at the end (the saved registers + // are always 0..num_saved_registers_-1) +- int num_saved_registers_; ++ const int num_saved_registers_; + + // Labels used internally. + Label entry_label_; +diff --git a/src/regexp/arm64/regexp-macro-assembler-arm64.cc b/src/regexp/arm64/regexp-macro-assembler-arm64.cc +index 6edb1335760e71442fec98c5d5a5ccbb81a3091e..911744b8b1c6d8a49100d88b53f8d9aedb943e2a 100644 +--- a/src/regexp/arm64/regexp-macro-assembler-arm64.cc ++++ b/src/regexp/arm64/regexp-macro-assembler-arm64.cc +@@ -113,6 +113,7 @@ RegExpMacroAssemblerARM64::RegExpMacroAssemblerARM64(Isolate* isolate, + : NativeRegExpMacroAssembler(isolate, zone), + masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes, + NewAssemblerBuffer(kRegExpCodeSize))), ++ no_root_array_scope_(masm_), + mode_(mode), + num_registers_(registers_to_save), + num_saved_registers_(registers_to_save), +@@ -121,8 +122,6 @@ RegExpMacroAssemblerARM64::RegExpMacroAssemblerARM64(Isolate* isolate, + success_label_(), + backtrack_label_(), + exit_label_() { +- masm_->set_root_array_available(false); +- + DCHECK_EQ(0, registers_to_save % 2); + // We can cache at most 16 W registers in x0-x7. + STATIC_ASSERT(kNumCachedRegisters <= 16); +@@ -700,6 +699,42 @@ void RegExpMacroAssemblerARM64::Fail() { + __ B(&exit_label_); + } + ++void RegExpMacroAssemblerARM64::LoadRegExpStackPointerFromMemory(Register dst) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); ++ __ Mov(dst, ref); ++ __ Ldr(dst, MemOperand(dst)); ++} ++ ++void RegExpMacroAssemblerARM64::StoreRegExpStackPointerToMemory( ++ Register src, Register scratch) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); ++ __ Mov(scratch, ref); ++ __ Str(src, MemOperand(scratch)); ++} ++ ++void RegExpMacroAssemblerARM64::PushRegExpBasePointer(Register scratch1, ++ Register scratch2) { ++ LoadRegExpStackPointerFromMemory(scratch1); ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ Mov(scratch2, ref); ++ __ Ldr(scratch2, MemOperand(scratch2)); ++ __ Sub(scratch2, scratch1, scratch2); ++ __ Str(scratch2, MemOperand(frame_pointer(), kRegExpStackBasePointer)); ++} ++ ++void RegExpMacroAssemblerARM64::PopRegExpBasePointer(Register scratch1, ++ Register scratch2) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ Ldr(scratch1, MemOperand(frame_pointer(), kRegExpStackBasePointer)); ++ __ Mov(scratch2, ref); ++ __ Ldr(scratch2, MemOperand(scratch2)); ++ __ Add(scratch1, scratch1, scratch2); ++ StoreRegExpStackPointerToMemory(scratch1, scratch2); ++} + + Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { + Label return_w0; +@@ -745,22 +780,27 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { + __ Mov(input_end(), x3); + __ Mov(output_array(), x4); + +- // Set the number of registers we will need to allocate, that is: +- // - kSuccessCounter / success_counter (X register) +- // - kBacktrackCount (X register) +- // - (num_registers_ - kNumCachedRegisters) (W registers) +- int num_wreg_to_allocate = num_registers_ - kNumCachedRegisters; +- // Do not allocate registers on the stack if they can all be cached. +- if (num_wreg_to_allocate < 0) { num_wreg_to_allocate = 0; } +- // Make room for the success_counter and kBacktrackCount. Each X (64-bit) +- // register is equivalent to two W (32-bit) registers. +- num_wreg_to_allocate += 2 + 2; +- + // Make sure the stack alignment will be respected. +- int alignment = masm_->ActivationFrameAlignment(); ++ const int alignment = masm_->ActivationFrameAlignment(); + DCHECK_EQ(alignment % 16, 0); +- int align_mask = (alignment / kWRegSize) - 1; +- num_wreg_to_allocate = (num_wreg_to_allocate + align_mask) & ~align_mask; ++ const int align_mask = (alignment / kWRegSize) - 1; ++ ++ // Make room for stack locals. ++ static constexpr int kWRegPerXReg = kXRegSize / kWRegSize; ++ DCHECK_EQ(kNumberOfStackLocals * kWRegPerXReg, ++ ((kNumberOfStackLocals * kWRegPerXReg) + align_mask) & ~align_mask); ++ __ Claim(kNumberOfStackLocals * kWRegPerXReg); ++ ++ // Store the regexp base pointer - we'll later restore it / write it to ++ // memory when returning from this irregexp code object. ++ PushRegExpBasePointer(x10, x11); ++ ++ // Set the number of registers we will need to allocate, that is: ++ // - (num_registers_ - kNumCachedRegisters) (W registers) ++ const int num_stack_registers = ++ std::max(0, num_registers_ - kNumCachedRegisters); ++ const int num_wreg_to_allocate = ++ (num_stack_registers + align_mask) & ~align_mask; + + // Check if we have space on the stack. + Label stack_limit_hit; +@@ -840,9 +880,9 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { + } + + // Initialize backtrack stack pointer. +- __ Ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackBase)); ++ LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); + +- // Execute ++ // Execute. + __ B(&start_label_); + + if (backtrack_label_.is_linked()) { +@@ -1014,7 +1054,7 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { + } + + if (exit_label_.is_linked()) { +- // Exit and return w0 ++ // Exit and return w0. + __ Bind(&exit_label_); + if (global()) { + __ Ldr(w0, MemOperand(frame_pointer(), kSuccessCounter)); +@@ -1022,8 +1062,11 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { + } + + __ Bind(&return_w0); ++ // Restore the original regexp stack pointer value (effectively, pop the ++ // stored base pointer). ++ PopRegExpBasePointer(x10, x11); + +- // Set stack pointer back to first register to retain ++ // Set stack pointer back to first register to retain. + __ Mov(sp, fp); + __ Pop(fp, lr); + +@@ -1040,6 +1083,9 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { + + if (check_preempt_label_.is_linked()) { + __ Bind(&check_preempt_label_); ++ ++ StoreRegExpStackPointerToMemory(backtrack_stackpointer(), x10); ++ + SaveLinkRegister(); + // The cached registers need to be retained. + __ PushCPURegList(cached_registers); +@@ -1049,26 +1095,30 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { + __ Cbnz(w0, &return_w0); + // Reset the cached registers. + __ PopCPURegList(cached_registers); ++ ++ LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); ++ + RestoreLinkRegister(); + __ Ret(); + } + + if (stack_overflow_label_.is_linked()) { + __ Bind(&stack_overflow_label_); ++ ++ StoreRegExpStackPointerToMemory(backtrack_stackpointer(), x10); ++ + SaveLinkRegister(); + // The cached registers need to be retained. + __ PushCPURegList(cached_registers); +- // Call GrowStack(backtrack_stackpointer(), &stack_base) +- __ Mov(x2, ExternalReference::isolate_address(isolate())); +- __ Add(x1, frame_pointer(), kStackBase); +- __ Mov(x0, backtrack_stackpointer()); +- ExternalReference grow_stack = +- ExternalReference::re_grow_stack(isolate()); +- __ CallCFunction(grow_stack, 3); +- // If return nullptr, we have failed to grow the stack, and +- // must exit with a stack-overflow exception. +- // Returning from the regexp code restores the stack (sp <- fp) +- // so we don't need to drop the link register from it before exiting. ++ // Call GrowStack(isolate) ++ static constexpr int kNumArguments = 1; ++ __ Mov(x0, ExternalReference::isolate_address(isolate())); ++ __ CallCFunction(ExternalReference::re_grow_stack(isolate()), ++ kNumArguments); ++ // If return nullptr, we have failed to grow the stack, and must exit with ++ // a stack-overflow exception. Returning from the regexp code restores the ++ // stack (sp <- fp) so we don't need to drop the link register from it ++ // before exiting. + __ Cbz(w0, &exit_with_exception); + // Otherwise use return value as new stack pointer. + __ Mov(backtrack_stackpointer(), x0); +@@ -1192,14 +1242,29 @@ void RegExpMacroAssemblerARM64::ReadCurrentPositionFromRegister(int reg) { + } + } + ++void RegExpMacroAssemblerARM64::WriteStackPointerToRegister(int reg) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ Mov(x10, ref); ++ __ Ldr(x10, MemOperand(x10)); ++ __ Sub(x10, backtrack_stackpointer(), x10); ++ if (FLAG_debug_code) { ++ __ Cmp(x10, Operand(w10, SXTW)); ++ // The stack offset needs to fit in a W register. ++ __ Check(eq, AbortReason::kOffsetOutOfRange); ++ } ++ StoreRegister(reg, w10); ++} + + void RegExpMacroAssemblerARM64::ReadStackPointerFromRegister(int reg) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + Register read_from = GetRegister(reg, w10); +- __ Ldr(x11, MemOperand(frame_pointer(), kStackBase)); ++ __ Mov(x11, ref); ++ __ Ldr(x11, MemOperand(x11)); + __ Add(backtrack_stackpointer(), x11, Operand(read_from, SXTW)); + } + +- + void RegExpMacroAssemblerARM64::SetCurrentPositionFromEnd(int by) { + Label after_position; + __ Cmp(current_input_offset(), -by * char_size()); +@@ -1301,19 +1366,6 @@ void RegExpMacroAssemblerARM64::ClearRegisters(int reg_from, int reg_to) { + } + } + +- +-void RegExpMacroAssemblerARM64::WriteStackPointerToRegister(int reg) { +- __ Ldr(x10, MemOperand(frame_pointer(), kStackBase)); +- __ Sub(x10, backtrack_stackpointer(), x10); +- if (FLAG_debug_code) { +- __ Cmp(x10, Operand(w10, SXTW)); +- // The stack offset needs to fit in a W register. +- __ Check(eq, AbortReason::kOffsetOutOfRange); +- } +- StoreRegister(reg, w10); +-} +- +- + // Helper function for reading a value out of a stack frame. + template + static T& frame_entry(Address re_frame, int frame_offset) { +diff --git a/src/regexp/arm64/regexp-macro-assembler-arm64.h b/src/regexp/arm64/regexp-macro-assembler-arm64.h +index 80931e3ca42f7d85a3dea067ca203b252a0f78f0..204ee68dc868142693e9959170c71df3f72f97ce 100644 +--- a/src/regexp/arm64/regexp-macro-assembler-arm64.h ++++ b/src/regexp/arm64/regexp-macro-assembler-arm64.h +@@ -110,18 +110,28 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 + // Below the frame pointer. + // Register parameters stored by setup code. + static const int kDirectCall = -kSystemPointerSize; +- static const int kStackBase = kDirectCall - kSystemPointerSize; +- static const int kOutputSize = kStackBase - kSystemPointerSize; ++ static const int kStackHighEnd = kDirectCall - kSystemPointerSize; ++ static const int kOutputSize = kStackHighEnd - kSystemPointerSize; + static const int kInput = kOutputSize - kSystemPointerSize; + // When adding local variables remember to push space for them in + // the frame in GetCode. + static const int kSuccessCounter = kInput - kSystemPointerSize; + static const int kBacktrackCount = kSuccessCounter - kSystemPointerSize; ++ // Stores the initial value of the regexp stack pointer in a ++ // position-independent representation (in case the regexp stack grows and ++ // thus moves). ++ static const int kRegExpStackBasePointer = ++ kBacktrackCount - kSystemPointerSize; ++ // A padding slot to preserve alignment. ++ static const int kStackLocalPadding = ++ kRegExpStackBasePointer - kSystemPointerSize; ++ static constexpr int kNumberOfStackLocals = 4; ++ + // First position register address on the stack. Following positions are + // below it. A position is a 32 bit value. +- static const int kFirstRegisterOnStack = kBacktrackCount - kWRegSize; ++ static const int kFirstRegisterOnStack = kStackLocalPadding - kWRegSize; + // A capture is a 64 bit value holding two position. +- static const int kFirstCaptureOnStack = kBacktrackCount - kXRegSize; ++ static const int kFirstCaptureOnStack = kStackLocalPadding - kXRegSize; + + // Initial size of code buffer. + static const int kRegExpCodeSize = 1024; +@@ -152,43 +162,43 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 + + // Register holding the current input position as negative offset from + // the end of the string. +- Register current_input_offset() { return w21; } ++ static constexpr Register current_input_offset() { return w21; } + + // The register containing the current character after LoadCurrentCharacter. +- Register current_character() { return w22; } ++ static constexpr Register current_character() { return w22; } + + // Register holding address of the end of the input string. +- Register input_end() { return x25; } ++ static constexpr Register input_end() { return x25; } + + // Register holding address of the start of the input string. +- Register input_start() { return x26; } ++ static constexpr Register input_start() { return x26; } + + // Register holding the offset from the start of the string where we should + // start matching. +- Register start_offset() { return w27; } ++ static constexpr Register start_offset() { return w27; } + + // Pointer to the output array's first element. +- Register output_array() { return x28; } ++ static constexpr Register output_array() { return x28; } + + // Register holding the frame address. Local variables, parameters and + // regexp registers are addressed relative to this. +- Register frame_pointer() { return fp; } ++ static constexpr Register frame_pointer() { return fp; } + + // The register containing the backtrack stack top. Provides a meaningful + // name to the register. +- Register backtrack_stackpointer() { return x23; } ++ static constexpr Register backtrack_stackpointer() { return x23; } + + // Register holding pointer to the current code object. +- Register code_pointer() { return x20; } ++ static constexpr Register code_pointer() { return x20; } + + // Register holding the value used for clearing capture registers. +- Register string_start_minus_one() { return w24; } ++ static constexpr Register string_start_minus_one() { return w24; } + // The top 32 bit of this register is used to store this value + // twice. This is used for clearing more than one register at a time. +- Register twice_non_position_value() { return x24; } ++ static constexpr Register twice_non_position_value() { return x24; } + + // Byte size of chars in the string to match (decided by the Mode argument) +- int char_size() { return static_cast(mode_); } ++ int char_size() const { return static_cast(mode_); } + + // Equivalent to a conditional branch to the label, unless the label + // is nullptr, in which case it is a conditional Backtrack. +@@ -254,19 +264,25 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 + // This assumes that the state of the register is not STACKED. + inline Register GetCachedRegister(int register_index); + ++ void LoadRegExpStackPointerFromMemory(Register dst); ++ void StoreRegExpStackPointerToMemory(Register src, Register scratch); ++ void PushRegExpBasePointer(Register scratch1, Register scratch2); ++ void PopRegExpBasePointer(Register scratch1, Register scratch2); ++ + Isolate* isolate() const { return masm_->isolate(); } + +- MacroAssembler* masm_; ++ MacroAssembler* const masm_; ++ const NoRootArrayScope no_root_array_scope_; + + // Which mode to generate code for (LATIN1 or UC16). +- Mode mode_; ++ const Mode mode_; + + // One greater than maximal register index actually used. + int num_registers_; + + // Number of registers to output at the end (the saved registers + // are always 0..num_saved_registers_-1) +- int num_saved_registers_; ++ const int num_saved_registers_; + + // Labels used internally. + Label entry_label_; +diff --git a/src/regexp/ia32/regexp-macro-assembler-ia32.cc b/src/regexp/ia32/regexp-macro-assembler-ia32.cc +index 6af1d02eed36af46a7e0d819d006361f51411ba6..51d63b2531e2bc85fb115de23d7b6a6f40b36f11 100644 +--- a/src/regexp/ia32/regexp-macro-assembler-ia32.cc ++++ b/src/regexp/ia32/regexp-macro-assembler-ia32.cc +@@ -90,6 +90,7 @@ RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(Isolate* isolate, Zone* zone, + : NativeRegExpMacroAssembler(isolate, zone), + masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes, + NewAssemblerBuffer(kRegExpCodeSize))), ++ no_root_array_scope_(masm_), + mode_(mode), + num_registers_(registers_to_save), + num_saved_registers_(registers_to_save), +@@ -98,9 +99,6 @@ RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(Isolate* isolate, Zone* zone, + success_label_(), + backtrack_label_(), + exit_label_() { +- // Irregexp code clobbers ebx and spills/restores it at all boundaries. +- masm_->set_root_array_available(false); +- + DCHECK_EQ(0, registers_to_save % 2); + __ jmp(&entry_label_); // We'll write the entry code later. + __ bind(&start_label_); // And then continue from here. +@@ -655,6 +653,38 @@ void RegExpMacroAssemblerIA32::Fail() { + __ jmp(&exit_label_); + } + ++void RegExpMacroAssemblerIA32::LoadRegExpStackPointerFromMemory(Register dst) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); ++ __ mov(dst, __ ExternalReferenceAsOperand(ref, dst)); ++} ++ ++void RegExpMacroAssemblerIA32::StoreRegExpStackPointerToMemory( ++ Register src, Register scratch) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); ++ __ mov(__ ExternalReferenceAsOperand(ref, scratch), src); ++} ++ ++void RegExpMacroAssemblerIA32::PushRegExpBasePointer(Register scratch1, ++ Register scratch2) { ++ LoadRegExpStackPointerFromMemory(scratch1); ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ mov(scratch2, __ ExternalReferenceAsOperand(ref, scratch2)); ++ __ sub(scratch1, scratch2); ++ __ mov(Operand(ebp, kRegExpStackBasePointer), scratch1); ++} ++ ++void RegExpMacroAssemblerIA32::PopRegExpBasePointer(Register scratch1, ++ Register scratch2) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ mov(scratch1, Operand(ebp, kRegExpStackBasePointer)); ++ __ mov(scratch2, __ ExternalReferenceAsOperand(ref, scratch2)); ++ __ add(scratch1, scratch2); ++ StoreRegExpStackPointerToMemory(scratch1, scratch2); ++} + + Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { + Label return_eax; +@@ -676,14 +706,23 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { + __ push(esi); + __ push(edi); + __ push(ebx); // Callee-save on MacOS. ++ STATIC_ASSERT(kLastCalleeSaveRegister == kBackup_ebx); + +- STATIC_ASSERT(kSuccessfulCaptures == kBackup_ebx - kSystemPointerSize); ++ STATIC_ASSERT(kSuccessfulCaptures == ++ kLastCalleeSaveRegister - kSystemPointerSize); + __ push(Immediate(0)); // Number of successful matches in a global regexp. + STATIC_ASSERT(kStringStartMinusOne == + kSuccessfulCaptures - kSystemPointerSize); + __ push(Immediate(0)); // Make room for "string start - 1" constant. + STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize); + __ push(Immediate(0)); // The backtrack counter. ++ STATIC_ASSERT(kRegExpStackBasePointer == ++ kBacktrackCount - kSystemPointerSize); ++ __ push(Immediate(0)); // The regexp stack base ptr. ++ ++ // Store the regexp base pointer - we'll later restore it / write it to ++ // memory when returning from this irregexp code object. ++ PushRegExpBasePointer(ecx, eax); + + // Check if we have space on the stack for registers. + Label stack_limit_hit; +@@ -769,7 +808,7 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { + } + + // Initialize backtrack stack pointer. +- __ mov(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); ++ LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); + + __ jmp(&start_label_); + +@@ -855,8 +894,12 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { + } + + __ bind(&return_eax); ++ // Restore the original regexp stack pointer value (effectively, pop the ++ // stored base pointer). ++ PopRegExpBasePointer(ecx, ebx); ++ + // Skip esp past regexp registers. +- __ lea(esp, Operand(ebp, kBackup_ebx)); ++ __ lea(esp, Operand(ebp, kLastCalleeSaveRegister)); + // Restore callee-save registers. + __ pop(ebx); + __ pop(edi); +@@ -877,7 +920,8 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { + if (check_preempt_label_.is_linked()) { + SafeCallTarget(&check_preempt_label_); + +- __ push(backtrack_stackpointer()); ++ StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi); ++ + __ push(edi); + + CallCheckStackGuardState(ebx); +@@ -887,7 +931,9 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { + __ j(not_zero, &return_eax); + + __ pop(edi); +- __ pop(backtrack_stackpointer()); ++ ++ LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); ++ + // String might have moved: Reload esi from frame. + __ mov(esi, Operand(ebp, kInputEnd)); + SafeReturn(); +@@ -898,21 +944,19 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { + SafeCallTarget(&stack_overflow_label_); + // Reached if the backtrack-stack limit has been hit. + +- // Save registers before calling C function ++ // Save registers before calling C function. + __ push(esi); + __ push(edi); + +- // Call GrowStack(backtrack_stackpointer()) +- static const int num_arguments = 3; +- __ PrepareCallCFunction(num_arguments, ebx); +- __ mov(Operand(esp, 2 * kSystemPointerSize), ++ StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi); ++ ++ // Call GrowStack(isolate). ++ static const int kNumArguments = 1; ++ __ PrepareCallCFunction(kNumArguments, ebx); ++ __ mov(Operand(esp, 0 * kSystemPointerSize), + Immediate(ExternalReference::isolate_address(isolate()))); +- __ lea(eax, Operand(ebp, kStackHighEnd)); +- __ mov(Operand(esp, 1 * kSystemPointerSize), eax); +- __ mov(Operand(esp, 0 * kSystemPointerSize), backtrack_stackpointer()); +- ExternalReference grow_stack = +- ExternalReference::re_grow_stack(isolate()); +- __ CallCFunction(grow_stack, num_arguments); ++ __ CallCFunction(ExternalReference::re_grow_stack(isolate()), ++ kNumArguments); + // If return nullptr, we have failed to grow the stack, and + // must exit with a stack-overflow exception. + __ or_(eax, eax); +@@ -1019,10 +1063,21 @@ void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) { + __ mov(edi, register_location(reg)); + } + ++void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) { ++ ExternalReference stack_top_address = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ mov(eax, __ ExternalReferenceAsOperand(stack_top_address, eax)); ++ __ sub(eax, backtrack_stackpointer()); ++ __ mov(register_location(reg), eax); ++} + + void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) { +- __ mov(backtrack_stackpointer(), register_location(reg)); +- __ add(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); ++ ExternalReference stack_top_address = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ mov(backtrack_stackpointer(), ++ __ ExternalReferenceAsOperand(stack_top_address, ++ backtrack_stackpointer())); ++ __ sub(backtrack_stackpointer(), register_location(reg)); + } + + void RegExpMacroAssemblerIA32::SetCurrentPositionFromEnd(int by) { +@@ -1069,14 +1124,6 @@ void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) { + } + } + +- +-void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) { +- __ mov(eax, backtrack_stackpointer()); +- __ sub(eax, Operand(ebp, kStackHighEnd)); +- __ mov(register_location(reg), eax); +-} +- +- + // Private methods: + + void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) { +diff --git a/src/regexp/ia32/regexp-macro-assembler-ia32.h b/src/regexp/ia32/regexp-macro-assembler-ia32.h +index 93fb2c9aba32ab48e335c41dd9dbe0bac94d73ed..861795da900d91111386e4f8e660f7f94ea46a33 100644 +--- a/src/regexp/ia32/regexp-macro-assembler-ia32.h ++++ b/src/regexp/ia32/regexp-macro-assembler-ia32.h +@@ -114,12 +114,20 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32 + static const int kBackup_esi = kFramePointer - kSystemPointerSize; + static const int kBackup_edi = kBackup_esi - kSystemPointerSize; + static const int kBackup_ebx = kBackup_edi - kSystemPointerSize; +- static const int kSuccessfulCaptures = kBackup_ebx - kSystemPointerSize; ++ static const int kLastCalleeSaveRegister = kBackup_ebx; ++ ++ static const int kSuccessfulCaptures = ++ kLastCalleeSaveRegister - kSystemPointerSize; + static const int kStringStartMinusOne = + kSuccessfulCaptures - kSystemPointerSize; + static const int kBacktrackCount = kStringStartMinusOne - kSystemPointerSize; ++ // Stores the initial value of the regexp stack pointer in a ++ // position-independent representation (in case the regexp stack grows and ++ // thus moves). ++ static const int kRegExpStackBasePointer = ++ kBacktrackCount - kSystemPointerSize; + // First register address. Following registers are below it on the stack. +- static const int kRegisterZero = kBacktrackCount - kSystemPointerSize; ++ static const int kRegisterZero = kRegExpStackBasePointer - kSystemPointerSize; + + // Initial size of code buffer. + static const int kRegExpCodeSize = 1024; +@@ -137,14 +145,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32 + Operand register_location(int register_index); + + // The register containing the current character after LoadCurrentCharacter. +- inline Register current_character() { return edx; } ++ static constexpr Register current_character() { return edx; } + + // The register containing the backtrack stack top. Provides a meaningful + // name to the register. +- inline Register backtrack_stackpointer() { return ecx; } ++ static constexpr Register backtrack_stackpointer() { return ecx; } + + // Byte size of chars in the string to match (decided by the Mode argument) +- inline int char_size() { return static_cast(mode_); } ++ inline int char_size() const { return static_cast(mode_); } + + // Equivalent to a conditional branch to the label, unless the label + // is nullptr, in which case it is a conditional Backtrack. +@@ -168,19 +176,25 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32 + // (ecx) and increments it by a word size. + inline void Pop(Register target); + ++ void LoadRegExpStackPointerFromMemory(Register dst); ++ void StoreRegExpStackPointerToMemory(Register src, Register scratch); ++ void PushRegExpBasePointer(Register scratch1, Register scratch2); ++ void PopRegExpBasePointer(Register scratch1, Register scratch2); ++ + Isolate* isolate() const { return masm_->isolate(); } + +- MacroAssembler* masm_; ++ MacroAssembler* const masm_; ++ const NoRootArrayScope no_root_array_scope_; + + // Which mode to generate code for (LATIN1 or UC16). +- Mode mode_; ++ const Mode mode_; + + // One greater than maximal register index actually used. + int num_registers_; + + // Number of registers to output at the end (the saved registers +- // are always 0..num_saved_registers_-1) +- int num_saved_registers_; ++ // are always 0..num_saved_registers_-1). ++ const int num_saved_registers_; + + // Labels used internally. + Label entry_label_; +diff --git a/src/regexp/regexp-macro-assembler.cc b/src/regexp/regexp-macro-assembler.cc +index 5457398f39ab4b36921738bb9c924127eb9dc104..27590fac36cea92f557dc0c149d9cbed6efef8b5 100644 +--- a/src/regexp/regexp-macro-assembler.cc ++++ b/src/regexp/regexp-macro-assembler.cc +@@ -302,7 +302,7 @@ int NativeRegExpMacroAssembler::Execute( + int* output, int output_size, Isolate* isolate, JSRegExp regexp) { + // Ensure that the minimum stack has been allocated. + RegExpStackScope stack_scope(isolate); +- Address stack_base = stack_scope.stack()->stack_base(); ++ Address stack_base = stack_scope.stack()->memory_top(); + + bool is_one_byte = String::IsOneByteRepresentationUnderneath(input); + Code code = FromCodeT(CodeT::cast(regexp.Code(is_one_byte))); +@@ -376,22 +376,23 @@ const byte NativeRegExpMacroAssembler::word_character_map[] = { + }; + // clang-format on + +-Address NativeRegExpMacroAssembler::GrowStack(Address stack_pointer, +- Address* stack_base, +- Isolate* isolate) { ++Address NativeRegExpMacroAssembler::GrowStack(Isolate* isolate) { ++ DisallowGarbageCollection no_gc; ++ + RegExpStack* regexp_stack = isolate->regexp_stack(); +- size_t size = regexp_stack->stack_capacity(); +- Address old_stack_base = regexp_stack->stack_base(); +- DCHECK(old_stack_base == *stack_base); +- DCHECK(stack_pointer <= old_stack_base); +- DCHECK(static_cast(old_stack_base - stack_pointer) <= size); +- Address new_stack_base = regexp_stack->EnsureCapacity(size * 2); +- if (new_stack_base == kNullAddress) { +- return kNullAddress; +- } +- *stack_base = new_stack_base; +- intptr_t stack_content_size = old_stack_base - stack_pointer; +- return new_stack_base - stack_content_size; ++ const size_t old_size = regexp_stack->memory_size(); ++ ++#ifdef DEBUG ++ const Address old_stack_top = regexp_stack->memory_top(); ++ const Address old_stack_pointer = regexp_stack->stack_pointer(); ++ CHECK_LE(old_stack_pointer, old_stack_top); ++ CHECK_LE(static_cast(old_stack_top - old_stack_pointer), old_size); ++#endif // DEBUG ++ ++ Address new_stack_base = regexp_stack->EnsureCapacity(old_size * 2); ++ if (new_stack_base == kNullAddress) return kNullAddress; ++ ++ return regexp_stack->stack_pointer(); + } + + } // namespace internal +diff --git a/src/regexp/regexp-macro-assembler.h b/src/regexp/regexp-macro-assembler.h +index 31e8b1a37039ff462f32904e2234d9678a6a05bc..71ddde8706fcbf1ee7502380467fd98ffe8d856e 100644 +--- a/src/regexp/regexp-macro-assembler.h ++++ b/src/regexp/regexp-macro-assembler.h +@@ -280,13 +280,11 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler { + int* offsets_vector, int offsets_vector_length, + int previous_index, Isolate* isolate); + +- // Called from RegExp if the backtrack stack limit is hit. +- // Tries to expand the stack. Returns the new stack-pointer if +- // successful, and updates the stack_top address, or returns 0 if unable +- // to grow the stack. ++ // Called from RegExp if the backtrack stack limit is hit. Tries to expand ++ // the stack. Returns the new stack-pointer if successful, or returns 0 if ++ // unable to grow the stack. + // This function must not trigger a garbage collection. +- static Address GrowStack(Address stack_pointer, Address* stack_top, +- Isolate* isolate); ++ static Address GrowStack(Isolate* isolate); + + static int CheckStackGuardState(Isolate* isolate, int start_index, + RegExp::CallOrigin call_origin, +diff --git a/src/regexp/regexp-stack.cc b/src/regexp/regexp-stack.cc +index 6d73b7c03d63f9358f54453aba3c52ec5da29c3b..9c403eed089c890df0098875763da62bce15fd64 100644 +--- a/src/regexp/regexp-stack.cc ++++ b/src/regexp/regexp-stack.cc +@@ -11,23 +11,17 @@ namespace v8 { + namespace internal { + + RegExpStackScope::RegExpStackScope(Isolate* isolate) +- : regexp_stack_(isolate->regexp_stack()) { ++ : regexp_stack_(isolate->regexp_stack()), ++ old_sp_top_delta_(regexp_stack_->sp_top_delta()) { + DCHECK(regexp_stack_->IsValid()); +- // Irregexp is not reentrant in several ways; in particular, the +- // RegExpStackScope is not reentrant since the destructor frees allocated +- // memory. Protect against reentrancy here. +- CHECK(!regexp_stack_->is_in_use()); +- regexp_stack_->set_is_in_use(true); + } + +- + RegExpStackScope::~RegExpStackScope() { +- // Reset the buffer if it has grown. +- regexp_stack_->Reset(); +- DCHECK(!regexp_stack_->is_in_use()); ++ CHECK_EQ(old_sp_top_delta_, regexp_stack_->sp_top_delta()); ++ regexp_stack_->ResetIfEmpty(); + } + +-RegExpStack::RegExpStack() : thread_local_(this), isolate_(nullptr) {} ++RegExpStack::RegExpStack() : thread_local_(this) {} + + RegExpStack::~RegExpStack() { thread_local_.FreeAndInvalidate(); } + +@@ -52,18 +46,16 @@ char* RegExpStack::RestoreStack(char* from) { + return from + kThreadLocalSize; + } + +-void RegExpStack::Reset() { thread_local_.ResetToStaticStack(this); } +- + void RegExpStack::ThreadLocal::ResetToStaticStack(RegExpStack* regexp_stack) { + if (owns_memory_) DeleteArray(memory_); + + memory_ = regexp_stack->static_stack_; + memory_top_ = regexp_stack->static_stack_ + kStaticStackSize; + memory_size_ = kStaticStackSize; ++ stack_pointer_ = memory_top_; + limit_ = reinterpret_cast
(regexp_stack->static_stack_) + + kStackLimitSlack * kSystemPointerSize; + owns_memory_ = false; +- is_in_use_ = false; + } + + void RegExpStack::ThreadLocal::FreeAndInvalidate() { +@@ -74,6 +66,7 @@ void RegExpStack::ThreadLocal::FreeAndInvalidate() { + memory_ = nullptr; + memory_top_ = nullptr; + memory_size_ = 0; ++ stack_pointer_ = nullptr; + limit_ = kMemoryTop; + } + +@@ -88,9 +81,11 @@ Address RegExpStack::EnsureCapacity(size_t size) { + thread_local_.memory_, thread_local_.memory_size_); + if (thread_local_.owns_memory_) DeleteArray(thread_local_.memory_); + } ++ ptrdiff_t delta = sp_top_delta(); + thread_local_.memory_ = new_memory; + thread_local_.memory_top_ = new_memory + size; + thread_local_.memory_size_ = size; ++ thread_local_.stack_pointer_ = thread_local_.memory_top_ + delta; + thread_local_.limit_ = reinterpret_cast
(new_memory) + + kStackLimitSlack * kSystemPointerSize; + thread_local_.owns_memory_ = true; +diff --git a/src/regexp/regexp-stack.h b/src/regexp/regexp-stack.h +index adca683ff890c82d7cfdf9e10c7a5d7e78d2d650..d52ca3e1d079d8953a753e2db1e835f214b980f3 100644 +--- a/src/regexp/regexp-stack.h ++++ b/src/regexp/regexp-stack.h +@@ -16,10 +16,7 @@ class RegExpStack; + + // Maintains a per-v8thread stack area that can be used by irregexp + // implementation for its backtracking stack. +-// Since there is only one stack area, the Irregexp implementation is not +-// re-entrant. I.e., no regular expressions may be executed in the same thread +-// during a preempted Irregexp execution. +-class V8_NODISCARD RegExpStackScope { ++class V8_NODISCARD RegExpStackScope final { + public: + // Create and delete an instance to control the life-time of a growing stack. + +@@ -32,46 +29,45 @@ class V8_NODISCARD RegExpStackScope { + RegExpStack* stack() const { return regexp_stack_; } + + private: +- RegExpStack* regexp_stack_; ++ RegExpStack* const regexp_stack_; ++ const ptrdiff_t old_sp_top_delta_; + }; + +-class RegExpStack { ++class RegExpStack final { + public: + RegExpStack(); + ~RegExpStack(); + RegExpStack(const RegExpStack&) = delete; + RegExpStack& operator=(const RegExpStack&) = delete; + +- // Number of allocated locations on the stack below the limit. +- // No sequence of pushes must be longer that this without doing a stack-limit +- // check. ++ // Number of allocated locations on the stack below the limit. No sequence of ++ // pushes must be longer than this without doing a stack-limit check. + static constexpr int kStackLimitSlack = 32; + +- // Gives the top of the memory used as stack. +- Address stack_base() { ++ Address memory_top() const { + DCHECK_NE(0, thread_local_.memory_size_); + DCHECK_EQ(thread_local_.memory_top_, + thread_local_.memory_ + thread_local_.memory_size_); + return reinterpret_cast
(thread_local_.memory_top_); + } + +- // The total size of the memory allocated for the stack. +- size_t stack_capacity() { return thread_local_.memory_size_; } ++ Address stack_pointer() const { ++ return reinterpret_cast
(thread_local_.stack_pointer_); ++ } ++ ++ size_t memory_size() const { return thread_local_.memory_size_; } + + // If the stack pointer gets below the limit, we should react and + // either grow the stack or report an out-of-stack exception. + // There is only a limited number of locations below the stack limit, + // so users of the stack should check the stack limit during any + // sequence of pushes longer that this. +- Address* limit_address_address() { return &(thread_local_.limit_); } ++ Address* limit_address_address() { return &thread_local_.limit_; } + + // Ensures that there is a memory area with at least the specified size. + // If passing zero, the default/minimum size buffer is allocated. + Address EnsureCapacity(size_t size); + +- bool is_in_use() const { return thread_local_.is_in_use_; } +- void set_is_in_use(bool v) { thread_local_.is_in_use_ = v; } +- + // Thread local archiving. + static constexpr int ArchiveSpacePerThread() { + return static_cast(kThreadLocalSize); +@@ -103,44 +99,59 @@ class RegExpStack { + + STATIC_ASSERT(kStaticStackSize <= kMaximumStackSize); + +- // Structure holding the allocated memory, size and limit. ++ // Structure holding the allocated memory, size and limit. Thread switching ++ // archives and restores this struct. + struct ThreadLocal { + explicit ThreadLocal(RegExpStack* regexp_stack) { + ResetToStaticStack(regexp_stack); + } + +- // If memory_size_ > 0 then memory_ and memory_top_ must be non-nullptr +- // and memory_top_ = memory_ + memory_size_ ++ // If memory_size_ > 0 then ++ // - memory_, memory_top_, stack_pointer_ must be non-nullptr ++ // - memory_top_ = memory_ + memory_size_ ++ // - memory_ <= stack_pointer_ <= memory_top_ + byte* memory_ = nullptr; + byte* memory_top_ = nullptr; + size_t memory_size_ = 0; ++ byte* stack_pointer_ = nullptr; + Address limit_ = kNullAddress; + bool owns_memory_ = false; // Whether memory_ is owned and must be freed. +- bool is_in_use_ = false; // To guard against reentrancy. + + void ResetToStaticStack(RegExpStack* regexp_stack); ++ void ResetToStaticStackIfEmpty(RegExpStack* regexp_stack) { ++ if (stack_pointer_ == memory_top_) ResetToStaticStack(regexp_stack); ++ } + void FreeAndInvalidate(); + }; + static constexpr size_t kThreadLocalSize = sizeof(ThreadLocal); + +- // Address of top of memory used as stack. + Address memory_top_address_address() { + return reinterpret_cast
(&thread_local_.memory_top_); + } + +- // Resets the buffer if it has grown beyond the default/minimum size. +- // After this, the buffer is either the default size, or it is empty, so +- // you have to call EnsureCapacity before using it again. +- void Reset(); ++ Address stack_pointer_address() { ++ return reinterpret_cast
(&thread_local_.stack_pointer_); ++ } ++ ++ // A position-independent representation of the stack pointer. ++ ptrdiff_t sp_top_delta() const { ++ ptrdiff_t result = ++ reinterpret_cast(thread_local_.stack_pointer_) - ++ reinterpret_cast(thread_local_.memory_top_); ++ DCHECK_LE(result, 0); ++ return result; ++ } ++ ++ // Resets the buffer if it has grown beyond the default/minimum size and is ++ // empty. ++ void ResetIfEmpty() { thread_local_.ResetToStaticStackIfEmpty(this); } + + // Whether the ThreadLocal storage has been invalidated. + bool IsValid() const { return thread_local_.memory_ != nullptr; } + + ThreadLocal thread_local_; +- Isolate* isolate_; + + friend class ExternalReference; +- friend class Isolate; + friend class RegExpStackScope; + }; + +diff --git a/src/regexp/x64/regexp-macro-assembler-x64.cc b/src/regexp/x64/regexp-macro-assembler-x64.cc +index 6f0cb53e8f52e4cad5997993b7fb00f2d8b8127a..abcbed18aaa9bdc4a497962714bffde74d581173 100644 +--- a/src/regexp/x64/regexp-macro-assembler-x64.cc ++++ b/src/regexp/x64/regexp-macro-assembler-x64.cc +@@ -6,13 +6,13 @@ + + #include "src/regexp/x64/regexp-macro-assembler-x64.h" + ++#include "src/codegen/code-desc.h" + #include "src/codegen/macro-assembler.h" + #include "src/heap/factory.h" + #include "src/logging/log.h" +-#include "src/objects/objects-inl.h" ++#include "src/objects/code-inl.h" + #include "src/regexp/regexp-macro-assembler.h" + #include "src/regexp/regexp-stack.h" +-#include "src/strings/unicode.h" + + namespace v8 { + namespace internal { +@@ -664,31 +664,64 @@ void RegExpMacroAssemblerX64::Fail() { + __ jmp(&exit_label_); + } + ++void RegExpMacroAssemblerX64::LoadRegExpStackPointerFromMemory(Register dst) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); ++ __ movq(dst, __ ExternalReferenceAsOperand(ref, dst)); ++} ++ ++void RegExpMacroAssemblerX64::StoreRegExpStackPointerToMemory( ++ Register src, Register scratch) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); ++ __ movq(__ ExternalReferenceAsOperand(ref, scratch), src); ++} ++ ++void RegExpMacroAssemblerX64::PushRegExpBasePointer(Register scratch1, ++ Register scratch2) { ++ LoadRegExpStackPointerFromMemory(scratch1); ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ movq(scratch2, __ ExternalReferenceAsOperand(ref, scratch2)); ++ __ subq(scratch1, scratch2); ++ __ movq(Operand(rbp, kRegExpStackBasePointer), scratch1); ++} ++ ++void RegExpMacroAssemblerX64::PopRegExpBasePointer(Register scratch1, ++ Register scratch2) { ++ ExternalReference ref = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ movq(scratch1, Operand(rbp, kRegExpStackBasePointer)); ++ __ movq(scratch2, __ ExternalReferenceAsOperand(ref, scratch2)); ++ __ addq(scratch1, scratch2); ++ StoreRegExpStackPointerToMemory(scratch1, scratch2); ++} + + Handle RegExpMacroAssemblerX64::GetCode(Handle source) { + Label return_rax; +- // Finalize code - write the entry point code now we know how many +- // registers we need. +- // Entry code: ++ // Finalize code - write the entry point code now we know how many registers ++ // we need. + __ bind(&entry_label_); + +- // Tell the system that we have a stack frame. Because the type is MANUAL, no +- // is generated. ++ // Tell the system that we have a stack frame. Because the type is MANUAL, no ++ // physical frame is generated. + FrameScope scope(&masm_, StackFrame::MANUAL); + + // Actually emit code to start a new stack frame. + __ pushq(rbp); + __ movq(rbp, rsp); ++ + // Save parameters and callee-save registers. Order here should correspond + // to order of kBackup_ebx etc. + #ifdef V8_TARGET_OS_WIN + // MSVC passes arguments in rcx, rdx, r8, r9, with backing stack slots. +- // Store register parameters in pre-allocated stack slots, +- __ movq(Operand(rbp, kInputString), rcx); +- __ movq(Operand(rbp, kStartIndex), rdx); // Passed as int32 in edx. +- __ movq(Operand(rbp, kInputStart), r8); +- __ movq(Operand(rbp, kInputEnd), r9); +- // Callee-save on Win64. ++ // Store register parameters in pre-allocated stack slots. ++ __ movq(Operand(rbp, kInputString), arg_reg_1); ++ __ movq(Operand(rbp, kStartIndex), arg_reg_2); // Passed as int32 in edx. ++ __ movq(Operand(rbp, kInputStart), arg_reg_3); ++ __ movq(Operand(rbp, kInputEnd), arg_reg_4); ++ ++ STATIC_ASSERT(kNumCalleeSaveRegisters == 3); + __ pushq(rsi); + __ pushq(rdi); + __ pushq(rbx); +@@ -701,14 +734,15 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { + DCHECK_EQ(kInputEnd, -4 * kSystemPointerSize); + DCHECK_EQ(kRegisterOutput, -5 * kSystemPointerSize); + DCHECK_EQ(kNumOutputRegisters, -6 * kSystemPointerSize); +- __ pushq(rdi); +- __ pushq(rsi); +- __ pushq(rdx); +- __ pushq(rcx); ++ __ pushq(arg_reg_1); ++ __ pushq(arg_reg_2); ++ __ pushq(arg_reg_3); ++ __ pushq(arg_reg_4); + __ pushq(r8); + __ pushq(r9); + +- __ pushq(rbx); // Callee-save ++ STATIC_ASSERT(kNumCalleeSaveRegisters == 1); ++ __ pushq(rbx); + #endif + + STATIC_ASSERT(kSuccessfulCaptures == +@@ -719,6 +753,13 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { + __ Push(Immediate(0)); // Make room for "string start - 1" constant. + STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize); + __ Push(Immediate(0)); // The backtrack counter. ++ STATIC_ASSERT(kRegExpStackBasePointer == ++ kBacktrackCount - kSystemPointerSize); ++ __ Push(Immediate(0)); // The regexp stack base ptr. ++ ++ // Store the regexp base pointer - we'll later restore it / write it to ++ // memory when returning from this irregexp code object. ++ PushRegExpBasePointer(rcx, kScratchRegister); + + // Check if we have space on the stack for registers. + Label stack_limit_hit; +@@ -808,7 +849,9 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { + } + + // Initialize backtrack stack pointer. +- __ movq(backtrack_stackpointer(), Operand(rbp, kStackHighEnd)); ++ // TODO(jgruber): Remove the kStackHighEnd parameter (and others like ++ // kIsolate). ++ LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); + + __ jmp(&start_label_); + +@@ -894,19 +937,26 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { + } + + __ bind(&return_rax); ++ // Restore the original regexp stack pointer value (effectively, pop the ++ // stored base pointer). ++ PopRegExpBasePointer(rcx, kScratchRegister); ++ + #ifdef V8_TARGET_OS_WIN + // Restore callee save registers. + __ leaq(rsp, Operand(rbp, kLastCalleeSaveRegister)); ++ STATIC_ASSERT(kNumCalleeSaveRegisters == 3); + __ popq(rbx); + __ popq(rdi); + __ popq(rsi); + // Stack now at rbp. + #else + // Restore callee save register. ++ STATIC_ASSERT(kNumCalleeSaveRegisters == 1); + __ movq(rbx, Operand(rbp, kBackup_rbx)); + // Skip rsp to rbp. + __ movq(rsp, rbp); + #endif ++ + // Exit function frame, restore previous one. + __ popq(rbp); + __ ret(0); +@@ -923,9 +973,10 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { + if (check_preempt_label_.is_linked()) { + SafeCallTarget(&check_preempt_label_); + +- __ pushq(backtrack_stackpointer()); + __ pushq(rdi); + ++ StoreRegExpStackPointerToMemory(backtrack_stackpointer(), kScratchRegister); ++ + CallCheckStackGuardState(); + __ testq(rax, rax); + // If returning non-zero, we should end execution with the given +@@ -935,7 +986,9 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { + // Restore registers. + __ Move(code_object_pointer(), masm_.CodeObject()); + __ popq(rdi); +- __ popq(backtrack_stackpointer()); ++ ++ LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); ++ + // String might have moved: Reload esi from frame. + __ movq(rsi, Operand(rbp, kInputEnd)); + SafeReturn(); +@@ -953,25 +1006,19 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { + __ pushq(rdi); + #endif + +- // Call GrowStack(backtrack_stackpointer()) +- static const int num_arguments = 3; +- __ PrepareCallCFunction(num_arguments); +-#ifdef V8_TARGET_OS_WIN +- // Microsoft passes parameters in rcx, rdx, r8. +- // First argument, backtrack stackpointer, is already in rcx. +- __ leaq(rdx, Operand(rbp, kStackHighEnd)); // Second argument +- __ LoadAddress(r8, ExternalReference::isolate_address(isolate())); +-#else +- // AMD64 ABI passes parameters in rdi, rsi, rdx. +- __ movq(rdi, backtrack_stackpointer()); // First argument. +- __ leaq(rsi, Operand(rbp, kStackHighEnd)); // Second argument. +- __ LoadAddress(rdx, ExternalReference::isolate_address(isolate())); +-#endif ++ // Call GrowStack(isolate). ++ ++ StoreRegExpStackPointerToMemory(backtrack_stackpointer(), kScratchRegister); ++ ++ static constexpr int kNumArguments = 1; ++ __ PrepareCallCFunction(kNumArguments); ++ __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate())); ++ + ExternalReference grow_stack = + ExternalReference::re_grow_stack(isolate()); +- __ CallCFunction(grow_stack, num_arguments); +- // If return nullptr, we have failed to grow the stack, and +- // must exit with a stack-overflow exception. ++ __ CallCFunction(grow_stack, kNumArguments); ++ // If nullptr is returned, we have failed to grow the stack, and must exit ++ // with a stack-overflow exception. + __ testq(rax, rax); + __ j(equal, &exit_with_exception); + // Otherwise use return value as new stack pointer. +@@ -1085,13 +1132,25 @@ void RegExpMacroAssemblerX64::ReadPositionFromRegister(Register dst, int reg) { + __ movq(dst, register_location(reg)); + } + ++// Preserves a position-independent representation of the stack pointer in reg: ++// reg = top - sp. ++void RegExpMacroAssemblerX64::WriteStackPointerToRegister(int reg) { ++ ExternalReference stack_top_address = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ movq(rax, __ ExternalReferenceAsOperand(stack_top_address, rax)); ++ __ subq(rax, backtrack_stackpointer()); ++ __ movq(register_location(reg), rax); ++} + + void RegExpMacroAssemblerX64::ReadStackPointerFromRegister(int reg) { +- __ movq(backtrack_stackpointer(), register_location(reg)); +- __ addq(backtrack_stackpointer(), Operand(rbp, kStackHighEnd)); ++ ExternalReference stack_top_address = ++ ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); ++ __ movq(backtrack_stackpointer(), ++ __ ExternalReferenceAsOperand(stack_top_address, ++ backtrack_stackpointer())); ++ __ subq(backtrack_stackpointer(), register_location(reg)); + } + +- + void RegExpMacroAssemblerX64::SetCurrentPositionFromEnd(int by) { + Label after_position; + __ cmpq(rdi, Immediate(-by * char_size())); +@@ -1136,14 +1195,6 @@ void RegExpMacroAssemblerX64::ClearRegisters(int reg_from, int reg_to) { + } + } + +- +-void RegExpMacroAssemblerX64::WriteStackPointerToRegister(int reg) { +- __ movq(rax, backtrack_stackpointer()); +- __ subq(rax, Operand(rbp, kStackHighEnd)); +- __ movq(register_location(reg), rax); +-} +- +- + // Private methods: + + void RegExpMacroAssemblerX64::CallCheckStackGuardState() { +diff --git a/src/regexp/x64/regexp-macro-assembler-x64.h b/src/regexp/x64/regexp-macro-assembler-x64.h +index c3a3cb90f2a9d865057af80801e2a95bbb873140..74a3c95b06c771078ab03e6787e5912315421bb2 100644 +--- a/src/regexp/x64/regexp-macro-assembler-x64.h ++++ b/src/regexp/x64/regexp-macro-assembler-x64.h +@@ -5,9 +5,7 @@ + #ifndef V8_REGEXP_X64_REGEXP_MACRO_ASSEMBLER_X64_H_ + #define V8_REGEXP_X64_REGEXP_MACRO_ASSEMBLER_X64_H_ + +-#include "src/base/strings.h" + #include "src/codegen/macro-assembler.h" +-#include "src/codegen/x64/assembler-x64.h" + #include "src/regexp/regexp-macro-assembler.h" + #include "src/zone/zone-chunk-list.h" + +@@ -133,18 +131,17 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 + static const int kIsolate = kDirectCall + kSystemPointerSize; + #endif + ++ // We push callee-save registers that we use after the frame pointer (and ++ // after the parameters). + #ifdef V8_TARGET_OS_WIN +- // Microsoft calling convention has three callee-saved registers +- // (that we are using). We push these after the frame pointer. + static const int kBackup_rsi = kFramePointer - kSystemPointerSize; + static const int kBackup_rdi = kBackup_rsi - kSystemPointerSize; + static const int kBackup_rbx = kBackup_rdi - kSystemPointerSize; ++ static const int kNumCalleeSaveRegisters = 3; + static const int kLastCalleeSaveRegister = kBackup_rbx; + #else +- // AMD64 Calling Convention has only one callee-save register that +- // we use. We push this after the frame pointer (and after the +- // parameters). + static const int kBackup_rbx = kNumOutputRegisters - kSystemPointerSize; ++ static const int kNumCalleeSaveRegisters = 1; + static const int kLastCalleeSaveRegister = kBackup_rbx; + #endif + +@@ -155,9 +152,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 + static const int kStringStartMinusOne = + kSuccessfulCaptures - kSystemPointerSize; + static const int kBacktrackCount = kStringStartMinusOne - kSystemPointerSize; ++ // Stores the initial value of the regexp stack pointer in a ++ // position-independent representation (in case the regexp stack grows and ++ // thus moves). ++ static const int kRegExpStackBasePointer = ++ kBacktrackCount - kSystemPointerSize; + + // First register address. Following registers are below it on the stack. +- static const int kRegisterZero = kBacktrackCount - kSystemPointerSize; ++ static const int kRegisterZero = kRegExpStackBasePointer - kSystemPointerSize; + + // Initial size of code buffer. + static const int kRegExpCodeSize = 1024; +@@ -175,14 +177,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 + Operand register_location(int register_index); + + // The register containing the current character after LoadCurrentCharacter. +- inline Register current_character() { return rdx; } ++ static constexpr Register current_character() { return rdx; } + + // The register containing the backtrack stack top. Provides a meaningful + // name to the register. +- inline Register backtrack_stackpointer() { return rcx; } ++ static constexpr Register backtrack_stackpointer() { return rcx; } + + // The registers containing a self pointer to this code's Code object. +- inline Register code_object_pointer() { return r8; } ++ static constexpr Register code_object_pointer() { return r8; } + + // Byte size of chars in the string to match (decided by the Mode argument) + inline int char_size() { return static_cast(mode_); } +@@ -224,24 +226,36 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 + // Increments the stack pointer (rcx) by a word size. + inline void Drop(); + ++ void LoadRegExpStackPointerFromMemory(Register dst); ++ void StoreRegExpStackPointerToMemory(Register src, Register scratch); ++ void PushRegExpBasePointer(Register scratch1, Register scratch2); ++ void PopRegExpBasePointer(Register scratch1, Register scratch2); ++ + inline void ReadPositionFromRegister(Register dst, int reg); + + Isolate* isolate() const { return masm_.isolate(); } + + MacroAssembler masm_; +- NoRootArrayScope no_root_array_scope_; ++ ++ // On x64, there is no reason to keep the kRootRegister uninitialized; we ++ // could easily use it by 1. initializing it and 2. storing/restoring it ++ // as callee-save on entry/exit. ++ // But: on other platforms, specifically ia32, it would be tricky to enable ++ // the kRootRegister since it's currently used for other purposes. Thus, for ++ // consistency, we also keep it uninitialized here. ++ const NoRootArrayScope no_root_array_scope_; + + ZoneChunkList code_relative_fixup_positions_; + + // Which mode to generate code for (LATIN1 or UC16). +- Mode mode_; ++ const Mode mode_; + + // One greater than maximal register index actually used. + int num_registers_; + + // Number of registers to output at the end (the saved registers + // are always 0..num_saved_registers_-1) +- int num_saved_registers_; ++ const int num_saved_registers_; + + // Labels used internally. + Label entry_label_; +diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status +index 21afa5310647eb67f3fe3fc4f2e0721b4bb4e0f6..ea49ec9b4096e986ea5fe64b2b06177855d24f69 100644 +--- a/test/cctest/cctest.status ++++ b/test/cctest/cctest.status +@@ -136,9 +136,6 @@ + 'test-strings/Traverse': [PASS, HEAVY], + 'test-swiss-name-dictionary-csa/DeleteAtBoundaries': [PASS, HEAVY], + 'test-swiss-name-dictionary-csa/SameH2': [PASS, HEAVY], +- +- # TODO(v8:11382): Reenable once irregexp is reentrant. +- 'test-regexp/RegExpInterruptReentrantExecution': [FAIL], + }], # ALWAYS + + ############################################################################## diff --git a/patches/v8/regexp_remove_the_stack_parameter_from_regexp_matchers.patch b/patches/v8/regexp_remove_the_stack_parameter_from_regexp_matchers.patch new file mode 100644 index 0000000000000..398ad2d1a3709 --- /dev/null +++ b/patches/v8/regexp_remove_the_stack_parameter_from_regexp_matchers.patch @@ -0,0 +1,397 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jakob Gruber +Date: Wed, 22 Sep 2021 14:42:48 +0200 +Subject: Remove the `stack` parameter from regexp matchers + +The argument is no longer in use. + +Bug: v8:11382 +Change-Id: I7febc7fe7ef17ae462c700f0dba3ca1beade3021 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3173681 +Commit-Queue: Jakob Gruber +Reviewed-by: Patrick Thier +Cr-Commit-Position: refs/heads/main@{#77017} + +diff --git a/src/builtins/builtins-regexp-gen.cc b/src/builtins/builtins-regexp-gen.cc +index 535188c567ee3eafee2333a45e9d41c4cf3b4a0b..bb7512fbfa26678110a2a26a717975beddd369b8 100644 +--- a/src/builtins/builtins-regexp-gen.cc ++++ b/src/builtins/builtins-regexp-gen.cc +@@ -435,8 +435,6 @@ TNode RegExpBuiltinsAssembler::RegExpExecInternal( + // External constants. + TNode isolate_address = + ExternalConstant(ExternalReference::isolate_address(isolate())); +- TNode regexp_stack_memory_top_address = ExternalConstant( +- ExternalReference::address_of_regexp_stack_memory_top_address(isolate())); + TNode static_offsets_vector_address = ExternalConstant( + ExternalReference::address_of_static_offsets_vector(isolate())); + +@@ -605,26 +603,18 @@ TNode RegExpBuiltinsAssembler::RegExpExecInternal( + MachineType arg5_type = type_int32; + TNode arg5 = SmiToInt32(register_count); + +- // Argument 6: Start (high end) of backtracking stack memory area. This +- // argument is ignored in the interpreter. +- TNode stack_top = UncheckedCast( +- Load(MachineType::Pointer(), regexp_stack_memory_top_address)); ++ // Argument 6: Indicate that this is a direct call from JavaScript. ++ MachineType arg6_type = type_int32; ++ TNode arg6 = Int32Constant(RegExp::CallOrigin::kFromJs); + +- MachineType arg6_type = type_ptr; +- TNode arg6 = stack_top; ++ // Argument 7: Pass current isolate address. ++ MachineType arg7_type = type_ptr; ++ TNode arg7 = isolate_address; + +- // Argument 7: Indicate that this is a direct call from JavaScript. +- MachineType arg7_type = type_int32; +- TNode arg7 = Int32Constant(RegExp::CallOrigin::kFromJs); +- +- // Argument 8: Pass current isolate address. +- MachineType arg8_type = type_ptr; +- TNode arg8 = isolate_address; +- +- // Argument 9: Regular expression object. This argument is ignored in native ++ // Argument 8: Regular expression object. This argument is ignored in native + // irregexp code. +- MachineType arg9_type = type_tagged; +- TNode arg9 = regexp; ++ MachineType arg8_type = type_tagged; ++ TNode arg8 = regexp; + + // TODO(v8:11880): avoid roundtrips between cdc and code. + TNode code_entry = LoadCodeObjectEntry(code); +@@ -639,8 +629,7 @@ TNode RegExpBuiltinsAssembler::RegExpExecInternal( + std::make_pair(arg1_type, arg1), std::make_pair(arg2_type, arg2), + std::make_pair(arg3_type, arg3), std::make_pair(arg4_type, arg4), + std::make_pair(arg5_type, arg5), std::make_pair(arg6_type, arg6), +- std::make_pair(arg7_type, arg7), std::make_pair(arg8_type, arg8), +- std::make_pair(arg9_type, arg9))); ++ std::make_pair(arg7_type, arg7), std::make_pair(arg8_type, arg8))); + + // Check the result. + // We expect exactly one result since we force the called regexp to behave +diff --git a/src/regexp/arm/regexp-macro-assembler-arm.cc b/src/regexp/arm/regexp-macro-assembler-arm.cc +index 10766db4cf1d41ad0fee0754c6eaeebe46ace500..6e79ffd8adf8417c356bb36e1dbb2d0bfc290858 100644 +--- a/src/regexp/arm/regexp-macro-assembler-arm.cc ++++ b/src/regexp/arm/regexp-macro-assembler-arm.cc +@@ -38,14 +38,12 @@ namespace internal { + * Each call to a public method should retain this convention. + * + * The stack will have the following structure: +- * - fp[56] Address regexp (address of the JSRegExp object; unused in ++ * - fp[52] Address regexp (address of the JSRegExp object; unused in + * native code, passed to match signature of + * the interpreter) +- * - fp[52] Isolate* isolate (address of the current isolate) +- * - fp[48] direct_call (if 1, direct call from JavaScript code, ++ * - fp[48] Isolate* isolate (address of the current isolate) ++ * - fp[44] direct_call (if 1, direct call from JavaScript code, + * if 0, call through the runtime system). +- * - fp[44] stack_area_base (high end of the memory area to use as +- * backtracking stack). + * - fp[40] capture array size (may fit multiple sets of matches) + * - fp[36] int* capture_array (int[num_saved_registers_], for output). + * --- sp when called --- +@@ -82,7 +80,6 @@ namespace internal { + * Address end, + * int* capture_output_array, + * int num_capture_registers, +- * byte* stack_area_base, + * bool direct_call = false, + * Isolate* isolate, + * Address regexp); +diff --git a/src/regexp/arm/regexp-macro-assembler-arm.h b/src/regexp/arm/regexp-macro-assembler-arm.h +index a76f9dea70264d79d57ebd6c60b100bc9e0a499d..5aad6c1d85d574f4db307b6edcdda89ed25d5ca8 100644 +--- a/src/regexp/arm/regexp-macro-assembler-arm.h ++++ b/src/regexp/arm/regexp-macro-assembler-arm.h +@@ -91,15 +91,13 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM + static const int kFramePointer = 0; + + // Above the frame pointer - Stored registers and stack passed parameters. +- // Register 4..11. + static const int kStoredRegisters = kFramePointer; + // Return address (stored from link register, read into pc on return). + static const int kReturnAddress = kStoredRegisters + 8 * kPointerSize; + // Stack parameters placed by caller. + static const int kRegisterOutput = kReturnAddress + kPointerSize; + static const int kNumOutputRegisters = kRegisterOutput + kPointerSize; +- static const int kStackHighEnd = kNumOutputRegisters + kPointerSize; +- static const int kDirectCall = kStackHighEnd + kPointerSize; ++ static const int kDirectCall = kNumOutputRegisters + kPointerSize; + static const int kIsolate = kDirectCall + kPointerSize; + + // Below the frame pointer. +diff --git a/src/regexp/arm64/regexp-macro-assembler-arm64.cc b/src/regexp/arm64/regexp-macro-assembler-arm64.cc +index 911744b8b1c6d8a49100d88b53f8d9aedb943e2a..ca21530f99b618e5c46511d06ef93121a7e3c23e 100644 +--- a/src/regexp/arm64/regexp-macro-assembler-arm64.cc ++++ b/src/regexp/arm64/regexp-macro-assembler-arm64.cc +@@ -66,14 +66,12 @@ namespace internal { + * ^^^^^^^^^ fp ^^^^^^^^^ + * - fp[-8] direct_call 1 => Direct call from JavaScript code. + * 0 => Call through the runtime system. +- * - fp[-16] stack_base High end of the memory area to use as +- * the backtracking stack. +- * - fp[-24] output_size Output may fit multiple sets of matches. +- * - fp[-32] input Handle containing the input string. +- * - fp[-40] success_counter ++ * - fp[-16] output_size Output may fit multiple sets of matches. ++ * - fp[-24] input Handle containing the input string. ++ * - fp[-32] success_counter + * ^^^^^^^^^^^^^ From here and downwards we store 32 bit values ^^^^^^^^^^^^^ +- * - fp[-44] register N Capture registers initialized with +- * - fp[-48] register N + 1 non_position_value. ++ * - fp[-40] register N Capture registers initialized with ++ * - fp[-44] register N + 1 non_position_value. + * ... The first kNumCachedRegisters (N) registers + * ... are cached in x0 to x7. + * ... Only positions must be stored in the first +@@ -95,7 +93,6 @@ namespace internal { + * Address end, + * int* capture_output_array, + * int num_capture_registers, +- * byte* stack_area_base, + * bool direct_call = false, + * Isolate* isolate, + * Address regexp); +@@ -751,11 +748,10 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { + // x3: byte* input_end + // x4: int* output array + // x5: int output array size +- // x6: Address stack_base +- // x7: int direct_call +- +- // sp[8]: address of the current isolate +- // sp[0]: secondary link/return address used by native call ++ // x6: int direct_call ++ // x7: Isolate* isolate ++ // ++ // sp[0]: secondary link/return address used by native call + + // Tell the system that we have a stack frame. Because the type is MANUAL, no + // code is generated. +diff --git a/src/regexp/arm64/regexp-macro-assembler-arm64.h b/src/regexp/arm64/regexp-macro-assembler-arm64.h +index 204ee68dc868142693e9959170c71df3f72f97ce..f3869a72b631f9fb42b275d2edd8f3cfe1cfd8bb 100644 +--- a/src/regexp/arm64/regexp-macro-assembler-arm64.h ++++ b/src/regexp/arm64/regexp-macro-assembler-arm64.h +@@ -102,16 +102,12 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 + // Callee-saved registers (x19-x28). + static const int kNumCalleeSavedRegisters = 10; + static const int kCalleeSavedRegisters = kReturnAddress + kSystemPointerSize; +- // Stack parameter placed by caller. +- // It is placed above the FP, LR and the callee-saved registers. +- static const int kIsolate = +- kCalleeSavedRegisters + kNumCalleeSavedRegisters * kSystemPointerSize; + + // Below the frame pointer. + // Register parameters stored by setup code. +- static const int kDirectCall = -kSystemPointerSize; +- static const int kStackHighEnd = kDirectCall - kSystemPointerSize; +- static const int kOutputSize = kStackHighEnd - kSystemPointerSize; ++ static const int kIsolate = -kSystemPointerSize; ++ static const int kDirectCall = kIsolate - kSystemPointerSize; ++ static const int kOutputSize = kDirectCall - kSystemPointerSize; + static const int kInput = kOutputSize - kSystemPointerSize; + // When adding local variables remember to push space for them in + // the frame in GetCode. +diff --git a/src/regexp/experimental/experimental.cc b/src/regexp/experimental/experimental.cc +index bff2d7da6645d6023fc218daf370a51a9d404495..def43dc2c167fd463947cbbbc507da664d38aead 100644 +--- a/src/regexp/experimental/experimental.cc ++++ b/src/regexp/experimental/experimental.cc +@@ -192,8 +192,7 @@ int32_t ExperimentalRegExp::ExecRaw(Isolate* isolate, + int32_t ExperimentalRegExp::MatchForCallFromJs( + Address subject, int32_t start_position, Address input_start, + Address input_end, int* output_registers, int32_t output_register_count, +- Address backtrack_stack, RegExp::CallOrigin call_origin, Isolate* isolate, +- Address regexp) { ++ RegExp::CallOrigin call_origin, Isolate* isolate, Address regexp) { + DCHECK(FLAG_enable_experimental_regexp_engine); + DCHECK_NOT_NULL(isolate); + DCHECK_NOT_NULL(output_registers); +diff --git a/src/regexp/experimental/experimental.h b/src/regexp/experimental/experimental.h +index 1b44100cc88bed7825c0a30fb05e8477c47860ec..671792e5ef82919af652f431c5f6b325fea08d77 100644 +--- a/src/regexp/experimental/experimental.h ++++ b/src/regexp/experimental/experimental.h +@@ -33,7 +33,6 @@ class ExperimentalRegExp final : public AllStatic { + Address input_start, Address input_end, + int* output_registers, + int32_t output_register_count, +- Address backtrack_stack, + RegExp::CallOrigin call_origin, + Isolate* isolate, Address regexp); + static MaybeHandle Exec( +diff --git a/src/regexp/ia32/regexp-macro-assembler-ia32.cc b/src/regexp/ia32/regexp-macro-assembler-ia32.cc +index 51d63b2531e2bc85fb115de23d7b6a6f40b36f11..8369b88e22c300890fe4ddb1bbba62093e8b23d8 100644 +--- a/src/regexp/ia32/regexp-macro-assembler-ia32.cc ++++ b/src/regexp/ia32/regexp-macro-assembler-ia32.cc +@@ -40,8 +40,6 @@ namespace internal { + * - Isolate* isolate (address of the current isolate) + * - direct_call (if 1, direct call from JavaScript code, if 0 + * call through the runtime system) +- * - stack_area_base (high end of the memory area to use as +- * backtracking stack) + * - capture array size (may fit multiple sets of matches) + * - int* capture_array (int[num_saved_registers_], for output). + * - end of input (address of end of string) +@@ -74,7 +72,6 @@ namespace internal { + * Address end, + * int* capture_output_array, + * int num_capture_registers, +- * byte* stack_area_base, + * bool direct_call = false, + * Isolate* isolate + * Address regexp); +diff --git a/src/regexp/ia32/regexp-macro-assembler-ia32.h b/src/regexp/ia32/regexp-macro-assembler-ia32.h +index 861795da900d91111386e4f8e660f7f94ea46a33..01914a6b8b5abb96a4eec8d844e2d1aea7cbf231 100644 +--- a/src/regexp/ia32/regexp-macro-assembler-ia32.h ++++ b/src/regexp/ia32/regexp-macro-assembler-ia32.h +@@ -105,8 +105,7 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32 + // one set of capture results. For the case of non-global regexp, we ignore + // this value. + static const int kNumOutputRegisters = kRegisterOutput + kSystemPointerSize; +- static const int kStackHighEnd = kNumOutputRegisters + kSystemPointerSize; +- static const int kDirectCall = kStackHighEnd + kSystemPointerSize; ++ static const int kDirectCall = kNumOutputRegisters + kSystemPointerSize; + static const int kIsolate = kDirectCall + kSystemPointerSize; + // Below the frame pointer - local stack variables. + // When adding local variables remember to push space for them in +diff --git a/src/regexp/regexp-interpreter.cc b/src/regexp/regexp-interpreter.cc +index 02fc3349208b7127d967a8b25763b3951f2c9dde..c9dd403e751502750cbb8bc4b4e820eb1136c9ea 100644 +--- a/src/regexp/regexp-interpreter.cc ++++ b/src/regexp/regexp-interpreter.cc +@@ -1110,7 +1110,7 @@ IrregexpInterpreter::Result IrregexpInterpreter::MatchInternal( + // builtin. + IrregexpInterpreter::Result IrregexpInterpreter::MatchForCallFromJs( + Address subject, int32_t start_position, Address, Address, +- int* output_registers, int32_t output_register_count, Address, ++ int* output_registers, int32_t output_register_count, + RegExp::CallOrigin call_origin, Isolate* isolate, Address regexp) { + DCHECK_NOT_NULL(isolate); + DCHECK_NOT_NULL(output_registers); +diff --git a/src/regexp/regexp-interpreter.h b/src/regexp/regexp-interpreter.h +index 9b4a8c6c307266a78a35f52ef4ef0afe5b6af6fe..19f9513acc2c7d309179ca5e18ca7ef2165e74f4 100644 +--- a/src/regexp/regexp-interpreter.h ++++ b/src/regexp/regexp-interpreter.h +@@ -34,9 +34,8 @@ class V8_EXPORT_PRIVATE IrregexpInterpreter : public AllStatic { + // RETRY is returned if a retry through the runtime is needed (e.g. when + // interrupts have been scheduled or the regexp is marked for tier-up). + // +- // Arguments input_start, input_end and backtrack_stack are +- // unused. They are only passed to match the signature of the native irregex +- // code. ++ // Arguments input_start and input_end are unused. They are only passed to ++ // match the signature of the native irregex code. + // + // Arguments output_registers and output_register_count describe the results + // array, which will contain register values of all captures if SUCCESS is +@@ -45,7 +44,6 @@ class V8_EXPORT_PRIVATE IrregexpInterpreter : public AllStatic { + Address input_start, Address input_end, + int* output_registers, + int32_t output_register_count, +- Address backtrack_stack, + RegExp::CallOrigin call_origin, + Isolate* isolate, Address regexp); + +diff --git a/src/regexp/regexp-macro-assembler.cc b/src/regexp/regexp-macro-assembler.cc +index 27590fac36cea92f557dc0c149d9cbed6efef8b5..73313f95ec1d6e5bd7e5479e45c6b1980c638aa9 100644 +--- a/src/regexp/regexp-macro-assembler.cc ++++ b/src/regexp/regexp-macro-assembler.cc +@@ -300,23 +300,21 @@ int NativeRegExpMacroAssembler::Execute( + String input, // This needs to be the unpacked (sliced, cons) string. + int start_offset, const byte* input_start, const byte* input_end, + int* output, int output_size, Isolate* isolate, JSRegExp regexp) { +- // Ensure that the minimum stack has been allocated. + RegExpStackScope stack_scope(isolate); +- Address stack_base = stack_scope.stack()->memory_top(); + + bool is_one_byte = String::IsOneByteRepresentationUnderneath(input); + Code code = FromCodeT(CodeT::cast(regexp.Code(is_one_byte))); + RegExp::CallOrigin call_origin = RegExp::CallOrigin::kFromRuntime; + +- using RegexpMatcherSig = int( +- Address input_string, int start_offset, const byte* input_start, +- const byte* input_end, int* output, int output_size, Address stack_base, +- int call_origin, Isolate* isolate, Address regexp); ++ using RegexpMatcherSig = ++ // NOLINTNEXTLINE(readability/casting) ++ int(Address input_string, int start_offset, const byte* input_start, ++ const byte* input_end, int* output, int output_size, int call_origin, ++ Isolate* isolate, Address regexp); + + auto fn = GeneratedCode::FromCode(code); +- int result = +- fn.Call(input.ptr(), start_offset, input_start, input_end, output, +- output_size, stack_base, call_origin, isolate, regexp.ptr()); ++ int result = fn.Call(input.ptr(), start_offset, input_start, input_end, ++ output, output_size, call_origin, isolate, regexp.ptr()); + DCHECK_GE(result, SMALLEST_REGEXP_RESULT); + + if (result == EXCEPTION && !isolate->has_pending_exception()) { +diff --git a/src/regexp/x64/regexp-macro-assembler-x64.cc b/src/regexp/x64/regexp-macro-assembler-x64.cc +index abcbed18aaa9bdc4a497962714bffde74d581173..e4bff5dafa9f12c14805c72e51f973252b97a5a7 100644 +--- a/src/regexp/x64/regexp-macro-assembler-x64.cc ++++ b/src/regexp/x64/regexp-macro-assembler-x64.cc +@@ -47,14 +47,12 @@ namespace internal { + * Each call to a C++ method should retain these registers. + * + * The stack will have the following content, in some order, indexable from the +- * frame pointer (see, e.g., kStackHighEnd): ++ * frame pointer (see, e.g., kDirectCall): + * - Address regexp (address of the JSRegExp object; unused in native + * code, passed to match signature of interpreter) + * - Isolate* isolate (address of the current isolate) + * - direct_call (if 1, direct call from JavaScript code, if 0 call + * through the runtime system) +- * - stack_area_base (high end of the memory area to use as +- * backtracking stack) + * - capture array size (may fit multiple sets of matches) + * - int* capture_array (int[num_saved_registers_], for output). + * - end of input (address of end of string) +@@ -85,7 +83,6 @@ namespace internal { + * Address end, + * int* capture_output_array, + * int num_capture_registers, +- * byte* stack_area_base, + * bool direct_call = false, + * Isolate* isolate, + * Address regexp); +@@ -849,8 +846,6 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { + } + + // Initialize backtrack stack pointer. +- // TODO(jgruber): Remove the kStackHighEnd parameter (and others like +- // kIsolate). + LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); + + __ jmp(&start_label_); +diff --git a/src/regexp/x64/regexp-macro-assembler-x64.h b/src/regexp/x64/regexp-macro-assembler-x64.h +index 74a3c95b06c771078ab03e6787e5912315421bb2..6f89ba9f8cf45430dc0edc7f2241a9aca34324c0 100644 +--- a/src/regexp/x64/regexp-macro-assembler-x64.h ++++ b/src/regexp/x64/regexp-macro-assembler-x64.h +@@ -108,9 +108,8 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 + // this value. NumOutputRegisters is passed as 32-bit value. The upper + // 32 bit of this 64-bit stack slot may contain garbage. + static const int kNumOutputRegisters = kRegisterOutput + kSystemPointerSize; +- static const int kStackHighEnd = kNumOutputRegisters + kSystemPointerSize; + // DirectCall is passed as 32 bit int (values 0 or 1). +- static const int kDirectCall = kStackHighEnd + kSystemPointerSize; ++ static const int kDirectCall = kNumOutputRegisters + kSystemPointerSize; + static const int kIsolate = kDirectCall + kSystemPointerSize; + #else + // In AMD64 ABI Calling Convention, the first six integer parameters +@@ -121,13 +120,12 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 + static const int kInputStart = kStartIndex - kSystemPointerSize; + static const int kInputEnd = kInputStart - kSystemPointerSize; + static const int kRegisterOutput = kInputEnd - kSystemPointerSize; +- + // For the case of global regular expression, we have room to store at least + // one set of capture results. For the case of non-global regexp, we ignore + // this value. + static const int kNumOutputRegisters = kRegisterOutput - kSystemPointerSize; +- static const int kStackHighEnd = kFrameAlign; +- static const int kDirectCall = kStackHighEnd + kSystemPointerSize; ++ ++ static const int kDirectCall = kFrameAlign; + static const int kIsolate = kDirectCall + kSystemPointerSize; + #endif +