Revert "[regexp] Guarantee an allocated regexp stack"
This reverts commit 97ed8b277b
.
Reason for revert: breaks chromium roll
https://chromium-review.googlesource.com/c/chromium/src/+/1864878
I bisected it down to this CL here:
https://chromium-review.googlesource.com/c/chromium/src/+/1865346/6
https://ci.chromium.org/p/chromium/builders/try/linux-rel/219610
Original change's description:
> [regexp] Guarantee an allocated regexp stack
>
> The regexp stack is used during execution of jitted regexp matcher
> code. Previously, the stack was initially not present / nullptr, and
> we had to explicitly check for this condition and bail out in builtin
> code.
>
> This CL changes behavior to guarantee a present stack by adding a
> statically-allocated area that is used whenever no
> dynamically-allocated stack exists.
>
> Change-Id: I52934425ae72cf0e5d13fab2b9d63d37ca76fcf3
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1852126
> Auto-Submit: Jakob Gruber <jgruber@chromium.org>
> Commit-Queue: Peter Marshall <petermarshall@chromium.org>
> Reviewed-by: Peter Marshall <petermarshall@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#64326}
TBR=jgruber@chromium.org,petermarshall@chromium.org
Change-Id: I085b7aebb513fdededda7631b06ff68e5ae5846e
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1864945
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64346}
This commit is contained in:
parent
581bf00eb2
commit
134f551248
@ -398,6 +398,8 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
ExternalConstant(ExternalReference::isolate_address(isolate()));
|
||||
TNode<ExternalReference> regexp_stack_memory_top_address = ExternalConstant(
|
||||
ExternalReference::address_of_regexp_stack_memory_top_address(isolate()));
|
||||
TNode<ExternalReference> regexp_stack_memory_size_address = ExternalConstant(
|
||||
ExternalReference::address_of_regexp_stack_memory_size(isolate()));
|
||||
TNode<ExternalReference> static_offsets_vector_address = ExternalConstant(
|
||||
ExternalReference::address_of_static_offsets_vector(isolate()));
|
||||
|
||||
@ -516,6 +518,21 @@ TNode<HeapObject> RegExpBuiltinsAssembler::RegExpExecInternal(
|
||||
GotoIf(TaggedIsSmi(var_code.value()), &runtime);
|
||||
TNode<Code> code = CAST(var_code.value());
|
||||
|
||||
// Ensure that a RegExp stack is allocated when using compiled Irregexp.
|
||||
// TODO(jgruber): Guarantee an allocated stack and remove this check.
|
||||
{
|
||||
Label next(this);
|
||||
GotoIfNot(TaggedIsSmi(var_bytecode.value()), &next);
|
||||
CSA_ASSERT(this, SmiEqual(CAST(var_bytecode.value()),
|
||||
SmiConstant(JSRegExp::kUninitializedValue)));
|
||||
|
||||
TNode<IntPtrT> stack_size = UncheckedCast<IntPtrT>(
|
||||
Load(MachineType::IntPtr(), regexp_stack_memory_size_address));
|
||||
Branch(IntPtrEqual(stack_size, IntPtrZero()), &runtime, &next);
|
||||
|
||||
BIND(&next);
|
||||
}
|
||||
|
||||
Label if_success(this), if_exception(this, Label::kDeferred);
|
||||
{
|
||||
IncrementCounter(isolate()->counters()->regexp_entry_native(), 1);
|
||||
|
@ -504,6 +504,16 @@ ExternalReference ExternalReference::address_of_regexp_stack_limit_address(
|
||||
return ExternalReference(isolate->regexp_stack()->limit_address_address());
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::address_of_regexp_stack_memory_address(
|
||||
Isolate* isolate) {
|
||||
return ExternalReference(isolate->regexp_stack()->memory_address_address());
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::address_of_regexp_stack_memory_size(
|
||||
Isolate* isolate) {
|
||||
return ExternalReference(isolate->regexp_stack()->memory_size_address());
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::address_of_regexp_stack_memory_top_address(
|
||||
Isolate* isolate) {
|
||||
return ExternalReference(
|
||||
|
@ -74,6 +74,9 @@ class StatsCounter;
|
||||
V(stack_is_iterable_address, "IsolateData::stack_is_iterable_address") \
|
||||
V(address_of_regexp_stack_limit_address, \
|
||||
"RegExpStack::limit_address_address()") \
|
||||
V(address_of_regexp_stack_memory_address, \
|
||||
"RegExpStack::memory_address_address()") \
|
||||
V(address_of_regexp_stack_memory_size, "RegExpStack::memory_size_address()") \
|
||||
V(address_of_regexp_stack_memory_top_address, \
|
||||
"RegExpStack::memory_top_address_address()") \
|
||||
V(address_of_static_offsets_vector, "OffsetsVector::static_offsets_vector") \
|
||||
|
@ -22,7 +22,7 @@ RegExpStackScope::~RegExpStackScope() {
|
||||
regexp_stack_->Reset();
|
||||
}
|
||||
|
||||
RegExpStack::RegExpStack() : thread_local_(this), isolate_(nullptr) {}
|
||||
RegExpStack::RegExpStack() : isolate_(nullptr) {}
|
||||
|
||||
RegExpStack::~RegExpStack() {
|
||||
thread_local_.Free();
|
||||
@ -30,17 +30,9 @@ RegExpStack::~RegExpStack() {
|
||||
|
||||
|
||||
char* RegExpStack::ArchiveStack(char* to) {
|
||||
if (!thread_local_.owns_memory_) {
|
||||
// Force dynamic stacks prior to archiving. Any growth will do. A dynamic
|
||||
// stack is needed because stack archival & restoration rely on `memory_`
|
||||
// pointing at a fixed-location backing store, whereas the static stack is
|
||||
// tied to a RegExpStack instance.
|
||||
EnsureCapacity(thread_local_.memory_size_ + 1);
|
||||
}
|
||||
|
||||
size_t size = sizeof(thread_local_);
|
||||
MemCopy(reinterpret_cast<void*>(to), &thread_local_, size);
|
||||
thread_local_ = ThreadLocal(this);
|
||||
thread_local_ = ThreadLocal();
|
||||
return to + size;
|
||||
}
|
||||
|
||||
@ -53,44 +45,37 @@ char* RegExpStack::RestoreStack(char* from) {
|
||||
|
||||
|
||||
void RegExpStack::Reset() {
|
||||
STATIC_ASSERT(kMinimumDynamicStackSize > kStaticStackSize);
|
||||
if (thread_local_.memory_size_ > kMinimumDynamicStackSize) {
|
||||
DCHECK(thread_local_.owns_memory_);
|
||||
if (thread_local_.memory_size_ > kMinimumStackSize) {
|
||||
DeleteArray(thread_local_.memory_);
|
||||
thread_local_ = ThreadLocal(this);
|
||||
thread_local_ = ThreadLocal();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RegExpStack::ThreadLocal::Free() {
|
||||
if (owns_memory_) DeleteArray(memory_);
|
||||
|
||||
// This stack may not be used after being freed. Just reset to invalid values
|
||||
// to ensure we don't accidentally use old memory areas.
|
||||
memory_ = nullptr;
|
||||
memory_top_ = nullptr;
|
||||
memory_size_ = 0;
|
||||
limit_ = kMemoryTop;
|
||||
if (memory_size_ > 0) {
|
||||
DeleteArray(memory_);
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Address RegExpStack::EnsureCapacity(size_t size) {
|
||||
if (size > kMaximumStackSize) return kNullAddress;
|
||||
if (size < kMinimumDynamicStackSize) size = kMinimumDynamicStackSize;
|
||||
if (size < kMinimumStackSize) size = kMinimumStackSize;
|
||||
if (thread_local_.memory_size_ < size) {
|
||||
byte* new_memory = NewArray<byte>(size);
|
||||
if (thread_local_.memory_size_ > 0) {
|
||||
// Copy original memory into top of new memory.
|
||||
MemCopy(new_memory + size - thread_local_.memory_size_,
|
||||
thread_local_.memory_, thread_local_.memory_size_);
|
||||
if (thread_local_.owns_memory_) DeleteArray(thread_local_.memory_);
|
||||
DeleteArray(thread_local_.memory_);
|
||||
}
|
||||
thread_local_.memory_ = new_memory;
|
||||
thread_local_.memory_top_ = new_memory + size;
|
||||
thread_local_.memory_size_ = size;
|
||||
thread_local_.limit_ = reinterpret_cast<Address>(new_memory) +
|
||||
kStackLimitSlack * kSystemPointerSize;
|
||||
thread_local_.owns_memory_ = true;
|
||||
}
|
||||
return reinterpret_cast<Address>(thread_local_.memory_top_);
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class RegExpStack {
|
||||
// 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.
|
||||
static constexpr int kStackLimitSlack = 32;
|
||||
static const int kStackLimitSlack = 32;
|
||||
|
||||
// Gives the top of the memory used as stack.
|
||||
Address stack_base() {
|
||||
@ -66,7 +66,7 @@ class RegExpStack {
|
||||
Address EnsureCapacity(size_t size);
|
||||
|
||||
// Thread local archiving.
|
||||
static constexpr int ArchiveSpacePerThread() {
|
||||
static int ArchiveSpacePerThread() {
|
||||
return static_cast<int>(sizeof(ThreadLocal));
|
||||
}
|
||||
char* ArchiveStack(char* to);
|
||||
@ -80,47 +80,41 @@ class RegExpStack {
|
||||
RegExpStack();
|
||||
~RegExpStack();
|
||||
|
||||
// Artificial limit used when the thread-local state has been destroyed.
|
||||
// Artificial limit used when no memory has been allocated.
|
||||
static const Address kMemoryTop =
|
||||
static_cast<Address>(static_cast<uintptr_t>(-1));
|
||||
|
||||
// Minimal size of dynamically-allocated stack area.
|
||||
static constexpr size_t kMinimumDynamicStackSize = 1 * KB;
|
||||
|
||||
// In addition to dynamically-allocated, variable-sized stacks, we also have
|
||||
// a statically allocated and sized area that is used whenever no dynamic
|
||||
// stack is allocated. This guarantees that a stack is always available and
|
||||
// we can skip availability-checks later on.
|
||||
// It's double the slack size to ensure that we have a bit of breathing room
|
||||
// before NativeRegExpMacroAssembler::GrowStack must be called.
|
||||
static constexpr size_t kStaticStackSize =
|
||||
2 * kStackLimitSlack * kSystemPointerSize;
|
||||
byte static_stack_[kStaticStackSize] = {0};
|
||||
|
||||
STATIC_ASSERT(kStaticStackSize <= kMaximumStackSize);
|
||||
// Minimal size of allocated stack area.
|
||||
static const size_t kMinimumStackSize = 1 * KB;
|
||||
|
||||
// Structure holding the allocated memory, size and limit.
|
||||
struct ThreadLocal {
|
||||
explicit ThreadLocal(RegExpStack* regexp_stack) {
|
||||
memory_ = regexp_stack->static_stack_;
|
||||
memory_top_ = regexp_stack->static_stack_ + kStaticStackSize;
|
||||
memory_size_ = kStaticStackSize;
|
||||
limit_ = reinterpret_cast<Address>(regexp_stack->static_stack_) +
|
||||
kStackLimitSlack * kSystemPointerSize;
|
||||
owns_memory_ = false;
|
||||
}
|
||||
|
||||
ThreadLocal() { Clear(); }
|
||||
// If memory_size_ > 0 then memory_ and memory_top_ must be non-nullptr
|
||||
// and memory_top_ = memory_ + memory_size_
|
||||
byte* memory_;
|
||||
byte* memory_top_;
|
||||
size_t memory_size_;
|
||||
Address limit_;
|
||||
bool owns_memory_; // Whether memory_ is owned and must be freed.
|
||||
|
||||
void Clear() {
|
||||
memory_ = nullptr;
|
||||
memory_top_ = nullptr;
|
||||
memory_size_ = 0;
|
||||
limit_ = kMemoryTop;
|
||||
}
|
||||
void Free();
|
||||
};
|
||||
|
||||
// Address of allocated memory.
|
||||
Address memory_address_address() {
|
||||
return reinterpret_cast<Address>(&thread_local_.memory_);
|
||||
}
|
||||
|
||||
// Address of size of allocated memory.
|
||||
Address memory_size_address() {
|
||||
return reinterpret_cast<Address>(&thread_local_.memory_size_);
|
||||
}
|
||||
|
||||
// Address of top of memory used as stack.
|
||||
Address memory_top_address_address() {
|
||||
return reinterpret_cast<Address>(&thread_local_.memory_top_);
|
||||
|
Loading…
Reference in New Issue
Block a user