DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
/* -*- 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_BinASTSupport_h
#define frontend_BinASTSupport_h

#include "mozilla/HashFunctions.h"

#include "frontend/BinASTToken.h"
#include "gc/DeletePolicy.h"

#include "js/AllocPolicy.h"
#include "js/HashTable.h"
#include "js/Result.h"
#include "js/UniquePtr.h"
#include "js/Vector.h"

namespace js {

class ScriptSource;

// Support for parsing JS Binary ASTs.
struct BinaryASTSupport {
  using BinASTVariant = js::frontend::BinASTVariant;
  using BinASTField = js::frontend::BinASTField;
  using BinASTKind = js::frontend::BinASTKind;

  // A structure designed to perform fast char* + length lookup
  // without copies.
  struct CharSlice {
    const char* start_;
    uint32_t byteLen_;
    CharSlice(const CharSlice& other)
        : start_(other.start_), byteLen_(other.byteLen_) {}
    CharSlice(const char* start, const uint32_t byteLen)
        : start_(start), byteLen_(byteLen) {}
    explicit CharSlice(JSContext*) : CharSlice(nullptr, 0) {}
    const char* begin() const { return start_; }
    const char* end() const { return start_ + byteLen_; }
#ifdef DEBUG
    void dump() const {
      for (auto c : *this) {
        fprintf(stderr, "%c", c);
      }

      fprintf(stderr, " (%d)", byteLen_);
    }
#endif  // DEBUG

    typedef const CharSlice Lookup;
    static js::HashNumber hash(Lookup l) {
      return mozilla::HashString(l.start_, l.byteLen_);
    }
    static bool match(const Lookup key, Lookup lookup) {
      if (key.byteLen_ != lookup.byteLen_) {
        return false;
      }
      return strncmp(key.start_, lookup.start_, key.byteLen_) == 0;
    }
  };

  BinaryASTSupport();

  JS::Result<const BinASTVariant*> binASTVariant(JSContext*, const CharSlice);
  JS::Result<const BinASTKind*> binASTKind(JSContext*, const CharSlice);

  bool ensureBinTablesInitialized(JSContext*);

 private:
  bool ensureBinASTKindsInitialized(JSContext*);
  bool ensureBinASTVariantsInitialized(JSContext*);

 private:
  // A HashMap that can be queried without copies from a CharSlice key.
  // Initialized on first call. Keys are CharSlices into static strings.
  using BinASTKindMap = js::HashMap<const CharSlice, BinASTKind, CharSlice,
                                    js::SystemAllocPolicy>;
  BinASTKindMap binASTKindMap_;

  using BinASTFieldMap = js::HashMap<const CharSlice, BinASTField, CharSlice,
                                     js::SystemAllocPolicy>;
  BinASTFieldMap binASTFieldMap_;

  using BinASTVariantMap = js::HashMap<const CharSlice, BinASTVariant,
                                       CharSlice, js::SystemAllocPolicy>;
  BinASTVariantMap binASTVariantMap_;
};

namespace frontend {

class BinASTSourceMetadata {
  using CharSlice = BinaryASTSupport::CharSlice;

  const uint32_t numStrings_;
  const uint32_t numBinASTKinds_;

  // The data lives inline in the allocation, after this class.
  inline JSAtom** atomsBase() {
    return reinterpret_cast<JSAtom**>(reinterpret_cast<uintptr_t>(this + 1));
  }
  inline CharSlice* sliceBase() {
    return reinterpret_cast<CharSlice*>(
        reinterpret_cast<uintptr_t>(atomsBase()) +
        numStrings_ * sizeof(JSAtom*));
  }
  inline BinASTKind* binASTKindBase() {
    return reinterpret_cast<BinASTKind*>(
        reinterpret_cast<uintptr_t>(sliceBase()) +
        numStrings_ * sizeof(CharSlice));
  }

  static inline size_t totalSize(uint32_t numBinASTKinds, uint32_t numStrings) {
    return sizeof(BinASTSourceMetadata) + numStrings * sizeof(JSAtom*) +
           numStrings * sizeof(CharSlice) + numBinASTKinds * sizeof(BinASTKind);
  }

  BinASTSourceMetadata(uint32_t numBinASTKinds, uint32_t numStrings)
      : numStrings_(numStrings), numBinASTKinds_(numBinASTKinds) {}

  friend class js::ScriptSource;

 public:
  static BinASTSourceMetadata* Create(const Vector<BinASTKind>& binASTKinds,
                                      uint32_t numStrings);

  inline uint32_t numBinASTKinds() { return numBinASTKinds_; }

  inline uint32_t numStrings() { return numStrings_; }

  inline BinASTKind& getBinASTKind(uint32_t index) {
    MOZ_ASSERT(index < numBinASTKinds_);
    return binASTKindBase()[index];
  }

  inline CharSlice& getSlice(uint32_t index) {
    MOZ_ASSERT(index < numStrings_);
    return sliceBase()[index];
  }

  inline JSAtom*& getAtom(uint32_t index) {
    MOZ_ASSERT(index < numStrings_);
    return atomsBase()[index];
  }

  void trace(JSTracer* tracer);
};

}  // namespace frontend

typedef UniquePtr<frontend::BinASTSourceMetadata,
                  GCManagedDeletePolicy<frontend::BinASTSourceMetadata>>
    UniqueBinASTSourceMetadataPtr;

}  // namespace js

#endif  // frontend_BinASTSupport_h