Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ParserAtom.h   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef frontend_ParserAtom_h
#define frontend_ParserAtom_h

#include "mozilla/MemoryReporting.h"  // mozilla::MallocSizeOf
#include "mozilla/Range.h"            // mozilla::Range
#include "mozilla/Span.h"             // mozilla::Span
#include "mozilla/TextUtils.h"

#include <stddef.h>
#include <stdint.h>

#include "jstypes.h"
#include "NamespaceImports.h"

#include "frontend/TypedIndex.h"  // TypedIndex
#include "js/HashTable.h"         // HashMap
#include "js/ProtoKey.h"          // JS_FOR_EACH_PROTOTYPE
#include "js/Symbol.h"            // JS_FOR_EACH_WELL_KNOWN_SYMBOL
#include "js/TypeDecls.h"         // Latin1Char
#include "js/Utility.h"           // UniqueChars
#include "js/Vector.h"            // Vector
#include "threading/Mutex.h"      // Mutex
#include "util/Text.h"            // InflatedChar16Sequence
#include "vm/CommonPropertyNames.h"
#include "vm/StaticStrings.h"
#include "vm/WellKnownAtom.h"  // WellKnownAtomId, WellKnownAtomInfo

struct JS_PUBLIC_API JSContext;

class JSAtom;
class JSString;

namespace mozilla {
union Utf8Unit;
}

namespace js {

class AtomSet;
class JS_PUBLIC_API GenericPrinter;
class LifoAlloc;
class StringBuilder;

namespace frontend {

struct CompilationAtomCache;
struct CompilationStencil;

template <typename CharT>
class SpecificParserAtomLookup;

// These types correspond into indices in the StaticStrings arrays.
enum class Length1StaticParserString : uint8_t;
enum class Length2StaticParserString : uint16_t;
enum class Length3StaticParserString : uint8_t;

class ParserAtom;
using ParserAtomIndex = TypedIndex<ParserAtom>;

// ParserAtomIndex, WellKnownAtomId, Length1StaticParserString,
// Length2StaticParserString, Length3StaticParserString, or null.
//
// 0x0000_0000  Null atom
//
// 0x1YYY_YYYY  28-bit ParserAtom
//
// 0x2000_YYYY  Well-known atom ID
// 0x2001_YYYY  Static length-1 atom : whole Latin1 range
// 0x2002_YYYY  Static length-2 atom : `[A-Za-z0-9$_]{2}`
// 0x2003_YYYY  Static length-3 atom : decimal "100" to "255"
class TaggedParserAtomIndex {
  uint32_t data_;

 public:
  static constexpr size_t IndexBit = 28;
  static constexpr size_t IndexMask = BitMask(IndexBit);

  static constexpr size_t TagShift = IndexBit;
  static constexpr size_t TagBit = 4;
  static constexpr size_t TagMask = BitMask(TagBit) << TagShift;

  enum class Kind : uint32_t {
    Null = 0,
    ParserAtomIndex,
    WellKnown,
  };

 private:
  static constexpr size_t SmallIndexBit = 16;
  static constexpr size_t SmallIndexMask = BitMask(SmallIndexBit);

  static constexpr size_t SubTagShift = SmallIndexBit;
  static constexpr size_t SubTagBit = 2;
  static constexpr size_t SubTagMask = BitMask(SubTagBit) << SubTagShift;

 public:
  static constexpr uint32_t NullTag = uint32_t(Kind::Null) << TagShift;
  static constexpr uint32_t ParserAtomIndexTag = uint32_t(Kind::ParserAtomIndex)
                                                 << TagShift;
  static constexpr uint32_t WellKnownTag = uint32_t(Kind::WellKnown)
                                           << TagShift;

 private:
  static constexpr uint32_t WellKnownSubTag = 0 << SubTagShift;
  static constexpr uint32_t Length1StaticSubTag = 1 << SubTagShift;
  static constexpr uint32_t Length2StaticSubTag = 2 << SubTagShift;
  static constexpr uint32_t Length3StaticSubTag = 3 << SubTagShift;

 public:
  static constexpr uint32_t IndexLimit = Bit(IndexBit);
  static constexpr uint32_t SmallIndexLimit = Bit(SmallIndexBit);

