tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SavedFrame.h (10499B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef vm_SavedFrame_h
      8 #define vm_SavedFrame_h
      9 
     10 #include "mozilla/Attributes.h"
     11 
     12 #include "gc/Policy.h"
     13 #include "js/ColumnNumber.h"  // JS::TaggedColumnNumberOneOrigin
     14 #include "js/GCHashTable.h"
     15 #include "js/Principals.h"
     16 #include "js/UbiNode.h"
     17 #include "vm/NativeObject.h"
     18 
     19 namespace js {
     20 
     21 class SavedFrame : public NativeObject {
     22  friend class SavedStacks;
     23  friend struct ::JSStructuredCloneReader;
     24 
     25  static const ClassSpec classSpec_;
     26 
     27 public:
     28  static const JSClass class_;
     29  static const JSClass protoClass_;
     30  static const JSPropertySpec protoAccessors[];
     31  static const JSFunctionSpec protoFunctions[];
     32  static const JSFunctionSpec staticFunctions[];
     33 
     34  // Prototype methods and properties to be exposed to JS.
     35  static bool construct(JSContext* cx, unsigned argc, Value* vp);
     36  static bool sourceProperty(JSContext* cx, unsigned argc, Value* vp);
     37  static bool sourceIdProperty(JSContext* cx, unsigned argc, Value* vp);
     38  static bool lineProperty(JSContext* cx, unsigned argc, Value* vp);
     39  static bool columnProperty(JSContext* cx, unsigned argc, Value* vp);
     40  static bool functionDisplayNameProperty(JSContext* cx, unsigned argc,
     41                                          Value* vp);
     42  static bool asyncCauseProperty(JSContext* cx, unsigned argc, Value* vp);
     43  static bool asyncParentProperty(JSContext* cx, unsigned argc, Value* vp);
     44  static bool parentProperty(JSContext* cx, unsigned argc, Value* vp);
     45  static bool toStringMethod(JSContext* cx, unsigned argc, Value* vp);
     46 
     47  static void finalize(JS::GCContext* gcx, JSObject* obj);
     48 
     49  // Convenient getters for SavedFrame's reserved slots for use from C++.
     50  JSAtom* getSource();
     51  uint32_t getSourceId();
     52  // Line number (1-origin).
     53  uint32_t getLine();
     54  // Column number in UTF-16 code units.
     55  JS::TaggedColumnNumberOneOrigin getColumn();
     56  JSAtom* getFunctionDisplayName();
     57  JSAtom* getAsyncCause();
     58  SavedFrame* getParent() const;
     59  JSPrincipals* getPrincipals();
     60  bool getMutedErrors();
     61  bool isSelfHosted(JSContext* cx);
     62  bool isWasm();
     63 
     64  // When isWasm():
     65  uint32_t wasmFuncIndex();
     66  uint32_t wasmBytecodeOffset();
     67 
     68  // Iterator for use with C++11 range based for loops, eg:
     69  //
     70  //     Rooted<SavedFrame*> stack(cx, getSomeSavedFrameStack());
     71  //     for (Handle<SavedFrame*> frame : SavedFrame::RootedRange(cx, stack)) {
     72  //         ...
     73  //     }
     74  //
     75  // Each frame yielded by `SavedFrame::RootedRange` is only a valid handle to
     76  // a rooted `SavedFrame` within the loop's block for a single loop
     77  // iteration. When the next iteration begins, the value is invalidated.
     78 
     79  class RootedRange;
     80 
     81  class MOZ_STACK_CLASS RootedIterator {
     82    friend class RootedRange;
     83    RootedRange* range_;
     84    // For use by RootedRange::end() only.
     85    explicit RootedIterator() : range_(nullptr) {}
     86 
     87   public:
     88    explicit RootedIterator(RootedRange& range) : range_(&range) {}
     89    Handle<SavedFrame*> operator*() {
     90      MOZ_ASSERT(range_);
     91      return range_->frame_;
     92    }
     93    bool operator!=(const RootedIterator& rhs) const {
     94      // We should only ever compare to the null range, aka we are just
     95      // testing if this range is done.
     96      MOZ_ASSERT(rhs.range_ == nullptr);
     97      return range_->frame_ != nullptr;
     98    }
     99    inline void operator++();
    100  };
    101 
    102  class MOZ_STACK_CLASS RootedRange {
    103    friend class RootedIterator;
    104    Rooted<SavedFrame*> frame_;
    105 
    106   public:
    107    RootedRange(JSContext* cx, Handle<SavedFrame*> frame) : frame_(cx, frame) {}
    108    RootedIterator begin() { return RootedIterator(*this); }
    109    RootedIterator end() { return RootedIterator(); }
    110  };
    111 
    112  struct Lookup;
    113  struct HashPolicy;
    114 
    115  using Set =
    116      JS::GCHashSet<WeakHeapPtr<SavedFrame*>, HashPolicy, SystemAllocPolicy>;
    117 
    118 private:
    119  static SavedFrame* create(JSContext* cx);
    120  [[nodiscard]] static bool finishSavedFrameInit(JSContext* cx,
    121                                                 HandleObject ctor,
    122                                                 HandleObject proto);
    123  void initFromLookup(JSContext* cx, Handle<Lookup> lookup);
    124  void initSource(JSAtom* source);
    125  void initSourceId(uint32_t id);
    126  void initLine(uint32_t line);
    127  void initColumn(JS::TaggedColumnNumberOneOrigin column);
    128  void initFunctionDisplayName(JSAtom* maybeName);
    129  void initAsyncCause(JSAtom* maybeCause);
    130  void initParent(SavedFrame* maybeParent);
    131  void initPrincipalsAlreadyHeldAndMutedErrors(JSPrincipals* principals,
    132                                               bool mutedErrors);
    133  void initPrincipalsAndMutedErrors(JSPrincipals* principals, bool mutedErrors);
    134 
    135  enum {
    136    // The reserved slots in the SavedFrame class.
    137    JSSLOT_SOURCE,
    138    JSSLOT_SOURCEID,
    139    JSSLOT_LINE,
    140    JSSLOT_COLUMN,
    141    JSSLOT_FUNCTIONDISPLAYNAME,
    142    JSSLOT_ASYNCCAUSE,
    143    JSSLOT_PARENT,
    144    JSSLOT_PRINCIPALS,
    145 
    146    // The total number of reserved slots in the SavedFrame class.
    147    JSSLOT_COUNT
    148  };
    149 };
    150 
    151 struct SavedFrame::HashPolicy {
    152  using Lookup = SavedFrame::Lookup;
    153  using SavedFramePtrHasher = StableCellHasher<SavedFrame*>;
    154  using JSPrincipalsPtrHasher = PointerHasher<JSPrincipals*>;
    155 
    156  static bool maybeGetHash(const Lookup& l, HashNumber* hashOut);
    157  static bool ensureHash(const Lookup& l, HashNumber* hashOut);
    158  static HashNumber hash(const Lookup& lookup);
    159  static bool match(SavedFrame* existing, const Lookup& lookup);
    160 
    161  using Key = WeakHeapPtr<SavedFrame*>;
    162  static void rekey(Key& key, const Key& newKey);
    163 
    164 private:
    165  static HashNumber calculateHash(const Lookup& lookup, HashNumber parentHash);
    166 };
    167 
    168 }  // namespace js
    169 
    170 namespace mozilla {
    171 
    172 template <>
    173 struct FallibleHashMethods<js::SavedFrame::HashPolicy> {
    174  template <typename Lookup>
    175  static bool maybeGetHash(Lookup&& l, HashNumber* hashOut) {
    176    return js::SavedFrame::HashPolicy::maybeGetHash(std::forward<Lookup>(l),
    177                                                    hashOut);
    178  }
    179  template <typename Lookup>
    180  static bool ensureHash(Lookup&& l, HashNumber* hashOut) {
    181    return js::SavedFrame::HashPolicy::ensureHash(std::forward<Lookup>(l),
    182                                                  hashOut);
    183  }
    184 };
    185 
    186 }  // namespace mozilla
    187 
    188 namespace js {
    189 
    190 // Assert that if the given object is not null, that it must be either a
    191 // SavedFrame object or wrapper (Xray or CCW) around a SavedFrame object.
    192 inline void AssertObjectIsSavedFrameOrWrapper(JSContext* cx,
    193                                              HandleObject stack);
    194 
    195 // When we reconstruct a SavedFrame stack from a JS::ubi::StackFrame, we may not
    196 // have access to the principals that the original stack was captured
    197 // with. Instead, we use these two singleton principals based on whether
    198 // JS::ubi::StackFrame::isSystem or not. These singletons should never be passed
    199 // to the subsumes callback, and should be special cased with a shortcut before
    200 // that.
    201 struct ReconstructedSavedFramePrincipals : public JSPrincipals {
    202 private:
    203  explicit constexpr ReconstructedSavedFramePrincipals()
    204      : JSPrincipals(JSPrincipals::RefCount(1)) {}
    205 
    206 public:
    207  ReconstructedSavedFramePrincipals(const ReconstructedSavedFramePrincipals&) =
    208      delete;
    209  ReconstructedSavedFramePrincipals& operator=(
    210      const ReconstructedSavedFramePrincipals&) = delete;
    211  ReconstructedSavedFramePrincipals(ReconstructedSavedFramePrincipals&&) =
    212      delete;
    213  ReconstructedSavedFramePrincipals& operator=(
    214      ReconstructedSavedFramePrincipals&&) = delete;
    215 
    216  [[nodiscard]] bool write(JSContext* cx,
    217                           JSStructuredCloneWriter* writer) override {
    218    MOZ_ASSERT(false,
    219               "ReconstructedSavedFramePrincipals should never be exposed to "
    220               "embedders");
    221    return false;
    222  }
    223 
    224  bool isSystemOrAddonPrincipal() override {
    225    MOZ_ASSERT(false,
    226               "ReconstructedSavedFramePrincipals should never be exposed to "
    227               "embedders");
    228    return false;
    229  }
    230 
    231  static ReconstructedSavedFramePrincipals IsSystem;
    232  static ReconstructedSavedFramePrincipals IsNotSystem;
    233 
    234  // Return true if the given JSPrincipals* points to one of the
    235  // ReconstructedSavedFramePrincipals singletons, false otherwise.
    236  static constexpr bool is(JSPrincipals* p) {
    237    return p == &IsSystem || p == &IsNotSystem;
    238  }
    239 
    240  // Get the appropriate ReconstructedSavedFramePrincipals singleton for the
    241  // given JS::ubi::StackFrame that is being reconstructed as a SavedFrame
    242  // stack.
    243  static JSPrincipals* getSingleton(JS::ubi::StackFrame& f) {
    244    return f.isSystem() ? &IsSystem : &IsNotSystem;
    245  }
    246 };
    247 
    248 inline void SavedFrame::RootedIterator::operator++() {
    249  MOZ_ASSERT(range_);
    250  range_->frame_ = range_->frame_->getParent();
    251 }
    252 
    253 }  // namespace js
    254 
    255 namespace JS {
    256 namespace ubi {
    257 
    258 using js::SavedFrame;
    259 
    260 // A concrete JS::ubi::StackFrame that is backed by a live SavedFrame object.
    261 template <>
    262 class ConcreteStackFrame<SavedFrame> : public BaseStackFrame {
    263  explicit ConcreteStackFrame(SavedFrame* ptr) : BaseStackFrame(ptr) {}
    264  SavedFrame& get() const { return *static_cast<SavedFrame*>(ptr); }
    265 
    266 public:
    267  static void construct(void* storage, SavedFrame* ptr) {
    268    new (storage) ConcreteStackFrame(ptr);
    269  }
    270 
    271  StackFrame parent() const override { return get().getParent(); }
    272  uint32_t line() const override { return get().getLine(); }
    273  JS::TaggedColumnNumberOneOrigin column() const override {
    274    return get().getColumn();
    275  }
    276 
    277  AtomOrTwoByteChars source() const override {
    278    auto source = get().getSource();
    279    return AtomOrTwoByteChars(source);
    280  }
    281 
    282  uint32_t sourceId() const override { return get().getSourceId(); }
    283 
    284  AtomOrTwoByteChars functionDisplayName() const override {
    285    auto name = get().getFunctionDisplayName();
    286    return AtomOrTwoByteChars(name);
    287  }
    288 
    289  void trace(JSTracer* trc) override {
    290    JSObject* prev = &get();
    291    JSObject* next = prev;
    292    js::TraceRoot(trc, &next, "ConcreteStackFrame<SavedFrame>::ptr");
    293    if (next != prev) {
    294      ptr = next;
    295    }
    296  }
    297 
    298  bool isSelfHosted(JSContext* cx) const override {
    299    return get().isSelfHosted(cx);
    300  }
    301 
    302  bool isSystem() const override;
    303 
    304  [[nodiscard]] bool constructSavedFrameStack(
    305      JSContext* cx, MutableHandleObject outSavedFrameStack) const override;
    306 };
    307 
    308 }  // namespace ubi
    309 }  // namespace JS
    310 
    311 #endif  // vm_SavedFrame_h