1 // Copyright 2009 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "irregexp/imported/regexp-stack.h" 6 7 8 namespace v8 { 9 namespace internal { 10 RegExpStackScope(Isolate * isolate)11RegExpStackScope::RegExpStackScope(Isolate* isolate) 12 : regexp_stack_(isolate->regexp_stack()) { 13 DCHECK(regexp_stack_->IsValid()); 14 // Irregexp is not reentrant in several ways; in particular, the 15 // RegExpStackScope is not reentrant since the destructor frees allocated 16 // memory. Protect against reentrancy here. 17 CHECK(!regexp_stack_->is_in_use()); 18 regexp_stack_->set_is_in_use(true); 19 } 20 21 ~RegExpStackScope()22RegExpStackScope::~RegExpStackScope() { 23 // Reset the buffer if it has grown. 24 regexp_stack_->Reset(); 25 DCHECK(!regexp_stack_->is_in_use()); 26 } 27 RegExpStack()28RegExpStack::RegExpStack() : thread_local_(this), isolate_(nullptr) {} 29 ~RegExpStack()30RegExpStack::~RegExpStack() { thread_local_.FreeAndInvalidate(); } 31 ArchiveStack(char * to)32char* RegExpStack::ArchiveStack(char* to) { 33 if (!thread_local_.owns_memory_) { 34 // Force dynamic stacks prior to archiving. Any growth will do. A dynamic 35 // stack is needed because stack archival & restoration rely on `memory_` 36 // pointing at a fixed-location backing store, whereas the static stack is 37 // tied to a RegExpStack instance. 38 EnsureCapacity(thread_local_.memory_size_ + 1); 39 DCHECK(thread_local_.owns_memory_); 40 } 41 42 MemCopy(reinterpret_cast<void*>(to), &thread_local_, kThreadLocalSize); 43 thread_local_ = ThreadLocal(this); 44 return to + kThreadLocalSize; 45 } 46 47 RestoreStack(char * from)48char* RegExpStack::RestoreStack(char* from) { 49 MemCopy(&thread_local_, reinterpret_cast<void*>(from), kThreadLocalSize); 50 return from + kThreadLocalSize; 51 } 52 Reset()53void RegExpStack::Reset() { thread_local_.ResetToStaticStack(this); } 54 ResetToStaticStack(RegExpStack * regexp_stack)55void RegExpStack::ThreadLocal::ResetToStaticStack(RegExpStack* regexp_stack) { 56 if (owns_memory_) DeleteArray(memory_); 57 58 memory_ = regexp_stack->static_stack_; 59 memory_top_ = regexp_stack->static_stack_ + kStaticStackSize; 60 memory_size_ = kStaticStackSize; 61 limit_ = reinterpret_cast<Address>(regexp_stack->static_stack_) + 62 kStackLimitSlack * kSystemPointerSize; 63 owns_memory_ = false; 64 is_in_use_ = false; 65 } 66 FreeAndInvalidate()67void RegExpStack::ThreadLocal::FreeAndInvalidate() { 68 if (owns_memory_) DeleteArray(memory_); 69 70 // This stack may not be used after being freed. Just reset to invalid values 71 // to ensure we don't accidentally use old memory areas. 72 memory_ = nullptr; 73 memory_top_ = nullptr; 74 memory_size_ = 0; 75 limit_ = kMemoryTop; 76 } 77 EnsureCapacity(size_t size)78Address RegExpStack::EnsureCapacity(size_t size) { 79 if (size > kMaximumStackSize) return kNullAddress; 80 if (thread_local_.memory_size_ < size) { 81 if (size < kMinimumDynamicStackSize) size = kMinimumDynamicStackSize; 82 byte* new_memory = NewArray<byte>(size); 83 if (thread_local_.memory_size_ > 0) { 84 // Copy original memory into top of new memory. 85 MemCopy(new_memory + size - thread_local_.memory_size_, 86 thread_local_.memory_, thread_local_.memory_size_); 87 if (thread_local_.owns_memory_) DeleteArray(thread_local_.memory_); 88 } 89 thread_local_.memory_ = new_memory; 90 thread_local_.memory_top_ = new_memory + size; 91 thread_local_.memory_size_ = size; 92 thread_local_.limit_ = reinterpret_cast<Address>(new_memory) + 93 kStackLimitSlack * kSystemPointerSize; 94 thread_local_.owns_memory_ = true; 95 } 96 return reinterpret_cast<Address>(thread_local_.memory_top_); 97 } 98 99 100 } // namespace internal 101 } // namespace v8 102