  static constexpr size_t Length1StaticLimit = 256U;
  static constexpr size_t Length2StaticLimit =
      StaticStrings::NUM_LENGTH2_ENTRIES;
  static constexpr size_t Length3StaticLimit = 256U;

 private:
  explicit TaggedParserAtomIndex(uint32_t data) : data_(data) {}

 public:
  constexpr TaggedParserAtomIndex() : data_(NullTag) {}

  explicit constexpr TaggedParserAtomIndex(ParserAtomIndex index)
      : data_(index.index | ParserAtomIndexTag) {
    MOZ_ASSERT(index.index < IndexLimit);
  }
  explicit constexpr TaggedParserAtomIndex(WellKnownAtomId index)
      : data_(uint32_t(index) | WellKnownTag | WellKnownSubTag) {
    MOZ_ASSERT(uint32_t(index) < SmallIndexLimit);

    // Length1Static/Length2Static string shouldn't use WellKnownAtomId.
#define CHECK_(NAME, _) MOZ_ASSERT(index != WellKnownAtomId::NAME);
    FOR_EACH_NON_EMPTY_TINY_PROPERTYNAME(CHECK_)
#undef CHECK_
  }
  explicit constexpr TaggedParserAtomIndex(Length1StaticParserString index)
      : data_(uint32_t(index) | WellKnownTag | Length1StaticSubTag) {}
  explicit constexpr TaggedParserAtomIndex(Length2StaticParserString index)
      : data_(uint32_t(index) | WellKnownTag | Length2StaticSubTag) {}
  explicit constexpr TaggedParserAtomIndex(Length3StaticParserString index)
      : data_(uint32_t(index) | WellKnownTag | Length3StaticSubTag) {}

  class WellKnown {
   public:
#define METHOD_(NAME, _)                                 \
  static constexpr TaggedParserAtomIndex NAME() {        \
    return TaggedParserAtomIndex(WellKnownAtomId::NAME); \
  }
    FOR_EACH_NONTINY_COMMON_PROPERTYNAME(METHOD_)
#undef METHOD_

#define METHOD_(NAME, _)                                 \
  static constexpr TaggedParserAtomIndex NAME() {        \
    return TaggedParserAtomIndex(WellKnownAtomId::NAME); \
  }
    JS_FOR_EACH_PROTOTYPE(METHOD_)
#undef METHOD_

#define METHOD_(NAME)                                    \
  static constexpr TaggedParserAtomIndex NAME() {        \
    return TaggedParserAtomIndex(WellKnownAtomId::NAME); \
  }
    JS_FOR_EACH_WELL_KNOWN_SYMBOL(METHOD_)
#undef METHOD_

#define METHOD_(NAME, STR)                                             \
  static constexpr TaggedParserAtomIndex NAME() {                      \
    return TaggedParserAtomIndex(Length1StaticParserString((STR)[0])); \
  }
    FOR_EACH_LENGTH1_PROPERTYNAME(METHOD_)
#undef METHOD_

#define METHOD_(NAME, STR)                                            \
  static constexpr TaggedParserAtomIndex NAME() {                     \
    return TaggedParserAtomIndex(Length2StaticParserString(           \
        (StaticStrings::getLength2IndexStatic((STR)[0], (STR)[1])))); \
  }
    FOR_EACH_LENGTH2_PROPERTYNAME(METHOD_)
#undef METHOD_

    static constexpr TaggedParserAtomIndex empty() {
      return TaggedParserAtomIndex(WellKnownAtomId::empty_);
    }
  };

