From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jakob Gruber Date: Thu, 23 Sep 2021 07:26:38 +0200 Subject: Allow reentrant irregexp execution .. by reusing the regexp stack from potentially multiple nested irregexp activations. To do this, we now maintain a stack pointer in RegExpStack. This stack pointer is synchronized at all boundaries between generated irregexp code and the outside world, i.e. when entering or returning from irregexp code, and when calling into C functions such as GrowStack. Fixed: v8:11382 Change-Id: I5ed27630c1a64ebf3afb9ddf80fb60ea067c0c40 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3162604 Reviewed-by: Toon Verwaest Reviewed-by: Patrick Thier Commit-Queue: Toon Verwaest Auto-Submit: Jakob Gruber Cr-Commit-Position: refs/heads/main@{#77013} diff --git a/src/api/api.cc b/src/api/api.cc index 97b0804562c7cd60791901fa9a8d48ff07c1abbf..f43dfaf5ef10f83416a915952439c0e97656904d 100644 --- a/src/api/api.cc +++ b/src/api/api.cc @@ -107,7 +107,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 2c7748f223c9359079b2c35b55aeaa04810eff85..770653d50ce129452829c43ef5cee3648f2f52aa 100644 --- a/src/codegen/external-reference.cc +++ b/src/codegen/external-reference.cc @@ -740,6 +740,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 9c25064572112b649c108a89df3c83b29ac603a0..229e4ca8d8770a698dfb21606b29ac7ac0018dc2 100644 --- a/src/debug/debug-interface.cc +++ b/src/debug/debug-interface.cc @@ -17,7 +17,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 @@ -304,10 +303,7 @@ void SetTerminateOnResume(Isolate* v8_isolate) { bool CanBreakProgram(Isolate* v8_isolate) { i::Isolate* isolate = reinterpret_cast(v8_isolate); ENTER_V8_DO_NOT_USE(isolate); - // We cannot break a program if we are currently running a regexp. - // TODO(yangguo): fix this exception. - return !isolate->regexp_stack()->is_in_use() && - isolate->debug()->AllFramesOnStackAreBlackboxed(); + return isolate->debug()->AllFramesOnStackAreBlackboxed(); } Isolate* Script::GetIsolate() const { diff --git a/src/execution/isolate.cc b/src/execution/isolate.cc index eaf3096ac6bb05d61d93012d5b7abec503a3259e..051e58263cb66b1ad2dc1b59143d5826e0dfe376 100644 --- a/src/execution/isolate.cc +++ b/src/execution/isolate.cc @@ -3591,7 +3591,6 @@ bool Isolate::Init(SnapshotData* startup_snapshot_data, store_stub_cache_ = new StubCache(this); materialized_object_store_ = new MaterializedObjectStore(this); regexp_stack_ = new RegExpStack(); - regexp_stack_->isolate_ = this; date_cache_ = new DateCache(); heap_profiler_ = new HeapProfiler(heap()); interpreter_ = new interpreter::Interpreter(this); diff --git a/src/regexp/arm/regexp-macro-assembler-arm.cc b/src/regexp/arm/regexp-macro-assembler-arm.cc index 6c90e00817342a115ec49a21b561a7014e0ce8f8..10766db4cf1d41ad0fee0754c6eaeebe46ace500 100644 --- a/src/regexp/arm/regexp-macro-assembler-arm.cc +++ b/src/regexp/arm/regexp-macro-assembler-arm.cc @@ -6,15 +6,13 @@ #include "src/regexp/arm/regexp-macro-assembler-arm.h" -#include "src/codegen/assembler-inl.h" +#include "src/codegen/arm/assembler-arm-inl.h" #include "src/codegen/macro-assembler.h" #include "src/heap/factory.h" #include "src/logging/log.h" -#include "src/objects/objects-inl.h" -#include "src/regexp/regexp-macro-assembler.h" +#include "src/objects/code-inl.h" #include "src/regexp/regexp-stack.h" #include "src/snapshot/embedded/embedded-data.h" -#include "src/strings/unicode.h" namespace v8 { namespace internal { @@ -102,6 +100,7 @@ RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(Isolate* isolate, Zone* zone, : NativeRegExpMacroAssembler(isolate, zone), masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes, NewAssemblerBuffer(kRegExpCodeSize))), + no_root_array_scope_(masm_), mode_(mode), num_registers_(registers_to_save), num_saved_registers_(registers_to_save), @@ -110,8 +109,6 @@ RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(Isolate* isolate, Zone* zone, success_label_(), backtrack_label_(), exit_label_() { - masm_->set_root_array_available(false); - DCHECK_EQ(0, registers_to_save % 2); __ jmp(&entry_label_); // We'll write the entry code later. __ bind(&start_label_); // And then continue from here. @@ -619,6 +616,42 @@ void RegExpMacroAssemblerARM::Fail() { __ jmp(&exit_label_); } +void RegExpMacroAssemblerARM::LoadRegExpStackPointerFromMemory(Register dst) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); + __ mov(dst, Operand(ref)); + __ ldr(dst, MemOperand(dst)); +} + +void RegExpMacroAssemblerARM::StoreRegExpStackPointerToMemory( + Register src, Register scratch) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); + __ mov(scratch, Operand(ref)); + __ str(src, MemOperand(scratch)); +} + +void RegExpMacroAssemblerARM::PushRegExpBasePointer(Register scratch1, + Register scratch2) { + LoadRegExpStackPointerFromMemory(scratch1); + ExternalReference ref = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ mov(scratch2, Operand(ref)); + __ ldr(scratch2, MemOperand(scratch2)); + __ sub(scratch2, scratch1, scratch2); + __ str(scratch2, MemOperand(frame_pointer(), kRegExpStackBasePointer)); +} + +void RegExpMacroAssemblerARM::PopRegExpBasePointer(Register scratch1, + Register scratch2) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ ldr(scratch1, MemOperand(frame_pointer(), kRegExpStackBasePointer)); + __ mov(scratch2, Operand(ref)); + __ ldr(scratch2, MemOperand(scratch2)); + __ add(scratch1, scratch1, scratch2); + StoreRegExpStackPointerToMemory(scratch1, scratch2); +} Handle RegExpMacroAssemblerARM::GetCode(Handle source) { Label return_r0; @@ -654,6 +687,13 @@ Handle RegExpMacroAssemblerARM::GetCode(Handle source) { __ push(r0); // Make room for "string start - 1" constant. STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize); __ push(r0); // The backtrack counter. + STATIC_ASSERT(kRegExpStackBasePointer == + kBacktrackCount - kSystemPointerSize); + __ push(r0); // The regexp stack base ptr. + + // Store the regexp base pointer - we'll later restore it / write it to + // memory when returning from this irregexp code object. + PushRegExpBasePointer(r0, r1); // Check if we have space on the stack for registers. Label stack_limit_hit; @@ -736,7 +776,7 @@ Handle RegExpMacroAssemblerARM::GetCode(Handle source) { } // Initialize backtrack stack pointer. - __ ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd)); + LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); __ jmp(&start_label_); @@ -834,6 +874,10 @@ Handle RegExpMacroAssemblerARM::GetCode(Handle source) { } __ bind(&return_r0); + // Restore the original regexp stack pointer value (effectively, pop the + // stored base pointer). + PopRegExpBasePointer(r1, r2); + // Skip sp past regexp registers and local variables.. __ mov(sp, frame_pointer()); // Restore registers r4..r11 and return (restoring lr to pc). @@ -851,12 +895,16 @@ Handle RegExpMacroAssemblerARM::GetCode(Handle source) { if (check_preempt_label_.is_linked()) { SafeCallTarget(&check_preempt_label_); + StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r1); + CallCheckStackGuardState(); __ cmp(r0, Operand::Zero()); // If returning non-zero, we should end execution with the given // result as return value. __ b(ne, &return_r0); + LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); + // String might have moved: Reload end of string from frame. __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); SafeReturn(); @@ -867,17 +915,18 @@ Handle RegExpMacroAssemblerARM::GetCode(Handle source) { SafeCallTarget(&stack_overflow_label_); // Reached if the backtrack-stack limit has been hit. - // Call GrowStack(backtrack_stackpointer(), &stack_base) - static const int num_arguments = 3; - __ PrepareCallCFunction(num_arguments); - __ mov(r0, backtrack_stackpointer()); - __ add(r1, frame_pointer(), Operand(kStackHighEnd)); - __ mov(r2, Operand(ExternalReference::isolate_address(isolate()))); + // Call GrowStack(isolate). + + StoreRegExpStackPointerToMemory(backtrack_stackpointer(), r1); + + static constexpr int kNumArguments = 1; + __ PrepareCallCFunction(kNumArguments); + __ mov(r0, Operand(ExternalReference::isolate_address(isolate()))); ExternalReference grow_stack = ExternalReference::re_grow_stack(isolate()); - __ CallCFunction(grow_stack, num_arguments); - // If return nullptr, we have failed to grow the stack, and - // must exit with a stack-overflow exception. + __ CallCFunction(grow_stack, kNumArguments); + // If nullptr is returned, we have failed to grow the stack, and must exit + // with a stack-overflow exception. __ cmp(r0, Operand::Zero()); __ b(eq, &exit_with_exception); // Otherwise use return value as new stack pointer. @@ -984,14 +1033,24 @@ void RegExpMacroAssemblerARM::ReadCurrentPositionFromRegister(int reg) { __ ldr(current_input_offset(), register_location(reg)); } +void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ mov(r1, Operand(ref)); + __ ldr(r1, MemOperand(r1)); + __ sub(r0, backtrack_stackpointer(), r1); + __ str(r0, register_location(reg)); +} void RegExpMacroAssemblerARM::ReadStackPointerFromRegister(int reg) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ mov(r0, Operand(ref)); + __ ldr(r0, MemOperand(r0)); __ ldr(backtrack_stackpointer(), register_location(reg)); - __ ldr(r0, MemOperand(frame_pointer(), kStackHighEnd)); - __ add(backtrack_stackpointer(), backtrack_stackpointer(), Operand(r0)); + __ add(backtrack_stackpointer(), backtrack_stackpointer(), r0); } - void RegExpMacroAssemblerARM::SetCurrentPositionFromEnd(int by) { Label after_position; __ cmp(current_input_offset(), Operand(-by * char_size())); @@ -1037,14 +1096,6 @@ void RegExpMacroAssemblerARM::ClearRegisters(int reg_from, int reg_to) { } } - -void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) { - __ ldr(r1, MemOperand(frame_pointer(), kStackHighEnd)); - __ sub(r0, backtrack_stackpointer(), r1); - __ str(r0, register_location(reg)); -} - - // Private methods: void RegExpMacroAssemblerARM::CallCheckStackGuardState() { diff --git a/src/regexp/arm/regexp-macro-assembler-arm.h b/src/regexp/arm/regexp-macro-assembler-arm.h index a02a4dc2af546e53a89161aad9f3500a51c062f8..a76f9dea70264d79d57ebd6c60b100bc9e0a499d 100644 --- a/src/regexp/arm/regexp-macro-assembler-arm.h +++ b/src/regexp/arm/regexp-macro-assembler-arm.h @@ -5,8 +5,6 @@ #ifndef V8_REGEXP_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_ #define V8_REGEXP_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_ -#include "src/base/strings.h" -#include "src/codegen/arm/assembler-arm.h" #include "src/codegen/macro-assembler.h" #include "src/regexp/regexp-macro-assembler.h" @@ -115,8 +113,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM static const int kSuccessfulCaptures = kInputString - kPointerSize; static const int kStringStartMinusOne = kSuccessfulCaptures - kPointerSize; static const int kBacktrackCount = kStringStartMinusOne - kSystemPointerSize; + // Stores the initial value of the regexp stack pointer in a + // position-independent representation (in case the regexp stack grows and + // thus moves). + static const int kRegExpStackBasePointer = + kBacktrackCount - kSystemPointerSize; + // First register address. Following registers are below it on the stack. - static const int kRegisterZero = kBacktrackCount - kSystemPointerSize; + static const int kRegisterZero = kRegExpStackBasePointer - kSystemPointerSize; // Initial size of code buffer. static const int kRegExpCodeSize = 1024; @@ -129,7 +133,6 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM // Check whether we are exceeding the stack limit on the backtrack stack. void CheckStackLimit(); - // Generate a call to CheckStackGuardState. void CallCheckStackGuardState(); @@ -138,27 +141,27 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM // Register holding the current input position as negative offset from // the end of the string. - inline Register current_input_offset() { return r6; } + static constexpr Register current_input_offset() { return r6; } // The register containing the current character after LoadCurrentCharacter. - inline Register current_character() { return r7; } + static constexpr Register current_character() { return r7; } // Register holding address of the end of the input string. - inline Register end_of_input_address() { return r10; } + static constexpr Register end_of_input_address() { return r10; } // Register holding the frame address. Local variables, parameters and // regexp registers are addressed relative to this. - inline Register frame_pointer() { return fp; } + static constexpr Register frame_pointer() { return fp; } // The register containing the backtrack stack top. Provides a meaningful // name to the register. - inline Register backtrack_stackpointer() { return r8; } + static constexpr Register backtrack_stackpointer() { return r8; } // Register holding pointer to the current code object. - inline Register code_pointer() { return r5; } + static constexpr Register code_pointer() { return r5; } // Byte size of chars in the string to match (decided by the Mode argument) - inline int char_size() { return static_cast(mode_); } + inline int char_size() const { return static_cast(mode_); } // Equivalent to a conditional branch to the label, unless the label // is nullptr, in which case it is a conditional Backtrack. @@ -178,19 +181,25 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM // and increments it by a word size. inline void Pop(Register target); + void LoadRegExpStackPointerFromMemory(Register dst); + void StoreRegExpStackPointerToMemory(Register src, Register scratch); + void PushRegExpBasePointer(Register scratch1, Register scratch2); + void PopRegExpBasePointer(Register scratch1, Register scratch2); + Isolate* isolate() const { return masm_->isolate(); } - MacroAssembler* masm_; + MacroAssembler* const masm_; + const NoRootArrayScope no_root_array_scope_; // Which mode to generate code for (Latin1 or UC16). - Mode mode_; + const Mode mode_; // One greater than maximal register index actually used. int num_registers_; // Number of registers to output at the end (the saved registers // are always 0..num_saved_registers_-1) - int num_saved_registers_; + const int num_saved_registers_; // Labels used internally. Label entry_label_; diff --git a/src/regexp/arm64/regexp-macro-assembler-arm64.cc b/src/regexp/arm64/regexp-macro-assembler-arm64.cc index 67793ffc411ccb9c32f67fff393e6b77d094b325..6192461fa32879469d56d36fb788b5de33038d77 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); @@ -699,6 +698,42 @@ void RegExpMacroAssemblerARM64::Fail() { __ B(&exit_label_); } +void RegExpMacroAssemblerARM64::LoadRegExpStackPointerFromMemory(Register dst) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); + __ Mov(dst, ref); + __ Ldr(dst, MemOperand(dst)); +} + +void RegExpMacroAssemblerARM64::StoreRegExpStackPointerToMemory( + Register src, Register scratch) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); + __ Mov(scratch, ref); + __ Str(src, MemOperand(scratch)); +} + +void RegExpMacroAssemblerARM64::PushRegExpBasePointer(Register scratch1, + Register scratch2) { + LoadRegExpStackPointerFromMemory(scratch1); + ExternalReference ref = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ Mov(scratch2, ref); + __ Ldr(scratch2, MemOperand(scratch2)); + __ Sub(scratch2, scratch1, scratch2); + __ Str(scratch2, MemOperand(frame_pointer(), kRegExpStackBasePointer)); +} + +void RegExpMacroAssemblerARM64::PopRegExpBasePointer(Register scratch1, + Register scratch2) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ Ldr(scratch1, MemOperand(frame_pointer(), kRegExpStackBasePointer)); + __ Mov(scratch2, ref); + __ Ldr(scratch2, MemOperand(scratch2)); + __ Add(scratch1, scratch1, scratch2); + StoreRegExpStackPointerToMemory(scratch1, scratch2); +} Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { Label return_w0; @@ -744,22 +779,27 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { __ Mov(input_end(), x3); __ Mov(output_array(), x4); - // Set the number of registers we will need to allocate, that is: - // - kSuccessCounter / success_counter (X register) - // - kBacktrackCount (X register) - // - (num_registers_ - kNumCachedRegisters) (W registers) - int num_wreg_to_allocate = num_registers_ - kNumCachedRegisters; - // Do not allocate registers on the stack if they can all be cached. - if (num_wreg_to_allocate < 0) { num_wreg_to_allocate = 0; } - // Make room for the success_counter and kBacktrackCount. Each X (64-bit) - // register is equivalent to two W (32-bit) registers. - num_wreg_to_allocate += 2 + 2; - // Make sure the stack alignment will be respected. - int alignment = masm_->ActivationFrameAlignment(); + const int alignment = masm_->ActivationFrameAlignment(); DCHECK_EQ(alignment % 16, 0); - int align_mask = (alignment / kWRegSize) - 1; - num_wreg_to_allocate = (num_wreg_to_allocate + align_mask) & ~align_mask; + const int align_mask = (alignment / kWRegSize) - 1; + + // Make room for stack locals. + static constexpr int kWRegPerXReg = kXRegSize / kWRegSize; + DCHECK_EQ(kNumberOfStackLocals * kWRegPerXReg, + ((kNumberOfStackLocals * kWRegPerXReg) + align_mask) & ~align_mask); + __ Claim(kNumberOfStackLocals * kWRegPerXReg); + + // Store the regexp base pointer - we'll later restore it / write it to + // memory when returning from this irregexp code object. + PushRegExpBasePointer(x10, x11); + + // Set the number of registers we will need to allocate, that is: + // - (num_registers_ - kNumCachedRegisters) (W registers) + const int num_stack_registers = + std::max(0, num_registers_ - kNumCachedRegisters); + const int num_wreg_to_allocate = + (num_stack_registers + align_mask) & ~align_mask; // Check if we have space on the stack. Label stack_limit_hit; @@ -839,9 +879,9 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { } // Initialize backtrack stack pointer. - __ Ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackBase)); + LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); - // Execute + // Execute. __ B(&start_label_); if (backtrack_label_.is_linked()) { @@ -1013,7 +1053,7 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { } if (exit_label_.is_linked()) { - // Exit and return w0 + // Exit and return w0. __ Bind(&exit_label_); if (global()) { __ Ldr(w0, MemOperand(frame_pointer(), kSuccessCounter)); @@ -1021,8 +1061,11 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { } __ Bind(&return_w0); + // Restore the original regexp stack pointer value (effectively, pop the + // stored base pointer). + PopRegExpBasePointer(x10, x11); - // Set stack pointer back to first register to retain + // Set stack pointer back to first register to retain. __ Mov(sp, fp); __ Pop(fp, lr); @@ -1039,6 +1082,9 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { if (check_preempt_label_.is_linked()) { __ Bind(&check_preempt_label_); + + StoreRegExpStackPointerToMemory(backtrack_stackpointer(), x10); + SaveLinkRegister(); // The cached registers need to be retained. __ PushCPURegList(cached_registers); @@ -1048,26 +1094,30 @@ Handle RegExpMacroAssemblerARM64::GetCode(Handle source) { __ Cbnz(w0, &return_w0); // Reset the cached registers. __ PopCPURegList(cached_registers); + + LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); + RestoreLinkRegister(); __ Ret(); } if (stack_overflow_label_.is_linked()) { __ Bind(&stack_overflow_label_); + + StoreRegExpStackPointerToMemory(backtrack_stackpointer(), x10); + SaveLinkRegister(); // The cached registers need to be retained. __ PushCPURegList(cached_registers); - // Call GrowStack(backtrack_stackpointer(), &stack_base) - __ Mov(x2, ExternalReference::isolate_address(isolate())); - __ Add(x1, frame_pointer(), kStackBase); - __ Mov(x0, backtrack_stackpointer()); - ExternalReference grow_stack = - ExternalReference::re_grow_stack(isolate()); - __ CallCFunction(grow_stack, 3); - // If return nullptr, we have failed to grow the stack, and - // must exit with a stack-overflow exception. - // Returning from the regexp code restores the stack (sp <- fp) - // so we don't need to drop the link register from it before exiting. + // Call GrowStack(isolate) + static constexpr int kNumArguments = 1; + __ Mov(x0, ExternalReference::isolate_address(isolate())); + __ CallCFunction(ExternalReference::re_grow_stack(isolate()), + kNumArguments); + // If return nullptr, we have failed to grow the stack, and must exit with + // a stack-overflow exception. Returning from the regexp code restores the + // stack (sp <- fp) so we don't need to drop the link register from it + // before exiting. __ Cbz(w0, &exit_with_exception); // Otherwise use return value as new stack pointer. __ Mov(backtrack_stackpointer(), x0); @@ -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) { + 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()); @@ -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. template static T& frame_entry(Address re_frame, int frame_offset) { diff --git a/src/regexp/arm64/regexp-macro-assembler-arm64.h b/src/regexp/arm64/regexp-macro-assembler-arm64.h index 80931e3ca42f7d85a3dea067ca203b252a0f78f0..204ee68dc868142693e9959170c71df3f72f97ce 100644 --- a/src/regexp/arm64/regexp-macro-assembler-arm64.h +++ b/src/regexp/arm64/regexp-macro-assembler-arm64.h @@ -110,18 +110,28 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 // Below the frame pointer. // Register parameters stored by setup code. static const int kDirectCall = -kSystemPointerSize; - static const int kStackBase = kDirectCall - kSystemPointerSize; - static const int kOutputSize = kStackBase - kSystemPointerSize; + static const int kStackHighEnd = kDirectCall - kSystemPointerSize; + static const int kOutputSize = kStackHighEnd - kSystemPointerSize; static const int kInput = kOutputSize - kSystemPointerSize; // When adding local variables remember to push space for them in // the frame in GetCode. static const int kSuccessCounter = kInput - kSystemPointerSize; static const int kBacktrackCount = kSuccessCounter - kSystemPointerSize; + // Stores the initial value of the regexp stack pointer in a + // position-independent representation (in case the regexp stack grows and + // thus moves). + static const int kRegExpStackBasePointer = + kBacktrackCount - kSystemPointerSize; + // A padding slot to preserve alignment. + static const int kStackLocalPadding = + kRegExpStackBasePointer - kSystemPointerSize; + static constexpr int kNumberOfStackLocals = 4; + // First position register address on the stack. Following positions are // below it. A position is a 32 bit value. - static const int kFirstRegisterOnStack = kBacktrackCount - kWRegSize; + static const int kFirstRegisterOnStack = kStackLocalPadding - kWRegSize; // A capture is a 64 bit value holding two position. - static const int kFirstCaptureOnStack = kBacktrackCount - kXRegSize; + static const int kFirstCaptureOnStack = kStackLocalPadding - kXRegSize; // Initial size of code buffer. static const int kRegExpCodeSize = 1024; @@ -152,43 +162,43 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 // Register holding the current input position as negative offset from // the end of the string. - Register current_input_offset() { return w21; } + static constexpr Register current_input_offset() { return w21; } // The register containing the current character after LoadCurrentCharacter. - Register current_character() { return w22; } + static constexpr Register current_character() { return w22; } // Register holding address of the end of the input string. - Register input_end() { return x25; } + static constexpr Register input_end() { return x25; } // Register holding address of the start of the input string. - Register input_start() { return x26; } + static constexpr Register input_start() { return x26; } // Register holding the offset from the start of the string where we should // start matching. - Register start_offset() { return w27; } + static constexpr Register start_offset() { return w27; } // Pointer to the output array's first element. - Register output_array() { return x28; } + static constexpr Register output_array() { return x28; } // Register holding the frame address. Local variables, parameters and // regexp registers are addressed relative to this. - Register frame_pointer() { return fp; } + static constexpr Register frame_pointer() { return fp; } // The register containing the backtrack stack top. Provides a meaningful // name to the register. - Register backtrack_stackpointer() { return x23; } + static constexpr Register backtrack_stackpointer() { return x23; } // Register holding pointer to the current code object. - Register code_pointer() { return x20; } + static constexpr Register code_pointer() { return x20; } // Register holding the value used for clearing capture registers. - Register string_start_minus_one() { return w24; } + static constexpr Register string_start_minus_one() { return w24; } // The top 32 bit of this register is used to store this value // twice. This is used for clearing more than one register at a time. - Register twice_non_position_value() { return x24; } + static constexpr Register twice_non_position_value() { return x24; } // Byte size of chars in the string to match (decided by the Mode argument) - int char_size() { return static_cast(mode_); } + int char_size() const { return static_cast(mode_); } // Equivalent to a conditional branch to the label, unless the label // is nullptr, in which case it is a conditional Backtrack. @@ -254,19 +264,25 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerARM64 // This assumes that the state of the register is not STACKED. inline Register GetCachedRegister(int register_index); + void LoadRegExpStackPointerFromMemory(Register dst); + void StoreRegExpStackPointerToMemory(Register src, Register scratch); + void PushRegExpBasePointer(Register scratch1, Register scratch2); + void PopRegExpBasePointer(Register scratch1, Register scratch2); + Isolate* isolate() const { return masm_->isolate(); } - MacroAssembler* masm_; + MacroAssembler* const masm_; + const NoRootArrayScope no_root_array_scope_; // Which mode to generate code for (LATIN1 or UC16). - Mode mode_; + const Mode mode_; // One greater than maximal register index actually used. int num_registers_; // Number of registers to output at the end (the saved registers // are always 0..num_saved_registers_-1) - int num_saved_registers_; + const int num_saved_registers_; // Labels used internally. Label entry_label_; diff --git a/src/regexp/ia32/regexp-macro-assembler-ia32.cc b/src/regexp/ia32/regexp-macro-assembler-ia32.cc index 6af1d02eed36af46a7e0d819d006361f51411ba6..51d63b2531e2bc85fb115de23d7b6a6f40b36f11 100644 --- a/src/regexp/ia32/regexp-macro-assembler-ia32.cc +++ b/src/regexp/ia32/regexp-macro-assembler-ia32.cc @@ -90,6 +90,7 @@ RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(Isolate* isolate, Zone* zone, : NativeRegExpMacroAssembler(isolate, zone), masm_(new MacroAssembler(isolate, CodeObjectRequired::kYes, NewAssemblerBuffer(kRegExpCodeSize))), + no_root_array_scope_(masm_), mode_(mode), num_registers_(registers_to_save), num_saved_registers_(registers_to_save), @@ -98,9 +99,6 @@ RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(Isolate* isolate, Zone* zone, success_label_(), backtrack_label_(), exit_label_() { - // Irregexp code clobbers ebx and spills/restores it at all boundaries. - masm_->set_root_array_available(false); - DCHECK_EQ(0, registers_to_save % 2); __ jmp(&entry_label_); // We'll write the entry code later. __ bind(&start_label_); // And then continue from here. @@ -655,6 +653,38 @@ void RegExpMacroAssemblerIA32::Fail() { __ jmp(&exit_label_); } +void RegExpMacroAssemblerIA32::LoadRegExpStackPointerFromMemory(Register dst) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); + __ mov(dst, __ ExternalReferenceAsOperand(ref, dst)); +} + +void RegExpMacroAssemblerIA32::StoreRegExpStackPointerToMemory( + Register src, Register scratch) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); + __ mov(__ ExternalReferenceAsOperand(ref, scratch), src); +} + +void RegExpMacroAssemblerIA32::PushRegExpBasePointer(Register scratch1, + Register scratch2) { + LoadRegExpStackPointerFromMemory(scratch1); + ExternalReference ref = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ mov(scratch2, __ ExternalReferenceAsOperand(ref, scratch2)); + __ sub(scratch1, scratch2); + __ mov(Operand(ebp, kRegExpStackBasePointer), scratch1); +} + +void RegExpMacroAssemblerIA32::PopRegExpBasePointer(Register scratch1, + Register scratch2) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ mov(scratch1, Operand(ebp, kRegExpStackBasePointer)); + __ mov(scratch2, __ ExternalReferenceAsOperand(ref, scratch2)); + __ add(scratch1, scratch2); + StoreRegExpStackPointerToMemory(scratch1, scratch2); +} Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { Label return_eax; @@ -676,14 +706,23 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { __ push(esi); __ push(edi); __ push(ebx); // Callee-save on MacOS. + STATIC_ASSERT(kLastCalleeSaveRegister == kBackup_ebx); - STATIC_ASSERT(kSuccessfulCaptures == kBackup_ebx - kSystemPointerSize); + STATIC_ASSERT(kSuccessfulCaptures == + kLastCalleeSaveRegister - kSystemPointerSize); __ push(Immediate(0)); // Number of successful matches in a global regexp. STATIC_ASSERT(kStringStartMinusOne == kSuccessfulCaptures - kSystemPointerSize); __ push(Immediate(0)); // Make room for "string start - 1" constant. STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize); __ push(Immediate(0)); // The backtrack counter. + STATIC_ASSERT(kRegExpStackBasePointer == + kBacktrackCount - kSystemPointerSize); + __ push(Immediate(0)); // The regexp stack base ptr. + + // Store the regexp base pointer - we'll later restore it / write it to + // memory when returning from this irregexp code object. + PushRegExpBasePointer(ecx, eax); // Check if we have space on the stack for registers. Label stack_limit_hit; @@ -769,7 +808,7 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { } // Initialize backtrack stack pointer. - __ mov(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); + LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); __ jmp(&start_label_); @@ -855,8 +894,12 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { } __ bind(&return_eax); + // Restore the original regexp stack pointer value (effectively, pop the + // stored base pointer). + PopRegExpBasePointer(ecx, ebx); + // Skip esp past regexp registers. - __ lea(esp, Operand(ebp, kBackup_ebx)); + __ lea(esp, Operand(ebp, kLastCalleeSaveRegister)); // Restore callee-save registers. __ pop(ebx); __ pop(edi); @@ -877,7 +920,8 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { if (check_preempt_label_.is_linked()) { SafeCallTarget(&check_preempt_label_); - __ push(backtrack_stackpointer()); + StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi); + __ push(edi); CallCheckStackGuardState(ebx); @@ -887,7 +931,9 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { __ j(not_zero, &return_eax); __ pop(edi); - __ pop(backtrack_stackpointer()); + + LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); + // String might have moved: Reload esi from frame. __ mov(esi, Operand(ebp, kInputEnd)); SafeReturn(); @@ -898,21 +944,19 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { SafeCallTarget(&stack_overflow_label_); // Reached if the backtrack-stack limit has been hit. - // Save registers before calling C function + // Save registers before calling C function. __ push(esi); __ push(edi); - // Call GrowStack(backtrack_stackpointer()) - static const int num_arguments = 3; - __ PrepareCallCFunction(num_arguments, ebx); - __ mov(Operand(esp, 2 * kSystemPointerSize), + StoreRegExpStackPointerToMemory(backtrack_stackpointer(), edi); + + // Call GrowStack(isolate). + static const int kNumArguments = 1; + __ PrepareCallCFunction(kNumArguments, ebx); + __ mov(Operand(esp, 0 * kSystemPointerSize), Immediate(ExternalReference::isolate_address(isolate()))); - __ lea(eax, Operand(ebp, kStackHighEnd)); - __ mov(Operand(esp, 1 * kSystemPointerSize), eax); - __ mov(Operand(esp, 0 * kSystemPointerSize), backtrack_stackpointer()); - ExternalReference grow_stack = - ExternalReference::re_grow_stack(isolate()); - __ CallCFunction(grow_stack, num_arguments); + __ CallCFunction(ExternalReference::re_grow_stack(isolate()), + kNumArguments); // If return nullptr, we have failed to grow the stack, and // must exit with a stack-overflow exception. __ or_(eax, eax); @@ -1019,10 +1063,21 @@ void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) { __ mov(edi, register_location(reg)); } +void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) { + ExternalReference stack_top_address = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ mov(eax, __ ExternalReferenceAsOperand(stack_top_address, eax)); + __ sub(eax, backtrack_stackpointer()); + __ mov(register_location(reg), eax); +} void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) { - __ mov(backtrack_stackpointer(), register_location(reg)); - __ add(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); + ExternalReference stack_top_address = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ mov(backtrack_stackpointer(), + __ ExternalReferenceAsOperand(stack_top_address, + backtrack_stackpointer())); + __ sub(backtrack_stackpointer(), register_location(reg)); } void RegExpMacroAssemblerIA32::SetCurrentPositionFromEnd(int by) { @@ -1069,14 +1124,6 @@ void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) { } } - -void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) { - __ mov(eax, backtrack_stackpointer()); - __ sub(eax, Operand(ebp, kStackHighEnd)); - __ mov(register_location(reg), eax); -} - - // Private methods: void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) { diff --git a/src/regexp/ia32/regexp-macro-assembler-ia32.h b/src/regexp/ia32/regexp-macro-assembler-ia32.h index 93fb2c9aba32ab48e335c41dd9dbe0bac94d73ed..861795da900d91111386e4f8e660f7f94ea46a33 100644 --- a/src/regexp/ia32/regexp-macro-assembler-ia32.h +++ b/src/regexp/ia32/regexp-macro-assembler-ia32.h @@ -114,12 +114,20 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32 static const int kBackup_esi = kFramePointer - kSystemPointerSize; static const int kBackup_edi = kBackup_esi - kSystemPointerSize; static const int kBackup_ebx = kBackup_edi - kSystemPointerSize; - static const int kSuccessfulCaptures = kBackup_ebx - kSystemPointerSize; + static const int kLastCalleeSaveRegister = kBackup_ebx; + + static const int kSuccessfulCaptures = + kLastCalleeSaveRegister - kSystemPointerSize; static const int kStringStartMinusOne = kSuccessfulCaptures - kSystemPointerSize; static const int kBacktrackCount = kStringStartMinusOne - kSystemPointerSize; + // Stores the initial value of the regexp stack pointer in a + // position-independent representation (in case the regexp stack grows and + // thus moves). + static const int kRegExpStackBasePointer = + kBacktrackCount - kSystemPointerSize; // First register address. Following registers are below it on the stack. - static const int kRegisterZero = kBacktrackCount - kSystemPointerSize; + static const int kRegisterZero = kRegExpStackBasePointer - kSystemPointerSize; // Initial size of code buffer. static const int kRegExpCodeSize = 1024; @@ -137,14 +145,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32 Operand register_location(int register_index); // The register containing the current character after LoadCurrentCharacter. - inline Register current_character() { return edx; } + static constexpr Register current_character() { return edx; } // The register containing the backtrack stack top. Provides a meaningful // name to the register. - inline Register backtrack_stackpointer() { return ecx; } + static constexpr Register backtrack_stackpointer() { return ecx; } // Byte size of chars in the string to match (decided by the Mode argument) - inline int char_size() { return static_cast(mode_); } + inline int char_size() const { return static_cast(mode_); } // Equivalent to a conditional branch to the label, unless the label // is nullptr, in which case it is a conditional Backtrack. @@ -168,19 +176,25 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerIA32 // (ecx) and increments it by a word size. inline void Pop(Register target); + void LoadRegExpStackPointerFromMemory(Register dst); + void StoreRegExpStackPointerToMemory(Register src, Register scratch); + void PushRegExpBasePointer(Register scratch1, Register scratch2); + void PopRegExpBasePointer(Register scratch1, Register scratch2); + Isolate* isolate() const { return masm_->isolate(); } - MacroAssembler* masm_; + MacroAssembler* const masm_; + const NoRootArrayScope no_root_array_scope_; // Which mode to generate code for (LATIN1 or UC16). - Mode mode_; + const Mode mode_; // One greater than maximal register index actually used. int num_registers_; // Number of registers to output at the end (the saved registers - // are always 0..num_saved_registers_-1) - int num_saved_registers_; + // are always 0..num_saved_registers_-1). + const int num_saved_registers_; // Labels used internally. Label entry_label_; diff --git a/src/regexp/regexp-macro-assembler.cc b/src/regexp/regexp-macro-assembler.cc index 891079b357a0191e20ea31b68df3a123b4d1b8d2..1f5875afb8850da4136da6633d5b0ad9f52803e3 100644 --- a/src/regexp/regexp-macro-assembler.cc +++ b/src/regexp/regexp-macro-assembler.cc @@ -308,7 +308,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))); @@ -382,22 +382,23 @@ const byte NativeRegExpMacroAssembler::word_character_map[] = { }; // clang-format on -Address NativeRegExpMacroAssembler::GrowStack(Address stack_pointer, - Address* stack_base, - Isolate* isolate) { +Address NativeRegExpMacroAssembler::GrowStack(Isolate* isolate) { + DisallowGarbageCollection no_gc; + RegExpStack* regexp_stack = isolate->regexp_stack(); - size_t size = regexp_stack->stack_capacity(); - Address old_stack_base = regexp_stack->stack_base(); - DCHECK(old_stack_base == *stack_base); - DCHECK(stack_pointer <= old_stack_base); - DCHECK(static_cast(old_stack_base - stack_pointer) <= size); - Address new_stack_base = regexp_stack->EnsureCapacity(size * 2); - if (new_stack_base == kNullAddress) { - return kNullAddress; - } - *stack_base = new_stack_base; - intptr_t stack_content_size = old_stack_base - stack_pointer; - return new_stack_base - stack_content_size; + const size_t old_size = regexp_stack->memory_size(); + +#ifdef DEBUG + const Address old_stack_top = regexp_stack->memory_top(); + const Address old_stack_pointer = regexp_stack->stack_pointer(); + CHECK_LE(old_stack_pointer, old_stack_top); + CHECK_LE(static_cast(old_stack_top - old_stack_pointer), old_size); +#endif // DEBUG + + Address new_stack_base = regexp_stack->EnsureCapacity(old_size * 2); + if (new_stack_base == kNullAddress) return kNullAddress; + + return regexp_stack->stack_pointer(); } } // namespace internal diff --git a/src/regexp/regexp-macro-assembler.h b/src/regexp/regexp-macro-assembler.h index 9bd9ba615e32ad9e34e246a7c4788fdf89375476..af3cc2f5caab97a3a57589d0c54011c07269227f 100644 --- a/src/regexp/regexp-macro-assembler.h +++ b/src/regexp/regexp-macro-assembler.h @@ -281,13 +281,11 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler { int* offsets_vector, int offsets_vector_length, int previous_index, Isolate* isolate); - // Called from RegExp if the backtrack stack limit is hit. - // Tries to expand the stack. Returns the new stack-pointer if - // successful, and updates the stack_top address, or returns 0 if unable - // to grow the stack. + // Called from RegExp if the backtrack stack limit is hit. Tries to expand + // the stack. Returns the new stack-pointer if successful, or returns 0 if + // unable to grow the stack. // This function must not trigger a garbage collection. - static Address GrowStack(Address stack_pointer, Address* stack_top, - Isolate* isolate); + static Address GrowStack(Isolate* isolate); static int CheckStackGuardState(Isolate* isolate, int start_index, RegExp::CallOrigin call_origin, diff --git a/src/regexp/regexp-stack.cc b/src/regexp/regexp-stack.cc index 6d73b7c03d63f9358f54453aba3c52ec5da29c3b..9c403eed089c890df0098875763da62bce15fd64 100644 --- a/src/regexp/regexp-stack.cc +++ b/src/regexp/regexp-stack.cc @@ -11,23 +11,17 @@ namespace v8 { namespace internal { RegExpStackScope::RegExpStackScope(Isolate* isolate) - : regexp_stack_(isolate->regexp_stack()) { + : regexp_stack_(isolate->regexp_stack()), + old_sp_top_delta_(regexp_stack_->sp_top_delta()) { DCHECK(regexp_stack_->IsValid()); - // Irregexp is not reentrant in several ways; in particular, the - // RegExpStackScope is not reentrant since the destructor frees allocated - // memory. Protect against reentrancy here. - CHECK(!regexp_stack_->is_in_use()); - regexp_stack_->set_is_in_use(true); } - RegExpStackScope::~RegExpStackScope() { - // Reset the buffer if it has grown. - regexp_stack_->Reset(); - DCHECK(!regexp_stack_->is_in_use()); + CHECK_EQ(old_sp_top_delta_, regexp_stack_->sp_top_delta()); + regexp_stack_->ResetIfEmpty(); } -RegExpStack::RegExpStack() : thread_local_(this), isolate_(nullptr) {} +RegExpStack::RegExpStack() : thread_local_(this) {} RegExpStack::~RegExpStack() { thread_local_.FreeAndInvalidate(); } @@ -52,18 +46,16 @@ char* RegExpStack::RestoreStack(char* from) { return from + kThreadLocalSize; } -void RegExpStack::Reset() { thread_local_.ResetToStaticStack(this); } - void RegExpStack::ThreadLocal::ResetToStaticStack(RegExpStack* regexp_stack) { if (owns_memory_) DeleteArray(memory_); memory_ = regexp_stack->static_stack_; memory_top_ = regexp_stack->static_stack_ + kStaticStackSize; memory_size_ = kStaticStackSize; + stack_pointer_ = memory_top_; limit_ = reinterpret_cast
(regexp_stack->static_stack_) + kStackLimitSlack * kSystemPointerSize; owns_memory_ = false; - is_in_use_ = false; } void RegExpStack::ThreadLocal::FreeAndInvalidate() { @@ -74,6 +66,7 @@ void RegExpStack::ThreadLocal::FreeAndInvalidate() { memory_ = nullptr; memory_top_ = nullptr; memory_size_ = 0; + stack_pointer_ = nullptr; limit_ = kMemoryTop; } @@ -88,9 +81,11 @@ Address RegExpStack::EnsureCapacity(size_t size) { thread_local_.memory_, thread_local_.memory_size_); if (thread_local_.owns_memory_) DeleteArray(thread_local_.memory_); } + ptrdiff_t delta = sp_top_delta(); thread_local_.memory_ = new_memory; thread_local_.memory_top_ = new_memory + size; thread_local_.memory_size_ = size; + thread_local_.stack_pointer_ = thread_local_.memory_top_ + delta; thread_local_.limit_ = reinterpret_cast
(new_memory) + kStackLimitSlack * kSystemPointerSize; thread_local_.owns_memory_ = true; diff --git a/src/regexp/regexp-stack.h b/src/regexp/regexp-stack.h index adca683ff890c82d7cfdf9e10c7a5d7e78d2d650..d52ca3e1d079d8953a753e2db1e835f214b980f3 100644 --- a/src/regexp/regexp-stack.h +++ b/src/regexp/regexp-stack.h @@ -16,10 +16,7 @@ class RegExpStack; // Maintains a per-v8thread stack area that can be used by irregexp // implementation for its backtracking stack. -// Since there is only one stack area, the Irregexp implementation is not -// re-entrant. I.e., no regular expressions may be executed in the same thread -// during a preempted Irregexp execution. -class V8_NODISCARD RegExpStackScope { +class V8_NODISCARD RegExpStackScope final { public: // Create and delete an instance to control the life-time of a growing stack. @@ -32,46 +29,45 @@ class V8_NODISCARD RegExpStackScope { RegExpStack* stack() const { return regexp_stack_; } private: - RegExpStack* regexp_stack_; + RegExpStack* const regexp_stack_; + const ptrdiff_t old_sp_top_delta_; }; -class RegExpStack { +class RegExpStack final { public: RegExpStack(); ~RegExpStack(); RegExpStack(const RegExpStack&) = delete; RegExpStack& operator=(const RegExpStack&) = delete; - // Number of allocated locations on the stack below the limit. - // No sequence of pushes must be longer that this without doing a stack-limit - // check. + // Number of allocated locations on the stack below the limit. No sequence of + // pushes must be longer than this without doing a stack-limit check. static constexpr int kStackLimitSlack = 32; - // Gives the top of the memory used as stack. - Address stack_base() { + Address memory_top() const { DCHECK_NE(0, thread_local_.memory_size_); DCHECK_EQ(thread_local_.memory_top_, thread_local_.memory_ + thread_local_.memory_size_); return reinterpret_cast
(thread_local_.memory_top_); } - // The total size of the memory allocated for the stack. - size_t stack_capacity() { return thread_local_.memory_size_; } + Address stack_pointer() const { + return reinterpret_cast
(thread_local_.stack_pointer_); + } + + size_t memory_size() const { return thread_local_.memory_size_; } // If the stack pointer gets below the limit, we should react and // either grow the stack or report an out-of-stack exception. // There is only a limited number of locations below the stack limit, // so users of the stack should check the stack limit during any // sequence of pushes longer that this. - Address* limit_address_address() { return &(thread_local_.limit_); } + Address* limit_address_address() { return &thread_local_.limit_; } // Ensures that there is a memory area with at least the specified size. // If passing zero, the default/minimum size buffer is allocated. Address EnsureCapacity(size_t size); - bool is_in_use() const { return thread_local_.is_in_use_; } - void set_is_in_use(bool v) { thread_local_.is_in_use_ = v; } - // Thread local archiving. static constexpr int ArchiveSpacePerThread() { return static_cast(kThreadLocalSize); @@ -103,44 +99,59 @@ class RegExpStack { STATIC_ASSERT(kStaticStackSize <= kMaximumStackSize); - // Structure holding the allocated memory, size and limit. + // Structure holding the allocated memory, size and limit. Thread switching + // archives and restores this struct. struct ThreadLocal { explicit ThreadLocal(RegExpStack* regexp_stack) { ResetToStaticStack(regexp_stack); } - // If memory_size_ > 0 then memory_ and memory_top_ must be non-nullptr - // and memory_top_ = memory_ + memory_size_ + // If memory_size_ > 0 then + // - memory_, memory_top_, stack_pointer_ must be non-nullptr + // - memory_top_ = memory_ + memory_size_ + // - memory_ <= stack_pointer_ <= memory_top_ byte* memory_ = nullptr; byte* memory_top_ = nullptr; size_t memory_size_ = 0; + byte* stack_pointer_ = nullptr; Address limit_ = kNullAddress; bool owns_memory_ = false; // Whether memory_ is owned and must be freed. - bool is_in_use_ = false; // To guard against reentrancy. void ResetToStaticStack(RegExpStack* regexp_stack); + void ResetToStaticStackIfEmpty(RegExpStack* regexp_stack) { + if (stack_pointer_ == memory_top_) ResetToStaticStack(regexp_stack); + } void FreeAndInvalidate(); }; static constexpr size_t kThreadLocalSize = sizeof(ThreadLocal); - // Address of top of memory used as stack. Address memory_top_address_address() { return reinterpret_cast
(&thread_local_.memory_top_); } - // Resets the buffer if it has grown beyond the default/minimum size. - // After this, the buffer is either the default size, or it is empty, so - // you have to call EnsureCapacity before using it again. - void Reset(); + Address stack_pointer_address() { + return reinterpret_cast
(&thread_local_.stack_pointer_); + } + + // A position-independent representation of the stack pointer. + ptrdiff_t sp_top_delta() const { + ptrdiff_t result = + reinterpret_cast(thread_local_.stack_pointer_) - + reinterpret_cast(thread_local_.memory_top_); + DCHECK_LE(result, 0); + return result; + } + + // Resets the buffer if it has grown beyond the default/minimum size and is + // empty. + void ResetIfEmpty() { thread_local_.ResetToStaticStackIfEmpty(this); } // Whether the ThreadLocal storage has been invalidated. bool IsValid() const { return thread_local_.memory_ != nullptr; } ThreadLocal thread_local_; - Isolate* isolate_; friend class ExternalReference; - friend class Isolate; friend class RegExpStackScope; }; diff --git a/src/regexp/x64/regexp-macro-assembler-x64.cc b/src/regexp/x64/regexp-macro-assembler-x64.cc index 6f0cb53e8f52e4cad5997993b7fb00f2d8b8127a..abcbed18aaa9bdc4a497962714bffde74d581173 100644 --- a/src/regexp/x64/regexp-macro-assembler-x64.cc +++ b/src/regexp/x64/regexp-macro-assembler-x64.cc @@ -6,13 +6,13 @@ #include "src/regexp/x64/regexp-macro-assembler-x64.h" +#include "src/codegen/code-desc.h" #include "src/codegen/macro-assembler.h" #include "src/heap/factory.h" #include "src/logging/log.h" -#include "src/objects/objects-inl.h" +#include "src/objects/code-inl.h" #include "src/regexp/regexp-macro-assembler.h" #include "src/regexp/regexp-stack.h" -#include "src/strings/unicode.h" namespace v8 { namespace internal { @@ -664,31 +664,64 @@ void RegExpMacroAssemblerX64::Fail() { __ jmp(&exit_label_); } +void RegExpMacroAssemblerX64::LoadRegExpStackPointerFromMemory(Register dst) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); + __ movq(dst, __ ExternalReferenceAsOperand(ref, dst)); +} + +void RegExpMacroAssemblerX64::StoreRegExpStackPointerToMemory( + Register src, Register scratch) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_stack_pointer(isolate()); + __ movq(__ ExternalReferenceAsOperand(ref, scratch), src); +} + +void RegExpMacroAssemblerX64::PushRegExpBasePointer(Register scratch1, + Register scratch2) { + LoadRegExpStackPointerFromMemory(scratch1); + ExternalReference ref = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ movq(scratch2, __ ExternalReferenceAsOperand(ref, scratch2)); + __ subq(scratch1, scratch2); + __ movq(Operand(rbp, kRegExpStackBasePointer), scratch1); +} + +void RegExpMacroAssemblerX64::PopRegExpBasePointer(Register scratch1, + Register scratch2) { + ExternalReference ref = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ movq(scratch1, Operand(rbp, kRegExpStackBasePointer)); + __ movq(scratch2, __ ExternalReferenceAsOperand(ref, scratch2)); + __ addq(scratch1, scratch2); + StoreRegExpStackPointerToMemory(scratch1, scratch2); +} Handle RegExpMacroAssemblerX64::GetCode(Handle source) { Label return_rax; - // Finalize code - write the entry point code now we know how many - // registers we need. - // Entry code: + // Finalize code - write the entry point code now we know how many registers + // we need. __ bind(&entry_label_); - // Tell the system that we have a stack frame. Because the type is MANUAL, no - // is generated. + // Tell the system that we have a stack frame. Because the type is MANUAL, no + // physical frame is generated. FrameScope scope(&masm_, StackFrame::MANUAL); // Actually emit code to start a new stack frame. __ pushq(rbp); __ movq(rbp, rsp); + // Save parameters and callee-save registers. Order here should correspond // to order of kBackup_ebx etc. #ifdef V8_TARGET_OS_WIN // MSVC passes arguments in rcx, rdx, r8, r9, with backing stack slots. - // Store register parameters in pre-allocated stack slots, - __ movq(Operand(rbp, kInputString), rcx); - __ movq(Operand(rbp, kStartIndex), rdx); // Passed as int32 in edx. - __ movq(Operand(rbp, kInputStart), r8); - __ movq(Operand(rbp, kInputEnd), r9); - // Callee-save on Win64. + // Store register parameters in pre-allocated stack slots. + __ movq(Operand(rbp, kInputString), arg_reg_1); + __ movq(Operand(rbp, kStartIndex), arg_reg_2); // Passed as int32 in edx. + __ movq(Operand(rbp, kInputStart), arg_reg_3); + __ movq(Operand(rbp, kInputEnd), arg_reg_4); + + STATIC_ASSERT(kNumCalleeSaveRegisters == 3); __ pushq(rsi); __ pushq(rdi); __ pushq(rbx); @@ -701,14 +734,15 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { DCHECK_EQ(kInputEnd, -4 * kSystemPointerSize); DCHECK_EQ(kRegisterOutput, -5 * kSystemPointerSize); DCHECK_EQ(kNumOutputRegisters, -6 * kSystemPointerSize); - __ pushq(rdi); - __ pushq(rsi); - __ pushq(rdx); - __ pushq(rcx); + __ pushq(arg_reg_1); + __ pushq(arg_reg_2); + __ pushq(arg_reg_3); + __ pushq(arg_reg_4); __ pushq(r8); __ pushq(r9); - __ pushq(rbx); // Callee-save + STATIC_ASSERT(kNumCalleeSaveRegisters == 1); + __ pushq(rbx); #endif STATIC_ASSERT(kSuccessfulCaptures == @@ -719,6 +753,13 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { __ Push(Immediate(0)); // Make room for "string start - 1" constant. STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize); __ Push(Immediate(0)); // The backtrack counter. + STATIC_ASSERT(kRegExpStackBasePointer == + kBacktrackCount - kSystemPointerSize); + __ Push(Immediate(0)); // The regexp stack base ptr. + + // Store the regexp base pointer - we'll later restore it / write it to + // memory when returning from this irregexp code object. + PushRegExpBasePointer(rcx, kScratchRegister); // Check if we have space on the stack for registers. Label stack_limit_hit; @@ -808,7 +849,9 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { } // Initialize backtrack stack pointer. - __ movq(backtrack_stackpointer(), Operand(rbp, kStackHighEnd)); + // TODO(jgruber): Remove the kStackHighEnd parameter (and others like + // kIsolate). + LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); __ jmp(&start_label_); @@ -894,19 +937,26 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { } __ bind(&return_rax); + // Restore the original regexp stack pointer value (effectively, pop the + // stored base pointer). + PopRegExpBasePointer(rcx, kScratchRegister); + #ifdef V8_TARGET_OS_WIN // Restore callee save registers. __ leaq(rsp, Operand(rbp, kLastCalleeSaveRegister)); + STATIC_ASSERT(kNumCalleeSaveRegisters == 3); __ popq(rbx); __ popq(rdi); __ popq(rsi); // Stack now at rbp. #else // Restore callee save register. + STATIC_ASSERT(kNumCalleeSaveRegisters == 1); __ movq(rbx, Operand(rbp, kBackup_rbx)); // Skip rsp to rbp. __ movq(rsp, rbp); #endif + // Exit function frame, restore previous one. __ popq(rbp); __ ret(0); @@ -923,9 +973,10 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { if (check_preempt_label_.is_linked()) { SafeCallTarget(&check_preempt_label_); - __ pushq(backtrack_stackpointer()); __ pushq(rdi); + StoreRegExpStackPointerToMemory(backtrack_stackpointer(), kScratchRegister); + CallCheckStackGuardState(); __ testq(rax, rax); // If returning non-zero, we should end execution with the given @@ -935,7 +986,9 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { // Restore registers. __ Move(code_object_pointer(), masm_.CodeObject()); __ popq(rdi); - __ popq(backtrack_stackpointer()); + + LoadRegExpStackPointerFromMemory(backtrack_stackpointer()); + // String might have moved: Reload esi from frame. __ movq(rsi, Operand(rbp, kInputEnd)); SafeReturn(); @@ -953,25 +1006,19 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { __ pushq(rdi); #endif - // Call GrowStack(backtrack_stackpointer()) - static const int num_arguments = 3; - __ PrepareCallCFunction(num_arguments); -#ifdef V8_TARGET_OS_WIN - // Microsoft passes parameters in rcx, rdx, r8. - // First argument, backtrack stackpointer, is already in rcx. - __ leaq(rdx, Operand(rbp, kStackHighEnd)); // Second argument - __ LoadAddress(r8, ExternalReference::isolate_address(isolate())); -#else - // AMD64 ABI passes parameters in rdi, rsi, rdx. - __ movq(rdi, backtrack_stackpointer()); // First argument. - __ leaq(rsi, Operand(rbp, kStackHighEnd)); // Second argument. - __ LoadAddress(rdx, ExternalReference::isolate_address(isolate())); -#endif + // Call GrowStack(isolate). + + StoreRegExpStackPointerToMemory(backtrack_stackpointer(), kScratchRegister); + + static constexpr int kNumArguments = 1; + __ PrepareCallCFunction(kNumArguments); + __ LoadAddress(arg_reg_1, ExternalReference::isolate_address(isolate())); + ExternalReference grow_stack = ExternalReference::re_grow_stack(isolate()); - __ CallCFunction(grow_stack, num_arguments); - // If return nullptr, we have failed to grow the stack, and - // must exit with a stack-overflow exception. + __ CallCFunction(grow_stack, kNumArguments); + // If nullptr is returned, we have failed to grow the stack, and must exit + // with a stack-overflow exception. __ testq(rax, rax); __ j(equal, &exit_with_exception); // Otherwise use return value as new stack pointer. @@ -1085,13 +1132,25 @@ void RegExpMacroAssemblerX64::ReadPositionFromRegister(Register dst, int reg) { __ movq(dst, register_location(reg)); } +// Preserves a position-independent representation of the stack pointer in reg: +// reg = top - sp. +void RegExpMacroAssemblerX64::WriteStackPointerToRegister(int reg) { + ExternalReference stack_top_address = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ movq(rax, __ ExternalReferenceAsOperand(stack_top_address, rax)); + __ subq(rax, backtrack_stackpointer()); + __ movq(register_location(reg), rax); +} void RegExpMacroAssemblerX64::ReadStackPointerFromRegister(int reg) { - __ movq(backtrack_stackpointer(), register_location(reg)); - __ addq(backtrack_stackpointer(), Operand(rbp, kStackHighEnd)); + ExternalReference stack_top_address = + ExternalReference::address_of_regexp_stack_memory_top_address(isolate()); + __ movq(backtrack_stackpointer(), + __ ExternalReferenceAsOperand(stack_top_address, + backtrack_stackpointer())); + __ subq(backtrack_stackpointer(), register_location(reg)); } - void RegExpMacroAssemblerX64::SetCurrentPositionFromEnd(int by) { Label after_position; __ cmpq(rdi, Immediate(-by * char_size())); @@ -1136,14 +1195,6 @@ void RegExpMacroAssemblerX64::ClearRegisters(int reg_from, int reg_to) { } } - -void RegExpMacroAssemblerX64::WriteStackPointerToRegister(int reg) { - __ movq(rax, backtrack_stackpointer()); - __ subq(rax, Operand(rbp, kStackHighEnd)); - __ movq(register_location(reg), rax); -} - - // Private methods: void RegExpMacroAssemblerX64::CallCheckStackGuardState() { diff --git a/src/regexp/x64/regexp-macro-assembler-x64.h b/src/regexp/x64/regexp-macro-assembler-x64.h index c3a3cb90f2a9d865057af80801e2a95bbb873140..74a3c95b06c771078ab03e6787e5912315421bb2 100644 --- a/src/regexp/x64/regexp-macro-assembler-x64.h +++ b/src/regexp/x64/regexp-macro-assembler-x64.h @@ -5,9 +5,7 @@ #ifndef V8_REGEXP_X64_REGEXP_MACRO_ASSEMBLER_X64_H_ #define V8_REGEXP_X64_REGEXP_MACRO_ASSEMBLER_X64_H_ -#include "src/base/strings.h" #include "src/codegen/macro-assembler.h" -#include "src/codegen/x64/assembler-x64.h" #include "src/regexp/regexp-macro-assembler.h" #include "src/zone/zone-chunk-list.h" @@ -133,18 +131,17 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 static const int kIsolate = kDirectCall + kSystemPointerSize; #endif + // We push callee-save registers that we use after the frame pointer (and + // after the parameters). #ifdef V8_TARGET_OS_WIN - // Microsoft calling convention has three callee-saved registers - // (that we are using). We push these after the frame pointer. static const int kBackup_rsi = kFramePointer - kSystemPointerSize; static const int kBackup_rdi = kBackup_rsi - kSystemPointerSize; static const int kBackup_rbx = kBackup_rdi - kSystemPointerSize; + static const int kNumCalleeSaveRegisters = 3; static const int kLastCalleeSaveRegister = kBackup_rbx; #else - // AMD64 Calling Convention has only one callee-save register that - // we use. We push this after the frame pointer (and after the - // parameters). static const int kBackup_rbx = kNumOutputRegisters - kSystemPointerSize; + static const int kNumCalleeSaveRegisters = 1; static const int kLastCalleeSaveRegister = kBackup_rbx; #endif @@ -155,9 +152,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 static const int kStringStartMinusOne = kSuccessfulCaptures - kSystemPointerSize; static const int kBacktrackCount = kStringStartMinusOne - kSystemPointerSize; + // Stores the initial value of the regexp stack pointer in a + // position-independent representation (in case the regexp stack grows and + // thus moves). + static const int kRegExpStackBasePointer = + kBacktrackCount - kSystemPointerSize; // First register address. Following registers are below it on the stack. - static const int kRegisterZero = kBacktrackCount - kSystemPointerSize; + static const int kRegisterZero = kRegExpStackBasePointer - kSystemPointerSize; // Initial size of code buffer. static const int kRegExpCodeSize = 1024; @@ -175,14 +177,14 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 Operand register_location(int register_index); // The register containing the current character after LoadCurrentCharacter. - inline Register current_character() { return rdx; } + static constexpr Register current_character() { return rdx; } // The register containing the backtrack stack top. Provides a meaningful // name to the register. - inline Register backtrack_stackpointer() { return rcx; } + static constexpr Register backtrack_stackpointer() { return rcx; } // The registers containing a self pointer to this code's Code object. - inline Register code_object_pointer() { return r8; } + static constexpr Register code_object_pointer() { return r8; } // Byte size of chars in the string to match (decided by the Mode argument) inline int char_size() { return static_cast(mode_); } @@ -224,24 +226,36 @@ class V8_EXPORT_PRIVATE RegExpMacroAssemblerX64 // Increments the stack pointer (rcx) by a word size. inline void Drop(); + void LoadRegExpStackPointerFromMemory(Register dst); + void StoreRegExpStackPointerToMemory(Register src, Register scratch); + void PushRegExpBasePointer(Register scratch1, Register scratch2); + void PopRegExpBasePointer(Register scratch1, Register scratch2); + inline void ReadPositionFromRegister(Register dst, int reg); Isolate* isolate() const { return masm_.isolate(); } MacroAssembler masm_; - NoRootArrayScope no_root_array_scope_; + + // On x64, there is no reason to keep the kRootRegister uninitialized; we + // could easily use it by 1. initializing it and 2. storing/restoring it + // as callee-save on entry/exit. + // But: on other platforms, specifically ia32, it would be tricky to enable + // the kRootRegister since it's currently used for other purposes. Thus, for + // consistency, we also keep it uninitialized here. + const NoRootArrayScope no_root_array_scope_; ZoneChunkList code_relative_fixup_positions_; // Which mode to generate code for (LATIN1 or UC16). - Mode mode_; + const Mode mode_; // One greater than maximal register index actually used. int num_registers_; // Number of registers to output at the end (the saved registers // are always 0..num_saved_registers_-1) - int num_saved_registers_; + const int num_saved_registers_; // Labels used internally. Label entry_label_; diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status index 9c28520ed56998173c105b9d8a2ca3c4489b916e..e092d3b74c79d5dfc2bbf056881164c16ebb7cda 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 ##############################################################################