11cb0ef41Sopenharmony_ci// Copyright 2009 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef V8_REGEXP_REGEXP_STACK_H_
61cb0ef41Sopenharmony_ci#define V8_REGEXP_REGEXP_STACK_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include "src/base/logging.h"
91cb0ef41Sopenharmony_ci#include "src/base/macros.h"
101cb0ef41Sopenharmony_ci#include "src/common/globals.h"
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_cinamespace v8 {
131cb0ef41Sopenharmony_cinamespace internal {
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ciclass RegExpStack;
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ci// Maintains a per-v8thread stack area that can be used by irregexp
181cb0ef41Sopenharmony_ci// implementation for its backtracking stack.
191cb0ef41Sopenharmony_ciclass V8_NODISCARD RegExpStackScope final {
201cb0ef41Sopenharmony_ci public:
211cb0ef41Sopenharmony_ci  // Create and delete an instance to control the life-time of a growing stack.
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci  // Initializes the stack memory area if necessary.
241cb0ef41Sopenharmony_ci  explicit RegExpStackScope(Isolate* isolate);
251cb0ef41Sopenharmony_ci  ~RegExpStackScope();  // Releases the stack if it has grown.
261cb0ef41Sopenharmony_ci  RegExpStackScope(const RegExpStackScope&) = delete;
271cb0ef41Sopenharmony_ci  RegExpStackScope& operator=(const RegExpStackScope&) = delete;
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci  RegExpStack* stack() const { return regexp_stack_; }
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci private:
321cb0ef41Sopenharmony_ci  RegExpStack* const regexp_stack_;
331cb0ef41Sopenharmony_ci  const ptrdiff_t old_sp_top_delta_;
341cb0ef41Sopenharmony_ci};
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ciclass RegExpStack final {
371cb0ef41Sopenharmony_ci public:
381cb0ef41Sopenharmony_ci  RegExpStack();
391cb0ef41Sopenharmony_ci  ~RegExpStack();
401cb0ef41Sopenharmony_ci  RegExpStack(const RegExpStack&) = delete;
411cb0ef41Sopenharmony_ci  RegExpStack& operator=(const RegExpStack&) = delete;
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  // Number of allocated locations on the stack below the limit. No sequence of
441cb0ef41Sopenharmony_ci  // pushes must be longer than this without doing a stack-limit check.
451cb0ef41Sopenharmony_ci  static constexpr int kStackLimitSlack = 32;
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci  Address memory_top() const {
481cb0ef41Sopenharmony_ci    DCHECK_NE(0, thread_local_.memory_size_);
491cb0ef41Sopenharmony_ci    DCHECK_EQ(thread_local_.memory_top_,
501cb0ef41Sopenharmony_ci              thread_local_.memory_ + thread_local_.memory_size_);
511cb0ef41Sopenharmony_ci    return reinterpret_cast<Address>(thread_local_.memory_top_);
521cb0ef41Sopenharmony_ci  }
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci  Address stack_pointer() const {
551cb0ef41Sopenharmony_ci    return reinterpret_cast<Address>(thread_local_.stack_pointer_);
561cb0ef41Sopenharmony_ci  }
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  size_t memory_size() const { return thread_local_.memory_size_; }
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci  // If the stack pointer gets below the limit, we should react and
611cb0ef41Sopenharmony_ci  // either grow the stack or report an out-of-stack exception.
621cb0ef41Sopenharmony_ci  // There is only a limited number of locations below the stack limit,
631cb0ef41Sopenharmony_ci  // so users of the stack should check the stack limit during any
641cb0ef41Sopenharmony_ci  // sequence of pushes longer that this.
651cb0ef41Sopenharmony_ci  Address* limit_address_address() { return &thread_local_.limit_; }
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  // Ensures that there is a memory area with at least the specified size.
681cb0ef41Sopenharmony_ci  // If passing zero, the default/minimum size buffer is allocated.
691cb0ef41Sopenharmony_ci  Address EnsureCapacity(size_t size);
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  // Thread local archiving.
721cb0ef41Sopenharmony_ci  static constexpr int ArchiveSpacePerThread() {
731cb0ef41Sopenharmony_ci    return static_cast<int>(kThreadLocalSize);
741cb0ef41Sopenharmony_ci  }
751cb0ef41Sopenharmony_ci  char* ArchiveStack(char* to);
761cb0ef41Sopenharmony_ci  char* RestoreStack(char* from);
771cb0ef41Sopenharmony_ci  void FreeThreadResources() { thread_local_.ResetToStaticStack(this); }
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci  // Maximal size of allocated stack area.
801cb0ef41Sopenharmony_ci  static constexpr size_t kMaximumStackSize = 64 * MB;
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci private:
831cb0ef41Sopenharmony_ci  // Artificial limit used when the thread-local state has been destroyed.
841cb0ef41Sopenharmony_ci  static const Address kMemoryTop =
851cb0ef41Sopenharmony_ci      static_cast<Address>(static_cast<uintptr_t>(-1));
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  // Minimal size of dynamically-allocated stack area.
881cb0ef41Sopenharmony_ci  static constexpr size_t kMinimumDynamicStackSize = 1 * KB;
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci  // In addition to dynamically-allocated, variable-sized stacks, we also have
911cb0ef41Sopenharmony_ci  // a statically allocated and sized area that is used whenever no dynamic
921cb0ef41Sopenharmony_ci  // stack is allocated. This guarantees that a stack is always available and
931cb0ef41Sopenharmony_ci  // we can skip availability-checks later on.
941cb0ef41Sopenharmony_ci  // It's double the slack size to ensure that we have a bit of breathing room
951cb0ef41Sopenharmony_ci  // before NativeRegExpMacroAssembler::GrowStack must be called.
961cb0ef41Sopenharmony_ci  static constexpr size_t kStaticStackSize =
971cb0ef41Sopenharmony_ci      2 * kStackLimitSlack * kSystemPointerSize;
981cb0ef41Sopenharmony_ci  byte static_stack_[kStaticStackSize] = {0};
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci  STATIC_ASSERT(kStaticStackSize <= kMaximumStackSize);
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci  // Structure holding the allocated memory, size and limit. Thread switching
1031cb0ef41Sopenharmony_ci  // archives and restores this struct.
1041cb0ef41Sopenharmony_ci  struct ThreadLocal {
1051cb0ef41Sopenharmony_ci    explicit ThreadLocal(RegExpStack* regexp_stack) {
1061cb0ef41Sopenharmony_ci      ResetToStaticStack(regexp_stack);
1071cb0ef41Sopenharmony_ci    }
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci    // If memory_size_ > 0 then
1101cb0ef41Sopenharmony_ci    //  - memory_, memory_top_, stack_pointer_ must be non-nullptr
1111cb0ef41Sopenharmony_ci    //  - memory_top_ = memory_ + memory_size_
1121cb0ef41Sopenharmony_ci    //  - memory_ <= stack_pointer_ <= memory_top_
1131cb0ef41Sopenharmony_ci    byte* memory_ = nullptr;
1141cb0ef41Sopenharmony_ci    byte* memory_top_ = nullptr;
1151cb0ef41Sopenharmony_ci    size_t memory_size_ = 0;
1161cb0ef41Sopenharmony_ci    byte* stack_pointer_ = nullptr;
1171cb0ef41Sopenharmony_ci    Address limit_ = kNullAddress;
1181cb0ef41Sopenharmony_ci    bool owns_memory_ = false;  // Whether memory_ is owned and must be freed.
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci    void ResetToStaticStack(RegExpStack* regexp_stack);
1211cb0ef41Sopenharmony_ci    void ResetToStaticStackIfEmpty(RegExpStack* regexp_stack) {
1221cb0ef41Sopenharmony_ci      if (stack_pointer_ == memory_top_) ResetToStaticStack(regexp_stack);
1231cb0ef41Sopenharmony_ci    }
1241cb0ef41Sopenharmony_ci    void FreeAndInvalidate();
1251cb0ef41Sopenharmony_ci  };
1261cb0ef41Sopenharmony_ci  static constexpr size_t kThreadLocalSize = sizeof(ThreadLocal);
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci  Address memory_top_address_address() {
1291cb0ef41Sopenharmony_ci    return reinterpret_cast<Address>(&thread_local_.memory_top_);
1301cb0ef41Sopenharmony_ci  }
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci  Address stack_pointer_address() {
1331cb0ef41Sopenharmony_ci    return reinterpret_cast<Address>(&thread_local_.stack_pointer_);
1341cb0ef41Sopenharmony_ci  }
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci  // A position-independent representation of the stack pointer.
1371cb0ef41Sopenharmony_ci  ptrdiff_t sp_top_delta() const {
1381cb0ef41Sopenharmony_ci    ptrdiff_t result =
1391cb0ef41Sopenharmony_ci        reinterpret_cast<intptr_t>(thread_local_.stack_pointer_) -
1401cb0ef41Sopenharmony_ci        reinterpret_cast<intptr_t>(thread_local_.memory_top_);
1411cb0ef41Sopenharmony_ci    DCHECK_LE(result, 0);
1421cb0ef41Sopenharmony_ci    return result;
1431cb0ef41Sopenharmony_ci  }
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci  // Resets the buffer if it has grown beyond the default/minimum size and is
1461cb0ef41Sopenharmony_ci  // empty.
1471cb0ef41Sopenharmony_ci  void ResetIfEmpty() { thread_local_.ResetToStaticStackIfEmpty(this); }
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci  // Whether the ThreadLocal storage has been invalidated.
1501cb0ef41Sopenharmony_ci  bool IsValid() const { return thread_local_.memory_ != nullptr; }
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci  ThreadLocal thread_local_;
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  friend class ExternalReference;
1551cb0ef41Sopenharmony_ci  friend class RegExpStackScope;
1561cb0ef41Sopenharmony_ci};
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci}  // namespace internal
1591cb0ef41Sopenharmony_ci}  // namespace v8
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci#endif  // V8_REGEXP_REGEXP_STACK_H_
162