  // The value of rawData() for WellKnown TaggedParserAtomIndex.
  // For using in switch-case.
  class WellKnownRawData {
   public:
#define METHOD_(NAME, _)                                                     \
  static constexpr uint32_t NAME() {                                         \
    return uint32_t(WellKnownAtomId::NAME) | WellKnownTag | WellKnownSubTag; \
  }
    FOR_EACH_NONTINY_COMMON_PROPERTYNAME(METHOD_)
#undef METHOD_

#define METHOD_(NAME, _)                                                     \
  static constexpr uint32_t NAME() {                                         \
    return uint32_t(WellKnownAtomId::NAME) | WellKnownTag | WellKnownSubTag; \
  }
    JS_FOR_EACH_PROTOTYPE(METHOD_)
#undef METHOD_

#define METHOD_(NAME)                                                        \
  static constexpr uint32_t NAME() {                                         \
    return uint32_t(WellKnownAtomId::NAME) | WellKnownTag | WellKnownSubTag; \
  }
    JS_FOR_EACH_WELL_KNOWN_SYMBOL(METHOD_)
#undef METHOD_

#define METHOD_(NAME, STR)                                          \
  static constexpr uint32_t NAME() {                                \
    return uint32_t((STR)[0]) | WellKnownTag | Length1StaticSubTag; \
  }
    FOR_EACH_LENGTH1_PROPERTYNAME(METHOD_)
#undef METHOD_

#define METHOD_(NAME, STR)                                                 \
  static constexpr uint32_t NAME() {                                       \
    return uint32_t(                                                       \
               StaticStrings::getLength2IndexStatic((STR)[0], (STR)[1])) | \
           WellKnownTag | Length2StaticSubTag;                             \
  }
    FOR_EACH_LENGTH2_PROPERTYNAME(METHOD_)
#undef METHOD_

    static constexpr uint32_t empty() {
      return uint32_t(WellKnownAtomId::empty_) | WellKnownTag | WellKnownSubTag;
    }
  };

  // NOTE: this is not well-known "null".
  static TaggedParserAtomIndex null() { return TaggedParserAtomIndex(); }

#ifdef DEBUG
  void validateRaw();
#endif

  static TaggedParserAtomIndex fromRaw(uint32_t data) {
    auto result = TaggedParserAtomIndex(data);
#ifdef DEBUG
    result.validateRaw();
#endif
    return result;
  }

  bool isParserAtomIndex() const {
    return (data_ & TagMask) == ParserAtomIndexTag;
  }
  bool isWellKnownAtomId() const {
    return (data_ & (TagMask | SubTagMask)) == (WellKnownTag | WellKnownSubTag);
  }
  bool isLength1StaticParserString() const {
    return (data_ & (TagMask | SubTagMask)) ==
           (WellKnownTag | Length1StaticSubTag);
  }
  bool isLength2StaticParserString() const {
    return (data_ & (TagMask | SubTagMask)) ==
           (WellKnownTag | Length2StaticSubTag);
  }
  bool isLength3StaticParserString() const {
    return (data_ & (TagMask | SubTagMask)) ==
           (WellKnownTag | Length3StaticSubTag);
  }
  bool isNull() const {
    bool result = !data_;
    MOZ_ASSERT_IF(result, (data_ & TagMask) == NullTag);
    return result;
  }
  HashNumber staticOrWellKnownHash() const;

  ParserAtomIndex toParserAtomIndex() const {
    MOZ_ASSERT(isParserAtomIndex());
    return ParserAtomIndex(data_ & IndexMask);
  }
  WellKnownAtomId toWellKnownAtomId() const {
    MOZ_ASSERT(isWellKnownAtomId());
    return WellKnownAtomId(data_ & SmallIndexMask);
  }
  Length1StaticParserString toLength1StaticParserString() const {
    MOZ_ASSERT(isLength1StaticParserString());
    return Length1StaticParserString(data_ & SmallIndexMask);
  }
  Length2StaticParserString toLength2StaticParserString() const {
    MOZ_ASSERT(isLength2StaticParserString());
    return Length2StaticParserString(data_ & SmallIndexMask);
  }
  Length3StaticParserString toLength3StaticParserString() const {
    MOZ_ASSERT(isLength3StaticParserString());
    return Length3StaticParserString(data_ & SmallIndexMask);
  }

  uint32_t* rawDataRef() { return &data_; }
  uint32_t rawData() const { return data_; }

  bool operator==(const TaggedParserAtomIndex& rhs) const {
    return data_ == rhs.data_;
  }
  bool operator!=(const TaggedParserAtomIndex& rhs) const {
    return data_ != rhs.data_;
  }

  explicit operator bool() const { return !isNull(); }
};

// Trivial variant of TaggedParserAtomIndex, to use in collection that requires
// trivial type.
// Provides minimal set of methods to use in collection.
class TrivialTaggedParserAtomIndex {
  uint32_t data_;

 public:
  static TrivialTaggedParserAtomIndex from(TaggedParserAtomIndex index) {
    TrivialTaggedParserAtomIndex result;
    result.data_ = index.rawData();
    return result;
  }

