Commit bba7c09a authored by Jakob Gruber's avatar Jakob Gruber Committed by V8 LUCI CQ

[regexp] 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/+/3162604Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarPatrick Thier <pthier@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Auto-Submit: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77013}
parent e262e1cb
...@@ -108,7 +108,6 @@ ...@@ -108,7 +108,6 @@
#include "src/profiler/heap-snapshot-generator-inl.h" #include "src/profiler/heap-snapshot-generator-inl.h"
#include "src/profiler/profile-generator-inl.h" #include "src/profiler/profile-generator-inl.h"
#include "src/profiler/tick-sample.h" #include "src/profiler/tick-sample.h"
#include "src/regexp/regexp-stack.h"
#include "src/regexp/regexp-utils.h" #include "src/regexp/regexp-utils.h"
#include "src/runtime/runtime.h" #include "src/runtime/runtime.h"
#include "src/snapshot/code-serializer.h" #include "src/snapshot/code-serializer.h"
......
...@@ -761,6 +761,11 @@ ExternalReference ExternalReference::address_of_regexp_stack_memory_top_address( ...@@ -761,6 +761,11 @@ ExternalReference ExternalReference::address_of_regexp_stack_memory_top_address(
isolate->regexp_stack()->memory_top_address_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( ExternalReference ExternalReference::javascript_execution_assert(
Isolate* isolate) { Isolate* isolate) {
return ExternalReference(isolate->javascript_execution_assert_address()); return ExternalReference(isolate->javascript_execution_assert_address());
......
...@@ -72,6 +72,8 @@ class StatsCounter; ...@@ -72,6 +72,8 @@ class StatsCounter;
"RegExpStack::limit_address_address()") \ "RegExpStack::limit_address_address()") \
V(address_of_regexp_stack_memory_top_address, \ V(address_of_regexp_stack_memory_top_address, \
"RegExpStack::memory_top_address_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(address_of_static_offsets_vector, "OffsetsVector::static_offsets_vector") \
V(thread_in_wasm_flag_address_address, \ V(thread_in_wasm_flag_address_address, \
"Isolate::thread_in_wasm_flag_address_address") \ "Isolate::thread_in_wasm_flag_address_address") \
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include "src/objects/js-generator-inl.h" #include "src/objects/js-generator-inl.h"
#include "src/objects/stack-frame-info-inl.h" #include "src/objects/stack-frame-info-inl.h"
#include "src/profiler/heap-profiler.h" #include "src/profiler/heap-profiler.h"
#include "src/regexp/regexp-stack.h"
#include "src/strings/string-builder-inl.h" #include "src/strings/string-builder-inl.h"
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
...@@ -304,10 +303,7 @@ void SetTerminateOnResume(Isolate* v8_isolate) { ...@@ -304,10 +303,7 @@ void SetTerminateOnResume(Isolate* v8_isolate) {
bool CanBreakProgram(Isolate* v8_isolate) { bool CanBreakProgram(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ENTER_V8_DO_NOT_USE(isolate); ENTER_V8_DO_NOT_USE(isolate);
// We cannot break a program if we are currently running a regexp. return isolate->debug()->AllFramesOnStackAreBlackboxed();
// TODO(yangguo): fix this exception.
return !isolate->regexp_stack()->is_in_use() &&
isolate->debug()->AllFramesOnStackAreBlackboxed();
} }
Isolate* Script::GetIsolate() const { Isolate* Script::GetIsolate() const {
......
...@@ -3610,7 +3610,6 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data, ...@@ -3610,7 +3610,6 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data,
store_stub_cache_ = new StubCache(this); store_stub_cache_ = new StubCache(this);
materialized_object_store_ = new MaterializedObjectStore(this); materialized_object_store_ = new MaterializedObjectStore(this);
regexp_stack_ = new RegExpStack(); regexp_stack_ = new RegExpStack();
regexp_stack_->isolate_ = this;
date_cache_ = new DateCache(); date_cache_ = new DateCache();
heap_profiler_ = new HeapProfiler(heap()); heap_profiler_ = new HeapProfiler(heap());
interpreter_ = new interpreter::Interpreter(this); interpreter_ = new interpreter::Interpreter(this);
......
...@@ -6,15 +6,13 @@ ...@@ -6,15 +6,13 @@
#include "src/regexp/arm/regexp-macro-assembler-arm.h" #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/codegen/macro-assembler.h"
#include "src/heap/factory.h" #include "src/heap/factory.h"
#include "src/logging/log.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/regexp/regexp-stack.h"
#include "src/snapshot/embedded/embedded-data.h" #include "src/snapshot/embedded/embedded-data.h"
#include "src/strings/unicode.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -102,6 +100,7 @@ RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(Isolate* isolate, Zone* zone, ...@@ -102,6 +100,7 @@ RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(Isolate* isolate, Zone* zone,
: NativeRegExpMacroAssembler(isolate, zone), : NativeRegExpMacroAssembler(isolate, zone),
masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes, masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes,
NewAssemblerBuffer(kRegExpCodeSize))), NewAssemblerBuffer(kRegExpCodeSize))),
no_root_array_scope_(masm_),
mode_(mode), mode_(mode),
num_registers_(registers_to_save), num_registers_(registers_to_save),
num_saved_registers_(registers_to_save), num_saved_registers_(registers_to_save),
...@@ -110,8 +109,6 @@ RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(Isolate* isolate, Zone* zone, ...@@ -110,8 +109,6 @@ RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(Isolate* isolate, Zone* zone,
success_label_(), success_label_(),
backtrack_label_(), backtrack_label_(),
exit_label_() { exit_label_() {
masm_->set_root_array_available(false);
DCHECK_EQ(0, registers_to_save % 2); DCHECK_EQ(0, registers_to_save % 2);
__ jmp(&entry_label_); // We'll write the entry code later. __ jmp(&entry_label_); // We'll write the entry code later.
__ bind(&start_label_); // And then continue from here. __ bind(&start_label_); // And then continue from here.
...@@ -619,6 +616,42 @@ void RegExpMacroAssemblerARM::Fail() { ...@@ -619,6 +616,42 @@ void RegExpMacroAssemblerARM::Fail() {
__ jmp(&exit_label_); __ 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) { Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
Label return_r0; Label return_r0;
...@@ -654,6 +687,13 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { ...@@ -654,6 +687,13 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
__ push(r0); // Make room for "string start - 1" constant. __ push(r0); // Make room for "string start - 1" constant.
STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize); STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize);
__ push(r0); // The backtrack counter. __ 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. // Check if we have space on the stack for registers.
Label stack_limit_hit; Label stack_limit_hit;
...@@ -736,7 +776,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { ...@@ -736,7 +776,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
} }
// Initialize backtrack stack pointer. // Initialize backtrack stack pointer.
__ ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd)); LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
__ jmp(&start_label_); __ jmp(&start_label_);
...@@ -834,6 +874,10 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { ...@@ -834,6 +874,10 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
} }
__ bind(&return_r0); __ 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.. // Skip sp past regexp registers and local variables..
__ mov(sp, frame_pointer()); __ mov(sp, frame_pointer());
// Restore registers r4..r11 and return (restoring lr to pc). // Restore registers r4..r11 and return (restoring lr to pc).
...@@ -851,12 +895,16 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { ...@@ -851,12 +895,16 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
if (check_preempt_label_.is_linked()) { if (check_preempt_label_.is_linked()) {
SafeCallTarget(&check_preempt_label_); SafeCallTarget(&check_preempt_label_);
StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r1);
CallCheckStackGuardState(); CallCheckStackGuardState();
__ cmp(r0, Operand::Zero()); __ cmp(r0, Operand::Zero());
// If returning non-zero, we should end execution with the given // If returning non-zero, we should end execution with the given
// result as return value. // result as return value.
__ b(ne, &return_r0); __ b(ne, &return_r0);
LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
// String might have moved: Reload end of string from frame. // String might have moved: Reload end of string from frame.
__ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
SafeReturn(); SafeReturn();
...@@ -867,17 +915,18 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) { ...@@ -867,17 +915,18 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
SafeCallTarget(&stack_overflow_label_); SafeCallTarget(&stack_overflow_label_);
// Reached if the backtrack-stack limit has been hit. // Reached if the backtrack-stack limit has been hit.
// Call GrowStack(backtrack_stackpointer(), &stack_base) // Call GrowStack(isolate).
static const int num_arguments = 3;
__ PrepareCallCFunction(num_arguments); StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r1);
__ mov(r0, backtrack_stackpointer());
__ add(r1, frame_pointer(), Operand(kStackHighEnd)); static constexpr int kNumArguments = 1;
__ mov(r2, Operand(ExternalReference::isolate_address(isolate()))); __ PrepareCallCFunction(kNumArguments);
__ mov(r0, Operand(ExternalReference::isolate_address(isolate())));
ExternalReference grow_stack = ExternalReference grow_stack =
ExternalReference::re_grow_stack(isolate()); ExternalReference::re_grow_stack(isolate());
__ CallCFunction(grow_stack, num_arguments); __ CallCFunction(grow_stack, kNumArguments);
// If return nullptr, we have failed to grow the stack, and // If nullptr is returned, we have failed to grow the stack, and must exit
// must exit with a stack-overflow exception. // with a stack-overflow exception.
__ cmp(r0, Operand::Zero()); __ cmp(r0, Operand::Zero());
__ b(eq, &exit_with_exception); __ b(eq, &exit_with_exception);
// Otherwise use return value as new stack pointer. // Otherwise use return value as new stack pointer.
...@@ -984,14 +1033,24 @@ void RegExpMacroAssemblerARM::ReadCurrentPositionFromRegister(int reg) { ...@@ -984,14 +1033,24 @@ void RegExpMacroAssemblerARM::ReadCurrentPositionFromRegister(int reg) {
__ ldr(current_input_offset(), register_location(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) { 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(backtrack_stackpointer(), register_location(reg));
__ ldr(r0, MemOperand(frame_pointer(), kStackHighEnd)); __ add(backtrack_stackpointer(), backtrack_stackpointer(), r0);
__ add(backtrack_stackpointer(), backtrack_stackpointer(), Operand(r0));
} }
void RegExpMacroAssemblerARM::SetCurrentPositionFromEnd(int by) { void RegExpMacroAssemblerARM::SetCurrentPositionFromEnd(int by) {
Label after_position; Label after_position;
__ cmp(current_input_offset(), Operand(-by * char_size())); __ cmp(current_input_offset(), Operand(-by * char_size()));
...@@ -1037,14 +1096,6 @@ void RegExpMacroAssemblerARM::ClearRegisters(int reg_from, int reg_to) { ...@@ -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: // Private methods:
void RegExpMacroAssemblerARM::CallCheckStackGuardState() { void RegExpMacroAssemblerARM::CallCheckStackGuardState() {
......
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
#ifndef V8_REGEXP_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_ #ifndef V8_REGEXP_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_
#define 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/codegen/macro-assembler.h"
#include "src/regexp/regexp-macro-assembler.h" #include "src/regexp/regexp-macro-assembler.h"
...@@ -115,8 +113,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM ...@@ -115,8 +113,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM
static const int kSuccessfulCaptures = kInputString - kPointerSize; static const int kSuccessfulCaptures = kInputString - kPointerSize;
static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize; static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize;
static const int kBacktrackCount = kStringStartMinusOne - 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. // 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. // Initial size of code buffer.
static const int kRegExpCodeSize = 1024; static const int kRegExpCodeSize = 1024;
...@@ -129,7 +133,6 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM ...@@ -129,7 +133,6 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM
// Check whether we are exceeding the stack limit on the backtrack stack. // Check whether we are exceeding the stack limit on the backtrack stack.
void CheckStackLimit(); void CheckStackLimit();
// Generate a call to CheckStackGuardState. // Generate a call to CheckStackGuardState.
void CallCheckStackGuardState(); void CallCheckStackGuardState();
...@@ -138,27 +141,27 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM ...@@ -138,27 +141,27 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM
// Register holding the current input position as negative offset from // Register holding the current input position as negative offset from
// the end of the string. // 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. // 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. // 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 // Register holding the frame address. Local variables, parameters and
// regexp registers are addressed relative to this. // 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 // The register containing the backtrack stack top. Provides a meaningful
// name to the register. // 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. // 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) // 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 // Equivalent to a conditional branch to the label, unless the label
// is nullptr, in which case it is a conditional Backtrack. // is nullptr, in which case it is a conditional Backtrack.
...@@ -178,19 +181,25 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM ...@@ -178,19 +181,25 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM
// and increments it by a word size. // and increments it by a word size.
inline void Pop(Register target); 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(); } 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). // Which mode to generate code for (Latin1 or UC16).
Mode mode_; const Mode mode_;
// One greater than maximal register index actually used. // One greater than maximal register index actually used.
int num_registers_; int num_registers_;
// Number of registers to output at the end (the saved registers // Number of registers to output at the end (the saved registers
// are always 0..num_saved_registers_-1) // are always 0..num_saved_registers_-1)
int num_saved_registers_; const int num_saved_registers_;
// Labels used internally. // Labels used internally.
Label entry_label_; Label entry_label_;
......
...@@ -113,6 +113,7 @@ RegExpMacroAssemblerARM64::RegExpMacroAssemblerARM64(Isolate* isolate, ...@@ -113,6 +113,7 @@ RegExpMacroAssemblerARM64::RegExpMacroAssemblerARM64(Isolate* isolate,
: NativeRegExpMacroAssembler(isolate, zone), : NativeRegExpMacroAssembler(isolate, zone),
masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes, masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes,
NewAssemblerBuffer(kRegExpCodeSize))), NewAssemblerBuffer(kRegExpCodeSize))),
no_root_array_scope_(masm_),
mode_(mode), mode_(mode),
num_registers_(registers_to_save), num_registers_(registers_to_save),
num_saved_registers_(registers_to_save), num_saved_registers_(registers_to_save),
...@@ -121,8 +122,6 @@ RegExpMacroAssemblerARM64::RegExpMacroAssemblerARM64(Isolate* isolate, ...@@ -121,8 +122,6 @@ RegExpMacroAssemblerARM64::RegExpMacroAssemblerARM64(Isolate* isolate,
success_label_(), success_label_(),
backtrack_label_(), backtrack_label_(),
exit_label_() { exit_label_() {
masm_->set_root_array_available(false);
DCHECK_EQ(0, registers_to_save % 2); DCHECK_EQ(0, registers_to_save % 2);
// We can cache at most 16 W registers in x0-x7. // We can cache at most 16 W registers in x0-x7.
STATIC_ASSERT(kNumCachedRegisters <= 16); STATIC_ASSERT(kNumCachedRegisters <= 16);
...@@ -699,6 +698,42 @@ void RegExpMacroAssemblerARM64::Fail() { ...@@ -699,6 +698,42 @@ void RegExpMacroAssemblerARM64::Fail() {
__ B(&exit_label_); __ 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) { Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
Label return_w0; Label return_w0;
...@@ -744,22 +779,27 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) { ...@@ -744,22 +779,27 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
__ Mov(input_end(), x3); __ Mov(input_end(), x3);
__ Mov(output_array(), x4); __ 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. // Make sure the stack alignment will be respected.
int alignment = masm_->ActivationFrameAlignment(); const int alignment = masm_->ActivationFrameAlignment();
DCHECK_EQ(alignment % 16, 0); DCHECK_EQ(alignment % 16, 0);
int align_mask = (alignment / kWRegSize) - 1; const int align_mask = (alignment / kWRegSize) - 1;
num_wreg_to_allocate = (num_wreg_to_allocate + align_mask) & ~align_mask;
// 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. // Check if we have space on the stack.
Label stack_limit_hit; Label stack_limit_hit;
...@@ -839,9 +879,9 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) { ...@@ -839,9 +879,9 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
} }
// Initialize backtrack stack pointer. // Initialize backtrack stack pointer.
__ Ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackBase)); LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
// Execute // Execute.
__ B(&start_label_); __ B(&start_label_);
if (backtrack_label_.is_linked()) { if (backtrack_label_.is_linked()) {
...@@ -1013,7 +1053,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) { ...@@ -1013,7 +1053,7 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
} }
if (exit_label_.is_linked()) { if (exit_label_.is_linked()) {
// Exit and return w0 // Exit and return w0.
__ Bind(&exit_label_); __ Bind(&exit_label_);
if (global()) { if (global()) {
__ Ldr(w0, MemOperand(frame_pointer(), kSuccessCounter)); __ Ldr(w0, MemOperand(frame_pointer(), kSuccessCounter));
...@@ -1021,8 +1061,11 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) { ...@@ -1021,8 +1061,11 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
} }
__ Bind(&return_w0); __ 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); __ Mov(sp, fp);
__ Pop<TurboAssembler::kAuthLR>(fp, lr); __ Pop<TurboAssembler::kAuthLR>(fp, lr);
...@@ -1039,6 +1082,9 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) { ...@@ -1039,6 +1082,9 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
if (check_preempt_label_.is_linked()) { if (check_preempt_label_.is_linked()) {
__ Bind(&check_preempt_label_); __ Bind(&check_preempt_label_);
StoreRegExpStackPointerToMemory(backtrack_stackpointer(), x10);
SaveLinkRegister(); SaveLinkRegister();
// The cached registers need to be retained. // The cached registers need to be retained.
__ PushCPURegList(cached_registers); __ PushCPURegList(cached_registers);
...@@ -1048,26 +1094,30 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) { ...@@ -1048,26 +1094,30 @@ Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
__ Cbnz(w0, &return_w0); __ Cbnz(w0, &return_w0);
// Reset the cached registers. // Reset the cached registers.
__ PopCPURegList(cached_registers); __ PopCPURegList(cached_registers);
LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
RestoreLinkRegister(); RestoreLinkRegister();
__ Ret(); __ Ret();
} }
if (stack_overflow_label_.is_linked()) { if (stack_overflow_label_.is_linked()) {
__ Bind(&stack_overflow_label_); __ Bind(&stack_overflow_label_);
StoreRegExpStackPointerToMemory(backtrack_stackpointer(), x10);
SaveLinkRegister(); SaveLinkRegister();
// The cached registers need to be retained. // The cached registers need to be retained.
__ PushCPURegList(cached_registers); __ PushCPURegList(cached_registers);
// Call GrowStack(backtrack_stackpointer(), &stack_base) // Call GrowStack(isolate)
__ Mov(x2, ExternalReference::isolate_address(isolate())); static constexpr int kNumArguments = 1;
__ Add(x1, frame_pointer(), kStackBase); __ Mov(x0, ExternalReference::isolate_address(isolate()));
__ Mov(x0, backtrack_stackpointer()); __ CallCFunction(ExternalReference::re_grow_stack(isolate()),
ExternalReference grow_stack = kNumArguments);
ExternalReference::re_grow_stack(isolate()); // If return nullptr, we have failed to grow the stack, and must exit with
__ CallCFunction(grow_stack, 3); // a stack-overflow exception. Returning from the regexp code restores the
// If return nullptr, we have failed to grow the stack, and // stack (sp <- fp) so we don't need to drop the link register from it
// must exit with a stack-overflow exception. // before exiting.
// 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); __ Cbz(w0, &exit_with_exception);
// Otherwise use return value as new stack pointer. // Otherwise use return value as new stack pointer.
__ Mov(backtrack_stackpointer(), x0); __ Mov(backtrack_stackpointer(), x0);
...@@ -1191,14 +1241,29 @@ void RegExpMacroAssemblerARM64::ReadCurrentPositionFromRegister(int reg) { ...@@ -1191,14 +1241,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) { void RegExpMacroAssemblerARM64::ReadStackPointerFromRegister(int reg) {
ExternalReference ref =
ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
Register read_from = GetRegister(reg, w10); 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)); __ Add(backtrack_stackpointer(), x11, Operand(read_from, SXTW));
} }
void RegExpMacroAssemblerARM64::SetCurrentPositionFromEnd(int by) { void RegExpMacroAssemblerARM64::SetCurrentPositionFromEnd(int by) {
Label after_position; Label after_position;
__ Cmp(current_input_offset(), -by * char_size()); __ Cmp(current_input_offset(), -by * char_size());
...@@ -1300,19 +1365,6 @@ void RegExpMacroAssemblerARM64::ClearRegisters(int reg_from, int reg_to) { ...@@ -1300,19 +1365,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. // Helper function for reading a value out of a stack frame.
template <typename T> template <typename T>
static T& frame_entry(Address re_frame, int frame_offset) { static T& frame_entry(Address re_frame, int frame_offset) {
......
...@@ -110,18 +110,28 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 ...@@ -110,18 +110,28 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64
// Below the frame pointer. // Below the frame pointer.
// Register parameters stored by setup code. // Register parameters stored by setup code.
static const int kDirectCall = -kSystemPointerSize; static const int kDirectCall = -kSystemPointerSize;
static const int kStackBase = kDirectCall - kSystemPointerSize; static const int kStackHighEnd = kDirectCall - kSystemPointerSize;
static const int kOutputSize = kStackBase - kSystemPointerSize; static const int kOutputSize = kStackHighEnd - kSystemPointerSize;
static const int kInput = kOutputSize - kSystemPointerSize; static const int kInput = kOutputSize - kSystemPointerSize;
// When adding local variables remember to push space for them in // When adding local variables remember to push space for them in
// the frame in GetCode. // the frame in GetCode.
static const int kSuccessCounter = kInput - kSystemPointerSize; static const int kSuccessCounter = kInput - kSystemPointerSize;
static const int kBacktrackCount = kSuccessCounter - 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 // First position register address on the stack. Following positions are
// below it. A position is a 32 bit value. // 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. // 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. // Initial size of code buffer.
static const int kRegExpCodeSize = 1024; static const int kRegExpCodeSize = 1024;
...@@ -152,43 +162,43 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 ...@@ -152,43 +162,43 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64
// Register holding the current input position as negative offset from // Register holding the current input position as negative offset from
// the end of the string. // 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. // 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 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 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 // Register holding the offset from the start of the string where we should
// start matching. // start matching.
Register start_offset() { return w27; } static constexpr Register start_offset() { return w27; }
// Pointer to the output array's first element. // 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 // Register holding the frame address. Local variables, parameters and
// regexp registers are addressed relative to this. // 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 // The register containing the backtrack stack top. Provides a meaningful
// name to the register. // 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 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 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 // 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. // 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) // 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 // Equivalent to a conditional branch to the label, unless the label
// is nullptr, in which case it is a conditional Backtrack. // is nullptr, in which case it is a conditional Backtrack.
...@@ -254,19 +264,25 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 ...@@ -254,19 +264,25 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64
// This assumes that the state of the register is not STACKED. // This assumes that the state of the register is not STACKED.
inline Register GetCachedRegister(int register_index); 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(); } 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). // Which mode to generate code for (LATIN1 or UC16).
Mode mode_; const Mode mode_;
// One greater than maximal register index actually used. // One greater than maximal register index actually used.
int num_registers_; int num_registers_;
// Number of registers to output at the end (the saved registers // Number of registers to output at the end (the saved registers
// are always 0..num_saved_registers_-1) // are always 0..num_saved_registers_-1)
int num_saved_registers_; const int num_saved_registers_;
// Labels used internally. // Labels used internally.
Label entry_label_; Label entry_label_;
......
...@@ -90,6 +90,7 @@ RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(Isolate* isolate, Zone* zone, ...@@ -90,6 +90,7 @@ RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(Isolate* isolate, Zone* zone,
: NativeRegExpMacroAssembler(isolate, zone), : NativeRegExpMacroAssembler(isolate, zone),
masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes, masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes,
NewAssemblerBuffer(kRegExpCodeSize))), NewAssemblerBuffer(kRegExpCodeSize))),
no_root_array_scope_(masm_),
mode_(mode), mode_(mode),
num_registers_(registers_to_save), num_registers_(registers_to_save),
num_saved_registers_(registers_to_save), num_saved_registers_(registers_to_save),
...@@ -98,9 +99,6 @@ RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(Isolate* isolate, Zone* zone, ...@@ -98,9 +99,6 @@ RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(Isolate* isolate, Zone* zone,
success_label_(), success_label_(),
backtrack_label_(), backtrack_label_(),
exit_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); DCHECK_EQ(0, registers_to_save % 2);
__ jmp(&entry_label_); // We'll write the entry code later. __ jmp(&entry_label_); // We'll write the entry code later.
__ bind(&start_label_); // And then continue from here. __ bind(&start_label_); // And then continue from here.
...@@ -655,6 +653,38 @@ void RegExpMacroAssemblerIA32::Fail() { ...@@ -655,6 +653,38 @@ void RegExpMacroAssemblerIA32::Fail() {
__ jmp(&exit_label_); __ 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) { Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
Label return_eax; Label return_eax;
...@@ -676,14 +706,23 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { ...@@ -676,14 +706,23 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
__ push(esi); __ push(esi);
__ push(edi); __ push(edi);
__ push(ebx); // Callee-save on MacOS. __ 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. __ push(Immediate(0)); // Number of successful matches in a global regexp.
STATIC_ASSERT(kStringStartMinusOne == STATIC_ASSERT(kStringStartMinusOne ==
kSuccessfulCaptures - kSystemPointerSize); kSuccessfulCaptures - kSystemPointerSize);
__ push(Immediate(0)); // Make room for "string start - 1" constant. __ push(Immediate(0)); // Make room for "string start - 1" constant.
STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize); STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize);
__ push(Immediate(0)); // The backtrack counter. __ 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. // Check if we have space on the stack for registers.
Label stack_limit_hit; Label stack_limit_hit;
...@@ -769,7 +808,7 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { ...@@ -769,7 +808,7 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
} }
// Initialize backtrack stack pointer. // Initialize backtrack stack pointer.
__ mov(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
__ jmp(&start_label_); __ jmp(&start_label_);
...@@ -855,8 +894,12 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { ...@@ -855,8 +894,12 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
} }
__ bind(&return_eax); __ bind(&return_eax);
// Restore the original regexp stack pointer value (effectively, pop the
// stored base pointer).
PopRegExpBasePointer(ecx, ebx);
// Skip esp past regexp registers. // Skip esp past regexp registers.
__ lea(esp, Operand(ebp, kBackup_ebx)); __ lea(esp, Operand(ebp, kLastCalleeSaveRegister));
// Restore callee-save registers. // Restore callee-save registers.
__ pop(ebx); __ pop(ebx);
__ pop(edi); __ pop(edi);
...@@ -877,7 +920,8 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { ...@@ -877,7 +920,8 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
if (check_preempt_label_.is_linked()) { if (check_preempt_label_.is_linked()) {
SafeCallTarget(&check_preempt_label_); SafeCallTarget(&check_preempt_label_);
__ push(backtrack_stackpointer()); StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi);
__ push(edi); __ push(edi);
CallCheckStackGuardState(ebx); CallCheckStackGuardState(ebx);
...@@ -887,7 +931,9 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { ...@@ -887,7 +931,9 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
__ j(not_zero, &return_eax); __ j(not_zero, &return_eax);
__ pop(edi); __ pop(edi);
__ pop(backtrack_stackpointer());
LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
// String might have moved: Reload esi from frame. // String might have moved: Reload esi from frame.
__ mov(esi, Operand(ebp, kInputEnd)); __ mov(esi, Operand(ebp, kInputEnd));
SafeReturn(); SafeReturn();
...@@ -898,21 +944,19 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) { ...@@ -898,21 +944,19 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
SafeCallTarget(&stack_overflow_label_); SafeCallTarget(&stack_overflow_label_);
// Reached if the backtrack-stack limit has been hit. // Reached if the backtrack-stack limit has been hit.
// Save registers before calling C function // Save registers before calling C function.
__ push(esi); __ push(esi);
__ push(edi); __ push(edi);
// Call GrowStack(backtrack_stackpointer()) StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi);
static const int num_arguments = 3;
__ PrepareCallCFunction(num_arguments, ebx); // Call GrowStack(isolate).
__ mov(Operand(esp, 2 * kSystemPointerSize), static const int kNumArguments = 1;
__ PrepareCallCFunction(kNumArguments, ebx);
__ mov(Operand(esp, 0 * kSystemPointerSize),
Immediate(ExternalReference::isolate_address(isolate()))); Immediate(ExternalReference::isolate_address(isolate())));
__ lea(eax, Operand(ebp, kStackHighEnd)); __ CallCFunction(ExternalReference::re_grow_stack(isolate()),
__ mov(Operand(esp, 1 * kSystemPointerSize), eax); kNumArguments);
__ mov(Operand(esp, 0 * kSystemPointerSize), backtrack_stackpointer());
ExternalReference grow_stack =
ExternalReference::re_grow_stack(isolate());
__ CallCFunction(grow_stack, num_arguments);
// If return nullptr, we have failed to grow the stack, and // If return nullptr, we have failed to grow the stack, and
// must exit with a stack-overflow exception. // must exit with a stack-overflow exception.
__ or_(eax, eax); __ or_(eax, eax);
...@@ -1019,10 +1063,21 @@ void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) { ...@@ -1019,10 +1063,21 @@ void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
__ mov(edi, register_location(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) { void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
__ mov(backtrack_stackpointer(), register_location(reg)); ExternalReference stack_top_address =
__ add(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); 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) { void RegExpMacroAssemblerIA32::SetCurrentPositionFromEnd(int by) {
...@@ -1069,14 +1124,6 @@ void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) { ...@@ -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: // Private methods:
void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) { void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
......
...@@ -114,12 +114,20 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32 ...@@ -114,12 +114,20 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32
static const int kBackup_esi = kFramePointer - kSystemPointerSize; static const int kBackup_esi = kFramePointer - kSystemPointerSize;
static const int kBackup_edi = kBackup_esi - kSystemPointerSize; static const int kBackup_edi = kBackup_esi - kSystemPointerSize;
static const int kBackup_ebx = kBackup_edi - 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 = static const int kStringStartMinusOne =
kSuccessfulCaptures - kSystemPointerSize; kSuccessfulCaptures - kSystemPointerSize;
static const int kBacktrackCount = kStringStartMinusOne - 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. // 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. // Initial size of code buffer.
static const int kRegExpCodeSize = 1024; static const int kRegExpCodeSize = 1024;
...@@ -137,14 +145,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32 ...@@ -137,14 +145,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32
Operand register_location(int register_index); Operand register_location(int register_index);
// The register containing the current character after LoadCurrentCharacter. // 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 // The register containing the backtrack stack top. Provides a meaningful
// name to the register. // 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) // 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 // Equivalent to a conditional branch to the label, unless the label
// is nullptr, in which case it is a conditional Backtrack. // is nullptr, in which case it is a conditional Backtrack.
...@@ -168,19 +176,25 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32 ...@@ -168,19 +176,25 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32
// (ecx) and increments it by a word size. // (ecx) and increments it by a word size.
inline void Pop(Register target); 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(); } 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). // Which mode to generate code for (LATIN1 or UC16).
Mode mode_; const Mode mode_;
// One greater than maximal register index actually used. // One greater than maximal register index actually used.
int num_registers_; int num_registers_;
// Number of registers to output at the end (the saved registers // Number of registers to output at the end (the saved registers
// are always 0..num_saved_registers_-1) // are always 0..num_saved_registers_-1).
int num_saved_registers_; const int num_saved_registers_;
// Labels used internally. // Labels used internally.
Label entry_label_; Label entry_label_;
......
...@@ -308,7 +308,7 @@ int NativeRegExpMacroAssembler::Execute( ...@@ -308,7 +308,7 @@ int NativeRegExpMacroAssembler::Execute(
int* output, int output_size, Isolate* isolate, JSRegExp regexp) { int* output, int output_size, Isolate* isolate, JSRegExp regexp) {
// Ensure that the minimum stack has been allocated. // Ensure that the minimum stack has been allocated.
RegExpStackScope stack_scope(isolate); 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); bool is_one_byte = String::IsOneByteRepresentationUnderneath(input);
Code code = FromCodeT(CodeT::cast(regexp.Code(is_one_byte))); Code code = FromCodeT(CodeT::cast(regexp.Code(is_one_byte)));
...@@ -382,22 +382,23 @@ const byte NativeRegExpMacroAssembler::word_character_map[] = { ...@@ -382,22 +382,23 @@ const byte NativeRegExpMacroAssembler::word_character_map[] = {
}; };
// clang-format on // clang-format on
Address NativeRegExpMacroAssembler::GrowStack(Address stack_pointer, Address NativeRegExpMacroAssembler::GrowStack(Isolate* isolate) {
Address* stack_base, DisallowGarbageCollection no_gc;
Isolate* isolate) {
RegExpStack* regexp_stack = isolate->regexp_stack(); RegExpStack* regexp_stack = isolate->regexp_stack();
size_t size = regexp_stack->stack_capacity(); const size_t old_size = regexp_stack->memory_size();
Address old_stack_base = regexp_stack->stack_base();
DCHECK(old_stack_base == *stack_base); #ifdef DEBUG
DCHECK(stack_pointer <= old_stack_base); const Address old_stack_top = regexp_stack->memory_top();
DCHECK(static_cast<size_t>(old_stack_base - stack_pointer) <= size); const Address old_stack_pointer = regexp_stack->stack_pointer();
Address new_stack_base = regexp_stack->EnsureCapacity(size * 2); CHECK_LE(old_stack_pointer, old_stack_top);
if (new_stack_base == kNullAddress) { CHECK_LE(static_cast<size_t>(old_stack_top - old_stack_pointer), old_size);
return kNullAddress; #endif // DEBUG
}
*stack_base = new_stack_base; Address new_stack_base = regexp_stack->EnsureCapacity(old_size * 2);
intptr_t stack_content_size = old_stack_base - stack_pointer; if (new_stack_base == kNullAddress) return kNullAddress;
return new_stack_base - stack_content_size;
return regexp_stack->stack_pointer();
} }
} // namespace internal } // namespace internal
......
...@@ -281,13 +281,11 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler { ...@@ -281,13 +281,11 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
int* offsets_vector, int offsets_vector_length, int* offsets_vector, int offsets_vector_length,
int previous_index, Isolate* isolate); int previous_index, Isolate* isolate);
// Called from RegExp if the backtrack stack limit is hit. // Called from RegExp if the backtrack stack limit is hit. Tries to expand
// Tries to expand the stack. Returns the new stack-pointer if // the stack. Returns the new stack-pointer if successful, or returns 0 if
// successful, and updates the stack_top address, or returns 0 if unable // unable to grow the stack.
// to grow the stack.
// This function must not trigger a garbage collection. // This function must not trigger a garbage collection.
static Address GrowStack(Address stack_pointer, Address* stack_top, static Address GrowStack(Isolate* isolate);
Isolate* isolate);
static int CheckStackGuardState(Isolate* isolate, int start_index, static int CheckStackGuardState(Isolate* isolate, int start_index,
RegExp::CallOrigin call_origin, RegExp::CallOrigin call_origin,
......
...@@ -11,23 +11,17 @@ namespace v8 { ...@@ -11,23 +11,17 @@ namespace v8 {
namespace internal { namespace internal {
RegExpStackScope::RegExpStackScope(Isolate* isolate) 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()); 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() { RegExpStackScope::~RegExpStackScope() {
// Reset the buffer if it has grown. CHECK_EQ(old_sp_top_delta_, regexp_stack_->sp_top_delta());
regexp_stack_->Reset(); regexp_stack_->ResetIfEmpty();
DCHECK(!regexp_stack_->is_in_use());
} }
RegExpStack::RegExpStack() : thread_local_(this), isolate_(nullptr) {} RegExpStack::RegExpStack() : thread_local_(this) {}
RegExpStack::~RegExpStack() { thread_local_.FreeAndInvalidate(); } RegExpStack::~RegExpStack() { thread_local_.FreeAndInvalidate(); }
...@@ -52,18 +46,16 @@ char* RegExpStack::RestoreStack(char* from) { ...@@ -52,18 +46,16 @@ char* RegExpStack::RestoreStack(char* from) {
return from + kThreadLocalSize; return from + kThreadLocalSize;
} }
void RegExpStack::Reset() { thread_local_.ResetToStaticStack(this); }
void RegExpStack::ThreadLocal::ResetToStaticStack(RegExpStack* regexp_stack) { void RegExpStack::ThreadLocal::ResetToStaticStack(RegExpStack* regexp_stack) {
if (owns_memory_) DeleteArray(memory_); if (owns_memory_) DeleteArray(memory_);
memory_ = regexp_stack->static_stack_; memory_ = regexp_stack->static_stack_;
memory_top_ = regexp_stack->static_stack_ + kStaticStackSize; memory_top_ = regexp_stack->static_stack_ + kStaticStackSize;
memory_size_ = kStaticStackSize; memory_size_ = kStaticStackSize;
stack_pointer_ = memory_top_;
limit_ = reinterpret_cast<Address>(regexp_stack->static_stack_) + limit_ = reinterpret_cast<Address>(regexp_stack->static_stack_) +
kStackLimitSlack * kSystemPointerSize; kStackLimitSlack * kSystemPointerSize;
owns_memory_ = false; owns_memory_ = false;
is_in_use_ = false;
} }
void RegExpStack::ThreadLocal::FreeAndInvalidate() { void RegExpStack::ThreadLocal::FreeAndInvalidate() {
...@@ -74,6 +66,7 @@ void RegExpStack::ThreadLocal::FreeAndInvalidate() { ...@@ -74,6 +66,7 @@ void RegExpStack::ThreadLocal::FreeAndInvalidate() {
memory_ = nullptr; memory_ = nullptr;
memory_top_ = nullptr; memory_top_ = nullptr;
memory_size_ = 0; memory_size_ = 0;
stack_pointer_ = nullptr;
limit_ = kMemoryTop; limit_ = kMemoryTop;
} }
...@@ -88,9 +81,11 @@ Address RegExpStack::EnsureCapacity(size_t size) { ...@@ -88,9 +81,11 @@ Address RegExpStack::EnsureCapacity(size_t size) {
thread_local_.memory_, thread_local_.memory_size_); thread_local_.memory_, thread_local_.memory_size_);
if (thread_local_.owns_memory_) DeleteArray(thread_local_.memory_); if (thread_local_.owns_memory_) DeleteArray(thread_local_.memory_);
} }
ptrdiff_t delta = sp_top_delta();
thread_local_.memory_ = new_memory; thread_local_.memory_ = new_memory;
thread_local_.memory_top_ = new_memory + size; thread_local_.memory_top_ = new_memory + size;
thread_local_.memory_size_ = size; thread_local_.memory_size_ = size;
thread_local_.stack_pointer_ = thread_local_.memory_top_ + delta;
thread_local_.limit_ = reinterpret_cast<Address>(new_memory) + thread_local_.limit_ = reinterpret_cast<Address>(new_memory) +
kStackLimitSlack * kSystemPointerSize; kStackLimitSlack * kSystemPointerSize;
thread_local_.owns_memory_ = true; thread_local_.owns_memory_ = true;
......
...@@ -16,10 +16,7 @@ class RegExpStack; ...@@ -16,10 +16,7 @@ class RegExpStack;
// Maintains a per-v8thread stack area that can be used by irregexp // Maintains a per-v8thread stack area that can be used by irregexp
// implementation for its backtracking stack. // implementation for its backtracking stack.
// Since there is only one stack area, the Irregexp implementation is not class V8_NODISCARD RegExpStackScope final {
// re-entrant. I.e., no regular expressions may be executed in the same thread
// during a preempted Irregexp execution.
class V8_NODISCARD RegExpStackScope {
public: public:
// Create and delete an instance to control the life-time of a growing stack. // Create and delete an instance to control the life-time of a growing stack.
...@@ -32,46 +29,45 @@ class V8_NODISCARD RegExpStackScope { ...@@ -32,46 +29,45 @@ class V8_NODISCARD RegExpStackScope {
RegExpStack* stack() const { return regexp_stack_; } RegExpStack* stack() const { return regexp_stack_; }
private: private:
RegExpStack* regexp_stack_; RegExpStack* const regexp_stack_;
const ptrdiff_t old_sp_top_delta_;
}; };
class RegExpStack { class RegExpStack final {
public: public:
RegExpStack(); RegExpStack();
~RegExpStack(); ~RegExpStack();
RegExpStack(const RegExpStack&) = delete; RegExpStack(const RegExpStack&) = delete;
RegExpStack& operator=(const RegExpStack&) = delete; RegExpStack& operator=(const RegExpStack&) = delete;
// Number of allocated locations on the stack below the limit. // Number of allocated locations on the stack below the limit. No sequence of
// No sequence of pushes must be longer that this without doing a stack-limit // pushes must be longer than this without doing a stack-limit check.
// check.
static constexpr int kStackLimitSlack = 32; static constexpr int kStackLimitSlack = 32;
// Gives the top of the memory used as stack. Address memory_top() const {
Address stack_base() {
DCHECK_NE(0, thread_local_.memory_size_); DCHECK_NE(0, thread_local_.memory_size_);
DCHECK_EQ(thread_local_.memory_top_, DCHECK_EQ(thread_local_.memory_top_,
thread_local_.memory_ + thread_local_.memory_size_); thread_local_.memory_ + thread_local_.memory_size_);
return reinterpret_cast<Address>(thread_local_.memory_top_); return reinterpret_cast<Address>(thread_local_.memory_top_);
} }
// The total size of the memory allocated for the stack. Address stack_pointer() const {
size_t stack_capacity() { return thread_local_.memory_size_; } 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 // If the stack pointer gets below the limit, we should react and
// either grow the stack or report an out-of-stack exception. // either grow the stack or report an out-of-stack exception.
// There is only a limited number of locations below the stack limit, // There is only a limited number of locations below the stack limit,
// so users of the stack should check the stack limit during any // so users of the stack should check the stack limit during any
// sequence of pushes longer that this. // 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. // Ensures that there is a memory area with at least the specified size.
// If passing zero, the default/minimum size buffer is allocated. // If passing zero, the default/minimum size buffer is allocated.
Address EnsureCapacity(size_t size); 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. // Thread local archiving.
static constexpr int ArchiveSpacePerThread() { static constexpr int ArchiveSpacePerThread() {
return static_cast<int>(kThreadLocalSize); return static_cast<int>(kThreadLocalSize);
...@@ -103,44 +99,59 @@ class RegExpStack { ...@@ -103,44 +99,59 @@ class RegExpStack {
STATIC_ASSERT(kStaticStackSize <= kMaximumStackSize); 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 { struct ThreadLocal {
explicit ThreadLocal(RegExpStack* regexp_stack) { explicit ThreadLocal(RegExpStack* regexp_stack) {
ResetToStaticStack(regexp_stack); ResetToStaticStack(regexp_stack);
} }
// If memory_size_ > 0 then memory_ and memory_top_ must be non-nullptr // If memory_size_ > 0 then
// and memory_top_ = memory_ + memory_size_ // - memory_, memory_top_, stack_pointer_ must be non-nullptr
// - memory_top_ = memory_ + memory_size_
// - memory_ <= stack_pointer_ <= memory_top_
byte* memory_ = nullptr; byte* memory_ = nullptr;
byte* memory_top_ = nullptr; byte* memory_top_ = nullptr;
size_t memory_size_ = 0; size_t memory_size_ = 0;
byte* stack_pointer_ = nullptr;
Address limit_ = kNullAddress; Address limit_ = kNullAddress;
bool owns_memory_ = false; // Whether memory_ is owned and must be freed. 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 ResetToStaticStack(RegExpStack* regexp_stack);
void ResetToStaticStackIfEmpty(RegExpStack* regexp_stack) {
if (stack_pointer_ == memory_top_) ResetToStaticStack(regexp_stack);
}
void FreeAndInvalidate(); void FreeAndInvalidate();
}; };
static constexpr size_t kThreadLocalSize = sizeof(ThreadLocal); static constexpr size_t kThreadLocalSize = sizeof(ThreadLocal);
// Address of top of memory used as stack.
Address memory_top_address_address() { Address memory_top_address_address() {
return reinterpret_cast<Address>(&thread_local_.memory_top_); return reinterpret_cast<Address>(&thread_local_.memory_top_);
} }
// Resets the buffer if it has grown beyond the default/minimum size. Address stack_pointer_address() {
// After this, the buffer is either the default size, or it is empty, so return reinterpret_cast<Address>(&thread_local_.stack_pointer_);
// you have to call EnsureCapacity before using it again. }
void Reset();
// 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. // Whether the ThreadLocal storage has been invalidated.
bool IsValid() const { return thread_local_.memory_ != nullptr; } bool IsValid() const { return thread_local_.memory_ != nullptr; }
ThreadLocal thread_local_; ThreadLocal thread_local_;
Isolate* isolate_;
friend class ExternalReference; friend class ExternalReference;
friend class Isolate;
friend class RegExpStackScope; friend class RegExpStackScope;
}; };
......
...@@ -5,9 +5,7 @@ ...@@ -5,9 +5,7 @@
#ifndef V8_REGEXP_X64_REGEXP_MACRO_ASSEMBLER_X64_H_ #ifndef V8_REGEXP_X64_REGEXP_MACRO_ASSEMBLER_X64_H_
#define 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/macro-assembler.h"
#include "src/codegen/x64/assembler-x64.h"
#include "src/regexp/regexp-macro-assembler.h" #include "src/regexp/regexp-macro-assembler.h"
#include "src/zone/zone-chunk-list.h" #include "src/zone/zone-chunk-list.h"
...@@ -133,18 +131,17 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 ...@@ -133,18 +131,17 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64
static const int kIsolate = kDirectCall + kSystemPointerSize; static const int kIsolate = kDirectCall + kSystemPointerSize;
#endif #endif
// We push callee-save registers that we use after the frame pointer (and
// after the parameters).
#ifdef V8_TARGET_OS_WIN #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_rsi = kFramePointer - kSystemPointerSize;
static const int kBackup_rdi = kBackup_rsi - kSystemPointerSize; static const int kBackup_rdi = kBackup_rsi - kSystemPointerSize;
static const int kBackup_rbx = kBackup_rdi - kSystemPointerSize; static const int kBackup_rbx = kBackup_rdi - kSystemPointerSize;
static const int kNumCalleeSaveRegisters = 3;
static const int kLastCalleeSaveRegister = kBackup_rbx; static const int kLastCalleeSaveRegister = kBackup_rbx;
#else #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 kBackup_rbx = kNumOutputRegisters - kSystemPointerSize;
static const int kNumCalleeSaveRegisters = 1;
static const int kLastCalleeSaveRegister = kBackup_rbx; static const int kLastCalleeSaveRegister = kBackup_rbx;
#endif #endif
...@@ -155,9 +152,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 ...@@ -155,9 +152,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64
static const int kStringStartMinusOne = static const int kStringStartMinusOne =
kSuccessfulCaptures - kSystemPointerSize; kSuccessfulCaptures - kSystemPointerSize;
static const int kBacktrackCount = kStringStartMinusOne - 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. // 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. // Initial size of code buffer.
static const int kRegExpCodeSize = 1024; static const int kRegExpCodeSize = 1024;
...@@ -175,14 +177,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 ...@@ -175,14 +177,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64
Operand register_location(int register_index); Operand register_location(int register_index);
// The register containing the current character after LoadCurrentCharacter. // 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 // The register containing the backtrack stack top. Provides a meaningful
// name to the register. // 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. // 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) // 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() { return static_cast<int>(mode_); }
...@@ -224,24 +226,36 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 ...@@ -224,24 +226,36 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64
// Increments the stack pointer (rcx) by a word size. // Increments the stack pointer (rcx) by a word size.
inline void Drop(); 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); inline void ReadPositionFromRegister(Register dst, int reg);
Isolate* isolate() const { return masm_.isolate(); } Isolate* isolate() const { return masm_.isolate(); }
MacroAssembler masm_; 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_; ZoneChunkList<int> code_relative_fixup_positions_;
// Which mode to generate code for (LATIN1 or UC16). // Which mode to generate code for (LATIN1 or UC16).
Mode mode_; const Mode mode_;
// One greater than maximal register index actually used. // One greater than maximal register index actually used.
int num_registers_; int num_registers_;
// Number of registers to output at the end (the saved registers // Number of registers to output at the end (the saved registers
// are always 0..num_saved_registers_-1) // are always 0..num_saved_registers_-1)
int num_saved_registers_; const int num_saved_registers_;
// Labels used internally. // Labels used internally.
Label entry_label_; Label entry_label_;
......
...@@ -136,9 +136,6 @@ ...@@ -136,9 +136,6 @@
'test-strings/Traverse': [PASS, HEAVY], 'test-strings/Traverse': [PASS, HEAVY],
'test-swiss-name-dictionary-csa/DeleteAtBoundaries': [PASS, HEAVY], 'test-swiss-name-dictionary-csa/DeleteAtBoundaries': [PASS, HEAVY],
'test-swiss-name-dictionary-csa/SameH2': [PASS, HEAVY], 'test-swiss-name-dictionary-csa/SameH2': [PASS, HEAVY],
# TODO(v8:11382): Reenable once irregexp is reentrant.
'test-regexp/RegExpInterruptReentrantExecution': [FAIL],
}], # ALWAYS }], # ALWAYS
############################################################################## ##############################################################################
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment