|
@@ -0,0 +1,1736 @@
|
|
|
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
+From: Jakob Gruber <[email protected]>
|
|
|
+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 <[email protected]>
|
|
|
+Reviewed-by: Patrick Thier <[email protected]>
|
|
|
+Commit-Queue: Toon Verwaest <[email protected]>
|
|
|
+Auto-Submit: Jakob Gruber <[email protected]>
|
|
|
+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<i::Isolate*>(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<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
|
|
|
+ Label return_r0;
|
|
|
+@@ -654,6 +687,13 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
|
|
|
+ }
|
|
|
+
|
|
|
+ // Initialize backtrack stack pointer.
|
|
|
+- __ ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd));
|
|
|
++ LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
|
|
|
+
|
|
|
+ __ jmp(&start_label_);
|
|
|
+
|
|
|
+@@ -834,6 +874,10 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> 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<int>(mode_); }
|
|
|
++ inline int char_size() const { return static_cast<int>(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<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
|
|
|
+ Label return_w0;
|
|
|
+@@ -745,22 +780,27 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> 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<TurboAssembler::kAuthLR>(fp, lr);
|
|
|
+
|
|
|
+@@ -1040,6 +1083,9 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> 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 <typename T>
|
|
|
+ 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<int>(mode_); }
|
|
|
++ int char_size() const { return static_cast<int>(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<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
|
|
|
+ Label return_eax;
|
|
|
+@@ -676,14 +706,23 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
|
|
|
+ }
|
|
|
+
|
|
|
+ // Initialize backtrack stack pointer.
|
|
|
+- __ mov(backtrack_stackpointer(), Operand(ebp, kStackHighEnd));
|
|
|
++ LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
|
|
|
+
|
|
|
+ __ jmp(&start_label_);
|
|
|
+
|
|
|
+@@ -855,8 +894,12 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> 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<int>(mode_); }
|
|
|
++ inline int char_size() const { return static_cast<int>(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<size_t>(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<size_t>(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<Address>(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<Address>(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<Address>(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<Address>(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<int>(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<Address>(&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<Address>(&thread_local_.stack_pointer_);
|
|
|
++ }
|
|
|
++
|
|
|
++ // A position-independent representation of the stack pointer.
|
|
|
++ ptrdiff_t sp_top_delta() const {
|
|
|
++ ptrdiff_t result =
|
|
|
++ reinterpret_cast<intptr_t>(thread_local_.stack_pointer_) -
|
|
|
++ reinterpret_cast<intptr_t>(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<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> 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<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> 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<int>(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<int> 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
|
|
|
+
|
|
|
+ ##############################################################################
|