  operator TaggedParserAtomIndex() const {
    return TaggedParserAtomIndex::fromRaw(data_);
  }

  static TrivialTaggedParserAtomIndex null() {
    TrivialTaggedParserAtomIndex result;
    result.data_ = 0;
    return result;
  }

  bool isNull() const {
    static_assert(TaggedParserAtomIndex::NullTag == 0);
    return data_ == 0;
  }

  uint32_t rawData() const { return data_; }

  bool operator==(const TrivialTaggedParserAtomIndex& rhs) const {
    return data_ == rhs.data_;
  }
  bool operator!=(const TrivialTaggedParserAtomIndex& rhs) const {
    return data_ != rhs.data_;
  }

  explicit operator bool() const { return !isNull(); }
};

/**
 * A ParserAtom is an in-parser representation of an interned atomic
 * string.  It mostly mirrors the information carried by a JSAtom*.
 *
 * The atom contents are stored in one of two locations:
 *  1. Inline Latin1Char storage (immediately after the ParserAtom memory).
 *  2. Inline char16_t storage (immediately after the ParserAtom memory).
 */

class alignas(alignof(uint32_t)) ParserAtom {
  friend class ParserAtomsTable;
  friend class WellKnownParserAtoms;

  static const uint16_t MAX_LATIN1_CHAR = 0xff;

  // Bit flags inside flags_.
  static constexpr uint32_t HasTwoByteCharsFlag = 1 << 0;
  static constexpr uint32_t UsedByStencilFlag = 1 << 1;
  static constexpr uint32_t AtomizeFlag = 1 << 2;

 public:
  // Whether to atomize the ParserAtom during instantiation.
  //
  // If this ParserAtom is used by opcode with JOF_ATOM, or used as a binding
  // in scope, it needs to be instantiated as JSAtom.
  // Otherwise, it needs to be instantiated as LinearString, to reduce the
  // cost of atomization.
  enum class Atomize : uint32_t {
    No = 0,
    Yes = AtomizeFlag,
  };

 private:
  // Helper routine to read some sequence of two-byte chars, and write them
  // into a target buffer of a particular character width.
  //
  // The characters in the sequence must have been verified prior
  template <typename CharT, typename SeqCharT>
  static void drainChar16Seq(CharT* buf, InflatedChar16Sequence<SeqCharT> seq,
                             uint32_t length) {
    static_assert(
        std::is_same_v<CharT, char16_t> || std::is_same_v<CharT, Latin1Char>,
        "Invalid target buffer type.");
    CharT* cur = buf;
    while (seq.hasMore()) {
      char16_t ch = seq.next();
      if constexpr (std::is_same_v<CharT, Latin1Char>) {
        MOZ_ASSERT(ch <= MAX_LATIN1_CHAR);
      }
      MOZ_ASSERT(cur < (buf + length));
      *cur = ch;
      cur++;
    }
  }

 private:
  // The JSAtom-compatible hash of the string.
  HashNumber hash_ = 0;

  // The length of the buffer in chars_.
  uint32_t length_ = 0;

  uint32_t flags_ = 0;

  // End of fields.

  ParserAtom(uint32_t length, HashNumber hash, bool hasTwoByteChars)
      : hash_(hash),
        length_(length),
        flags_(hasTwoByteChars ? HasTwoByteCharsFlag : 0) {}

 public:
  // The constexpr constructor is used by XDR
  constexpr ParserAtom() = default;

  // ParserAtoms may own their content buffers in variant_, and thus
  // cannot be copy-constructed - as a new chars would need to be allocated.
  ParserAtom(const ParserAtom&) = delete;
  ParserAtom(ParserAtom&& other) = delete;

  template <typename CharT, typename SeqCharT>
  static ParserAtom* allocate(FrontendContext* fc, LifoAlloc& alloc,
                              InflatedChar16Sequence<SeqCharT> seq,
                              uint32_t length, HashNumber hash);

  bool hasLatin1Chars() const { return !(flags_ & HasTwoByteCharsFlag); }
  bool hasTwoByteChars() const { return flags_ & HasTwoByteCharsFlag; }

  bool isAscii() const {
    if (hasTwoByteChars()) {
      return false;
    }
    for (Latin1Char ch : latin1Range()) {
      if (!mozilla::IsAscii(ch)) {
        return false;
      }
    }
    return true;
  }

  bool isPrivateName() const {
    if (length() < 2) {
      return false;
    }

    return charAt(0) == '#';
  }

  HashNumber hash() const { return hash_; }
  uint32_t length() const { return length_; }

  bool isUsedByStencil() const { return flags_ & UsedByStencilFlag; }

 private:
  bool isMarkedAtomize() const { return flags_ & AtomizeFlag; }

  static constexpr uint32_t MinimumLengthForNonAtom = 8;

 public:
  bool isInstantiatedAsJSAtom() const;

  template <typename CharT>
  bool equalsSeq(HashNumber hash, InflatedChar16Sequence<CharT> seq) const;

  // Convert NotInstantiated and usedByStencil entry to a js-atom.
  JSString* instantiateString(JSContext* cx, FrontendContext* fc,
                              ParserAtomIndex index,
                              CompilationAtomCache& atomCache) const;
  JSAtom* instantiateAtom(JSContext* cx, FrontendContext* fc,
                          ParserAtomIndex index,
                          CompilationAtomCache& atomCache) const;
  JSAtom* instantiatePermanentAtom(JSContext* cx, FrontendContext* fc,
                                   AtomSet& atomSet, ParserAtomIndex index,
                                   CompilationAtomCache& atomCache) const;

 private:
  void markUsedByStencil(Atomize atomize) {
    flags_ |= UsedByStencilFlag | uint32_t(atomize);
  }
  void markAtomize(Atomize atomize) { flags_ |= uint32_t(atomize); }

  template <typename CharT>
  const CharT* chars() const {
    MOZ_ASSERT(sizeof(CharT) == (hasTwoByteChars() ? 2 : 1));
    return reinterpret_cast<const CharT*>(this + 1);
  }

  template <typename CharT>
  CharT* chars() {
    MOZ_ASSERT(sizeof(CharT) == (hasTwoByteChars() ? 2 : 1));
    return reinterpret_cast<CharT*>(this + 1);
  }

  const Latin1Char* latin1Chars() const { return chars<Latin1Char>(); }
  const char16_t* twoByteChars() const { return chars<char16_t>(); }
  mozilla::Range<const Latin1Char> latin1Range() const {
    return mozilla::Range(latin1Chars(), length_);
  }
  mozilla::Range<const char16_t> twoByteRange() const {
    return mozilla::Range(twoByteChars(), length_);
  }

  // Returns index-th char.
  // Boundary check isn't performed.
  char16_t charAt(size_t index) const {
    MOZ_ASSERT(index < length());
    if (hasLatin1Chars()) {
      return latin1Chars()[index];
    }
    return twoByteChars()[index];
  }

 public:
#if defined(DEBUG) || defined(JS_JITSPEW)
  void dump() const;
  void dumpCharsNoQuote(js::GenericPrinter& out) const;
#endif
};

/**
 * A lookup structure that allows for querying ParserAtoms in
 * a hashtable using a flexible input type that supports string
 * representations of various forms.
 */

class ParserAtomLookup {
 protected:
  HashNumber hash_;

  ParserAtomLookup(HashNumber hash) : hash_(hash) {}

 public:
  HashNumber hash() const { return hash_; }

  virtual bool equalsEntry(const ParserAtom* entry) const = 0;
  virtual bool equalsEntry(const WellKnownAtomInfo* info) const = 0;
};

struct ParserAtomLookupHasher {
  using Lookup = ParserAtomLookup;

  static inline HashNumber hash(const Lookup& l) { return l.hash(); }
  static inline bool match(const ParserAtom* entry, const Lookup& l) {
    return l.equalsEntry(entry);
  }
};

struct WellKnownAtomInfoHasher {
  using Lookup = ParserAtomLookup;

  static inline HashNumber hash(const Lookup& l) { return l.hash(); }
  static inline bool match(const WellKnownAtomInfo* info, const Lookup& l) {
    return l.equalsEntry(info);
  }
};

using ParserAtomVector = Vector<ParserAtom*, 0, js::SystemAllocPolicy>;
using ParserAtomSpan = mozilla::Span<ParserAtom*>;

/**
 * WellKnownParserAtoms allows the parser to lookup up specific atoms in
 * constant time.
 */

class WellKnownParserAtoms {
  static WellKnownParserAtoms singleton_;

