Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/js/src/irregexp/imported/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 13 kB image not shown  

Quelle  regexp-bytecodes-inl.h   Sprache: C

 

// Copyright 2025 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_REGEXP_REGEXP_BYTECODES_INL_H_
#define V8_REGEXP_REGEXP_BYTECODES_INL_H_

#include "irregexp/imported/regexp-bytecodes.h"
// Include the non-inl header before the rest of the headers.

#include <array>
#include <limits>
#include <string_view>
#include <type_traits>

#include "irregexp/imported/regexp-macro-assembler.h"  // For StackCheckFlag

namespace v8 {
namespace internal {
namespace regexp {

template <BytecodeOperandType>
struct OperandTypeTraits;

#define DECLARE_BASIC_OPERAND_TYPE_TRAITS(Name, CType)                      \
  template <>                                                               \
  struct OperandTypeTraits<BytecodeOperandType::k##Name> {                  \
    static_assert(!std::is_pointer_v<CType>);                               \
    static constexpr uint8_t kSize = sizeof(CType);                         \
    using kCType = CType;                                                   \
    static constexpr bool kIsBasic = true;                                  \
    static constexpr kCType kMinValue = std::numeric_limits<kCType>::min(); \
    static constexpr kCType kMaxValue = std::numeric_limits<kCType>::max(); \
    static constexpr size_t kAlignment = kSize;                             \
  };
BASIC_BYTECODE_OPERAND_TYPE_LIST(DECLARE_BASIC_OPERAND_TYPE_TRAITS)
#undef DECLARE_OPERAND_TYPE_TRAITS

#define DECLARE_BASIC_OPERAND_TYPE_LIMITS_TRAITS(Name, CType, MinValue, \
                                                 MaxValue)              \
  template <>                                                           \
  struct OperandTypeTraits<BytecodeOperandType::k##Name> {              \
    static_assert(!std::is_pointer_v<CType>);                           \
    static constexpr uint8_t kSize = sizeof(CType);                     \
    using kCType = CType;                                               \
    static constexpr bool kIsBasic = true;                              \
    static_assert(std::is_enum_v<kCType> ||                             \
                  MinValue >= std::numeric_limits<kCType>::min());      \
    static_assert(std::is_enum_v<kCType> ||                             \
                  MaxValue <= std::numeric_limits<kCType>::max());      \
    static constexpr kCType kMinValue = MinValue;                       \
    static constexpr kCType kMaxValue = MaxValue;                       \
    static constexpr size_t kAlignment = kSize;                         \
  };
BASIC_BYTECODE_OPERAND_TYPE_LIMITS_LIST(
    DECLARE_BASIC_OPERAND_TYPE_LIMITS_TRAITS)
#undef DECLARE_OPERAND_TYPE_LIMITS_TRAITS

#define DECLARE_SPECIAL_OPERAND_TYPE_TRAITS(Name, Size, Alignment) \
  template <>                                                      \
  struct OperandTypeTraits<BytecodeOperandType::k##Name> {         \
    static constexpr uint8_t kSize = Size;                         \
    static constexpr bool kIsBasic = false;                        \
    static constexpr size_t kAlignment = Alignment;                \
    static_assert(IsAligned(kSize, kAlignment));                   \
  };
SPECIAL_BYTECODE_OPERAND_TYPE_LIST(DECLARE_SPECIAL_OPERAND_TYPE_TRAITS)
#undef DECLARE_OPERAND_TYPE_TRAITS

namespace detail {

template <auto... Args>
constexpr int CountOf() {
  return sizeof...(Args);
}

template <size_t N>
constexpr std::array<std::string_view, N> SplitNames(const char* raw_names) {
  std::array<std::string_view, N> result;
  std::string_view names(raw_names);

  // Remove '(' and ')'.
  DCHECK_EQ(names.front(), '(');
  DCHECK_EQ(names.back(), ')');
  size_t start = 1;
  size_t names_size = names.size() - 1;

  for (size_t i = 0; i < N; ++i) {
    size_t comma = names.find(',', start);
    DCHECK_EQ(i == N - 1, comma == std::string_view::npos);

    // Trim whitespace.
    start = names.find_first_not_of(" ", start);
    size_t end = (comma == std::string_view::npos) ? names_size : comma;
    end = names.find_last_not_of(" ,)", end) + 1;
    result[i] = names.substr(start, end - start);

    start = comma + 1;
  }

  return result;
}

// Calculates packed offsets for each Bytecode operand.
// All operands are aligned to their own size.
template <BytecodeOperandType... operand_types>
constexpr auto CalculateAlignedOffsets() {
  constexpr int N = sizeof...(operand_types);
  constexpr std::array<uint8_t, N> kOperandSizes = {
      OperandTypeTraits<operand_types>::kSize...};
  constexpr std::array<uint8_t, N> kOperandAlignments = {
      OperandTypeTraits<operand_types>::kAlignment...};

  std::array<int, N> offsets{};
  int first_offset = sizeof(Bytecode);
  int offset = first_offset;

  for (size_t i = 0; i < N; ++i) {
    uint8_t operand_size = kOperandSizes[i];
    size_t operand_alignment = kOperandAlignments[i];

    offset = RoundUp(offset, operand_alignment);

    // If the operand doesn't fit into the current 4-byte block, start a new
    // 4-byte block.
    if ((offset % kBytecodeAlignment) + operand_size > kBytecodeAlignment) {
      offset = RoundUp<kBytecodeAlignment>(offset);
    }

    offsets[i] = offset;
    offset += operand_size;
  }

  return offsets;
}

template <BytecodeOperandType... ops>
struct BytecodeOperandsTraits {
  static constexpr int kOperandCount = sizeof...(ops);
  static constexpr std::array<BytecodeOperandType, kOperandCount>
      kOperandTypes = {ops...};
  static constexpr std::array<uint8_t, kOperandCount> kOperandSizes = {
      OperandTypeTraits<ops>::kSize...};
  static constexpr std::array<uint8_t, kOperandCount> kOperandAlignments = {
      OperandTypeTraits<ops>::kAlignment...};
  static constexpr std::array<int, kOperandCount> kOperandOffsets =
      CalculateAlignedOffsets<ops...>();
  static constexpr int kSize = RoundUp<kBytecodeAlignment>(
      kOperandCount == 0 ? sizeof(Bytecode)
                         : kOperandOffsets.back() + kOperandSizes.back());
};

template <Bytecode bc>
struct BytecodeOperandNames;

#define DECLARE_OPERAND_NAMES(CamelName, OpNames, OpTypes, ...)           \
  template <>                                                             \
  struct BytecodeOperandNames<Bytecode::k##CamelName> {                   \
    enum Operand { UNPAREN(OpNames) };                                    \
    static constexpr size_t kCount = detail::CountOf<UNPAREN(OpNames)>(); \
    static constexpr auto kNames = detail::SplitNames<kCount>(#OpNames);  \
    static constexpr std::string_view Name(Operand op) {                  \
      return kNames[static_cast<size_t>(op)];                             \
    }                                                                     \
  };
REGEXP_BYTECODE_LIST(DECLARE_OPERAND_NAMES)
#undef DECLARE_OPERAND_NAMES

template <Bytecode bc, BytecodeOperandType... OpTypes>
class BytecodeOperandsBase : public BytecodeOperandNames<bc> {
 public:
  static constexpr Bytecode kBytecode = bc;
  using Operand = BytecodeOperandNames<bc>::Operand;
  using Traits = BytecodeOperandsTraits<OpTypes...>;
  static constexpr int kCount = Traits::kOperandCount;
  static constexpr int kTotalSize = Traits::kSize;
  static constexpr int Index(Operand op) { return static_cast<uint8_t>(op); }
  static constexpr int Size(Operand op) {
    return Traits::kOperandSizes[Index(op)];
  }
  static constexpr int Offset(Operand op) {
    return Traits::kOperandOffsets[Index(op)];
  }
  static constexpr BytecodeOperandType Type(Operand op) {
    return Traits::kOperandTypes[Index(op)];
  }

  static constexpr std::string_view Name(Operand op) {
    return BytecodeOperandNames<bc>::Name(op);
  }

  // Returns a tuple of all operands.
  static constexpr auto GetOperandsTuple() {
    return []<size_t... Is>(std::index_sequence<Is...>) {
      return std::tuple_cat([]<size_t I>() {
        constexpr auto id = static_cast<Operand>(I);
        return std::tuple(std::integral_constant<Operand, id>{});
      }.template operator()<Is>()...);
    }(std::make_index_sequence<kCount>{});
  }

  // Calls |f| templatized by Operand for each Operand in the Operands list.
  // Example:
  // using Operands = BytecodeOperands<Bytecode::...>;
  // size_t op_sizes = 0;
  // Operands::ForEachOperand([]<auto op>() {
  //   op_sizes += Operands::Size(op);
  // });
  // Note that this gets evaluated at compile time, so op_sizes in the example
  // above is essentially a constant.
  template <typename Func>
  static constexpr void ForEachOperand(Func&& f) {
    constexpr auto filtered_ops = GetOperandsTuple();
    std::apply([&](auto... ops) { (..., f.template operator()<ops.value>()); },
               filtered_ops);
  }

  // Similar to ForEachOperand, but additionally provides the current index as
  // a template argument. The index is a sequential index of operands.
  template <typename Func>
  static constexpr void ForEachOperandWithIndex(Func&& f) {
    constexpr auto filtered_ops = GetOperandsTuple();
    [&]<size_t... I>(std::index_sequence<I...>) {
      (...,
       f.template operator()<
           std::tuple_element_t<I, decltype(filtered_ops)>::value /* Operand */,
           I /* Index */>());
    }(std::make_index_sequence<std::tuple_size_v<decltype(filtered_ops)>>{});
  }

  // Similar to above, but calls |f| only for operands of a given type.
  template <BytecodeOperandType OpType, typename Func>
  static constexpr void ForEachOperandOfType(Func&& f) {
    ForEachOperand([&]<auto operand>() {
      if constexpr (Type(operand) == OpType) {
        f.template operator()<operand>();
      }
    });
  }

 public:
  template <Operand op>
    requires(OperandTypeTraits<Type(op)>::kIsBasic)
  static auto Get(const uint8_t* pc, const DisallowGarbageCollection& no_gc) {
    DCHECK_EQ(Bytecodes::FromPtr(pc), bc);
    constexpr BytecodeOperandType OperandType = Type(op);
    constexpr int offset = Offset(op);
    using CType = OperandTypeTraits<OperandType>::kCType;
    DCHECK(IsAligned(offset, sizeof(CType)));
    return *reinterpret_cast<const CType*>(pc + offset);
  }

  template <Operand op>
    requires(OperandTypeTraits<Type(op)>::kIsBasic)
  static auto Get(DirectHandle<TrustedByteArray> bytecode, int offset,
                  Zone* zone) {
    // Basic operand types won't allocate, so we can always fallback to the
    // GC-unsafe version.
    DisallowGarbageCollection no_gc;
    return Get<op>(bytecode->begin() + offset, no_gc);
  }

  template <Operand op>
    requires(Type(op) == BytecodeOperandType::kBitTable)
  static auto Get(const uint8_t* pc,
                  const DisallowGarbageCollection& no_gc V8_LIFETIME_BOUND) {
    static_assert(Size(op) == RegExpMacroAssembler::kTableSize / kBitsPerByte);
    DCHECK_EQ(Bytecodes::FromPtr(pc), bc);
    constexpr int offset = Offset(op);
    return pc + offset;
  }

  template <Operand op>
    requires(Type(op) == BytecodeOperandType::kBitTable)
  static auto Get(DirectHandle<TrustedByteArray> bytecode, int offset,
                  Zone* zone) {
    static_assert(Size(op) == RegExpMacroAssembler::kTableSize / kBitsPerByte);
    DCHECK_EQ(Bytecodes::FromPtr(bytecode->begin() + offset), bc);
    constexpr int op_offset = Offset(op);
    const uint8_t* start = bytecode->begin() + offset + op_offset;
    const uint8_t* end = start + Size(op);
    return ZoneVector<uint8_t>(start, end, zone);
  }
};

}  // namespace detail

#define PACK_OPTIONAL(x, ...) x __VA_OPT__(, ) __VA_ARGS__

#define DECLARE_OPERANDS(CamelName, OpNames, OpTypes, ...) \
  template <>                                              \
  class BytecodeOperands<Bytecode::k##CamelName> final     \
      : public detail::BytecodeOperandsBase<PACK_OPTIONAL( \
            Bytecode::k##CamelName, UNPAREN(OpTypes))>,    \
        public AllStatic {                                 \
  };

REGEXP_BYTECODE_LIST(DECLARE_OPERANDS)
#undef DECLARE_OPERANDS

namespace detail {

#define DECLARE_BYTECODE_NAMES(CamelName, ...) #CamelName,
static constexpr const char* kBytecodeNames[] = {
    REGEXP_BYTECODE_LIST(DECLARE_BYTECODE_NAMES)};
#undef DECLARE_BYTECODE_NAMES

#define DECLARE_BYTECODE_SIZES(CamelName, ...) \
  BytecodeOperands<Bytecode::k##CamelName>::kTotalSize,
static constexpr uint8_t kBytecodeSizes[] = {
    REGEXP_BYTECODE_LIST(DECLARE_BYTECODE_SIZES)};
#undef DECLARE_BYTECODE_SIZES

#define DECLARE_BYTECODE_FLAGS(CamelName, OpNames, OpTypes, Flags) \
  BytecodeFlags(UNPAREN(Flags)),
static constexpr BytecodeFlags kBytecodeFlags[] = {
    REGEXP_BYTECODE_LIST(DECLARE_BYTECODE_FLAGS)};
#undef DECLARE_BYTECODE_FLAGS

#define DECLARE_OPERAND_TYPE_SIZE(Name, ...) \
  OperandTypeTraits<BytecodeOperandType::k##Name>::kSize,
static constexpr uint8_t kOperandTypeSizes[] = {
    BYTECODE_OPERAND_TYPE_LIST(DECLARE_OPERAND_TYPE_SIZE)};
#undef DECLARE_OPERAND_TYPE_SIZE

}  // namespace detail

// static
template <typename Func>
decltype(auto) Bytecodes::DispatchOnBytecode(Bytecode bytecode, Func&& f) {
  switch (bytecode) {
#define CASE(CamelName, ...)   \
  case Bytecode::k##CamelName: \
    return f.template operator()<Bytecode::k##CamelName>();
    REGEXP_BYTECODE_LIST(CASE)
#undef CASE
  }
  UNREACHABLE();
}

// static
constexpr const char* Bytecodes::Name(Bytecode bytecode) {
  return Name(ToByte(bytecode));
}

// static
constexpr const char* Bytecodes::Name(uint8_t bytecode) {
  DCHECK_LT(bytecode, kCount);
  return detail::kBytecodeNames[bytecode];
}

// static
constexpr uint8_t Bytecodes::Size(Bytecode bytecode) {
  return Size(ToByte(bytecode));
}

// static
constexpr uint8_t Bytecodes::Size(uint8_t bytecode) {
  DCHECK_LT(bytecode, kCount);
  return detail::kBytecodeSizes[bytecode];
}

// static
constexpr uint8_t Bytecodes::Size(BytecodeOperandType type) {
  return detail::kOperandTypeSizes[static_cast<int>(type)];
}

// static
constexpr BytecodeFlags Bytecodes::Flags(Bytecode bytecode) {
  return Flags(ToByte(bytecode));
}

// static
constexpr BytecodeFlags Bytecodes::Flags(uint8_t bytecode) {
  DCHECK_LT(bytecode, kCount);
  return detail::kBytecodeFlags[bytecode];
}

}  // namespace regexp
}  // namespace internal
}  // namespace v8

#endif  // V8_REGEXP_REGEXP_BYTECODES_INL_H_

Messung V0.5 in Prozent
C=90 H=99 G=94

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-09-30) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.