  // Common property and prototype names are tracked in a hash table. This table
  // does not key for any items already in a direct-indexing tiny atom table.
  using EntryMap = HashMap<const WellKnownAtomInfo*, TaggedParserAtomIndex,
                           WellKnownAtomInfoHasher, js::SystemAllocPolicy>;
  EntryMap wellKnownMap_;

  bool initSingle(const WellKnownAtomInfo& info, TaggedParserAtomIndex index);

  bool init();
  void free();

 public:
  static bool initSingleton();
  static void freeSingleton();

  static WellKnownParserAtoms& getSingleton() {
    MOZ_ASSERT(!singleton_.wellKnownMap_.empty());
    return singleton_;
  }

  // Maximum length of any well known atoms. This can be increased if needed.
  static constexpr size_t MaxWellKnownLength = 32;

  template <typename CharT>
  TaggedParserAtomIndex lookupChar16Seq(
      const SpecificParserAtomLookup<CharT>& lookup) const;

  template <typename CharsT>
  TaggedParserAtomIndex lookupTinyIndex(CharsT chars, size_t length) const {
    static_assert(std::is_same_v<CharsT, const Latin1Char*> ||
                      std::is_same_v<CharsT, const char16_t*> ||
                      std::is_same_v<CharsT, const char*> ||
                      std::is_same_v<CharsT, char16_t*>,
                  "This assert mostly explicitly documents the calling types, "
                  "and forces that to be updated if new types show up.");
    switch (length) {
      case 0:
        return TaggedParserAtomIndex::WellKnown::empty();

      case 1: {
        if (char16_t(chars[0]) < TaggedParserAtomIndex::Length1StaticLimit) {
          return TaggedParserAtomIndex(Length1StaticParserString(chars[0]));
        }
        break;
      }

      case 2:
        if (StaticStrings::fitsInSmallChar(chars[0]) &&
            StaticStrings::fitsInSmallChar(chars[1])) {
          return TaggedParserAtomIndex(Length2StaticParserString(
              StaticStrings::getLength2Index(chars[0], chars[1])));
        }
        break;

      case 3: {
        int i;
        if (StaticStrings::fitsInLength3Static(chars[0], chars[1], chars[2],
                                               &i)) {
          return TaggedParserAtomIndex(Length3StaticParserString(i));
        }
        break;
      }
    }

    // No match on tiny Atoms
    return TaggedParserAtomIndex::null();
  }

  TaggedParserAtomIndex lookupTinyIndexUTF8(const mozilla::Utf8Unit* utf8Ptr,
                                            size_t nbyte) const;

  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    return wellKnownMap_.shallowSizeOfExcludingThis(mallocSizeOf);
  }
};

bool InstantiateMarkedAtoms(JSContext* cx, FrontendContext* fc,
                            const ParserAtomSpan& entries,
                            CompilationAtomCache& atomCache);

bool InstantiateMarkedAtomsAsPermanent(JSContext* cx, FrontendContext* fc,
                                       AtomSet& atomSet,
                                       const ParserAtomSpan& entries,
                                       CompilationAtomCache& atomCache);

/**
 * A ParserAtomsTable owns and manages the vector of ParserAtom entries
 * associated with a given compile session.
 */

class ParserAtomsTable {
  friend struct CompilationStencil;

 private:
  LifoAlloc* alloc_;

  // The ParserAtom are owned by the LifoAlloc.
  using EntryMap = HashMap<const ParserAtom*, TaggedParserAtomIndex,
                           ParserAtomLookupHasher, js::SystemAllocPolicy>;
  EntryMap entryMap_;
  ParserAtomVector entries_;

 public:
  explicit ParserAtomsTable(LifoAlloc& alloc);
  ParserAtomsTable(ParserAtomsTable&&) = default;
  ParserAtomsTable& operator=(ParserAtomsTable&& other) noexcept {
    entryMap_ = std::move(other.entryMap_);
    entries_ = std::move(other.entries_);
    return *this;
  }

  void fixupAlloc(LifoAlloc& alloc) { alloc_ = &alloc; }

  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    return entryMap_.shallowSizeOfExcludingThis(mallocSizeOf) +
           entries_.sizeOfExcludingThis(mallocSizeOf);
  }
  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
  }

 private:
  // Internal APIs for interning to the table after well-known atoms cases have
  // been tested.
  TaggedParserAtomIndex addEntry(FrontendContext* fc, EntryMap::AddPtr& addPtr,
                                 ParserAtom* entry);
  template <typename AtomCharT, typename SeqCharT>
  TaggedParserAtomIndex internChar16Seq(FrontendContext* fc,
                                        EntryMap::AddPtr& addPtr,
                                        HashNumber hash,
                                        InflatedChar16Sequence<SeqCharT> seq,
                                        uint32_t length);

  template <typename AtomCharT>
  TaggedParserAtomIndex internExternalParserAtomImpl(FrontendContext* fc,
                                                     const ParserAtom* atom);

 public:
  TaggedParserAtomIndex internAscii(FrontendContext* fc, const char* asciiPtr,
                                    uint32_t length);

  TaggedParserAtomIndex internLatin1(FrontendContext* fc,
                                     const JS::Latin1Char* latin1Ptr,
                                     uint32_t length);

  TaggedParserAtomIndex internUtf8(FrontendContext* fc,
                                   const mozilla::Utf8Unit* utf8Ptr,
                                   uint32_t nbyte);

  TaggedParserAtomIndex internChar16(FrontendContext* fc,
                                     const char16_t* char16Ptr,
                                     uint32_t length);

  TaggedParserAtomIndex internJSAtom(FrontendContext* fc,
                                     CompilationAtomCache& atomCache,
                                     JSAtom* atom);

  // Intern ParserAtom data from other ParserAtomTable.
  // This copies flags as well.
  TaggedParserAtomIndex internExternalParserAtom(FrontendContext* fc,
                                                 const ParserAtom* atom);

  // The atomIndex given as argument is in relation with the context Stencil.
  // The atomIndex might be a well-known or static, in which case this function
  // is a no-op.
  TaggedParserAtomIndex internExternalParserAtomIndex(
      FrontendContext* fc, const CompilationStencil& context,
      TaggedParserAtomIndex atomIndex);

  // Compare an internal atom index with an external atom index coming from the
  // stencil given as argument.
  bool isEqualToExternalParserAtomIndex(TaggedParserAtomIndex internal,
                                        const CompilationStencil& context,
                                        TaggedParserAtomIndex external) const;

  bool addPlaceholder(FrontendContext* fc);

 private:
  const ParserAtom* getWellKnown(WellKnownAtomId atomId) const;
  ParserAtom* getParserAtom(ParserAtomIndex index) const;

 public:
  const ParserAtomVector& entries() const { return entries_; }

  // Accessors for querying atom properties.
  bool isIdentifier(TaggedParserAtomIndex index) const;
  bool isPrivateName(TaggedParserAtomIndex index) const;
  bool isExtendedUnclonedSelfHostedFunctionName(
      TaggedParserAtomIndex index) const;
  bool isModuleExportName(TaggedParserAtomIndex index) const;
  bool isIndex(TaggedParserAtomIndex index, uint32_t* indexp) const;
  bool isInstantiatedAsJSAtom(TaggedParserAtomIndex index) const;
  uint32_t length(TaggedParserAtomIndex index) const;
  HashNumber hash(TaggedParserAtomIndex index) const;

  // Methods for atom.
  void markUsedByStencil(TaggedParserAtomIndex index,
                         ParserAtom::Atomize atomize) const;
  void markAtomize(TaggedParserAtomIndex index,
                   ParserAtom::Atomize atomize) const;
  double toNumber(TaggedParserAtomIndex index) const;
  UniqueChars toNewUTF8CharsZ(FrontendContext* fc,
                              TaggedParserAtomIndex index) const;
  UniqueChars toPrintableString(TaggedParserAtomIndex index) const;
  UniqueChars toQuotedString(TaggedParserAtomIndex index) const;
  JSAtom* toJSAtom(JSContext* cx, FrontendContext* fc,
                   TaggedParserAtomIndex index,
                   CompilationAtomCache& atomCache) const;

 private:
  JSAtom* toWellKnownJSAtom(JSContext* cx, TaggedParserAtomIndex index) const;

 public:
  bool appendTo(StringBuilder& sb, TaggedParserAtomIndex index) const;

 public:
#if defined(DEBUG) || defined(JS_JITSPEW)
  void dump(TaggedParserAtomIndex index) const;
  void dumpCharsNoQuote(js::GenericPrinter& out,
                        TaggedParserAtomIndex index) const;

  static void dumpCharsNoQuote(js::GenericPrinter& out, WellKnownAtomId id);
  static void dumpCharsNoQuote(js::GenericPrinter& out,
                               Length1StaticParserString index);
  static void dumpCharsNoQuote(js::GenericPrinter& out,
                               Length2StaticParserString index);
  static void dumpCharsNoQuote(js::GenericPrinter& out,
                               Length3StaticParserString index);
#endif

  static void getLength1Content(Length1StaticParserString s,
                                Latin1Char contents[1]) {
    contents[0] = Latin1Char(s);
  }

  static void getLength2Content(Length2StaticParserString s, char contents[2]) {
    contents[0] = StaticStrings::firstCharOfLength2(size_t(s));
    contents[1] = StaticStrings::secondCharOfLength2(size_t(s));
  }

  static void getLength3Content(Length3StaticParserString s, char contents[3]) {
    contents[0] = StaticStrings::firstCharOfLength3(int32_t(s));
    contents[1] = StaticStrings::secondCharOfLength3(int32_t(s));
    contents[2] = StaticStrings::thirdCharOfLength3(int32_t(s));
  }
};

// Lightweight version of ParserAtomsTable.
// This doesn't support deduplication.
// Used while decoding XDR.
class ParserAtomSpanBuilder {
  ParserAtomSpan& entries_;

 public:
  explicit ParserAtomSpanBuilder(ParserAtomSpan& entries) : entries_(entries) {}

  bool allocate(FrontendContext* fc, LifoAlloc& alloc, size_t count);

  void set(ParserAtomIndex index, const ParserAtom* atom) {
    entries_[index] = const_cast<ParserAtom*>(atom);
  }
};

template <typename CharT>
class SpecificParserAtomLookup : public ParserAtomLookup {
  // The sequence of characters to look up.
  InflatedChar16Sequence<CharT> seq_;

 public:
  explicit SpecificParserAtomLookup(const InflatedChar16Sequence<CharT>& seq)
      : SpecificParserAtomLookup(seq, seq.computeHash()) {}

  SpecificParserAtomLookup(const InflatedChar16Sequence<CharT>& seq,
                           HashNumber hash)
      : ParserAtomLookup(hash), seq_(seq) {
    MOZ_ASSERT(seq_.computeHash() == hash);
  }

  virtual bool equalsEntry(const ParserAtom* entry) const override {
    return entry->equalsSeq<CharT>(hash_, seq_);
  }

  virtual bool equalsEntry(const WellKnownAtomInfo* info) const override {
    // Compare hashes first.
    if (info->hash != hash_) {
      return false;
    }

    InflatedChar16Sequence<CharT> seq = seq_;
    for (uint32_t i = 0; i < info->length; i++) {
      if (!seq.hasMore() || char16_t(info->content[i]) != seq.next()) {
        return false;
      }
    }
    return !seq.hasMore();
  }
};

template <typename CharT>
inline bool ParserAtom::equalsSeq(HashNumber hash,
                                  InflatedChar16Sequence<CharT> seq) const {
  // Compare hashes first.
  if (hash_ != hash) {
    return false;
  }

  if (hasTwoByteChars()) {
    const char16_t* chars = twoByteChars();
    for (uint32_t i = 0; i < length_; i++) {
      if (!seq.hasMore() || chars[i] != seq.next()) {
        return false;
      }
    }
  } else {
    const Latin1Char* chars = latin1Chars();
    for (uint32_t i = 0; i < length_; i++) {
      if (!seq.hasMore() || char16_t(chars[i]) != seq.next()) {
        return false;
      }
    }
  }
  return !seq.hasMore();
}

JSAtom* GetWellKnownAtom(JSContext* cx, WellKnownAtomId atomId);

/* namespace frontend */
/* namespace js */

#endif  // frontend_ParserAtom_h

Messung V0.5
C=89 H=93 G=90

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge