LCOV - code coverage report
Current view: top level - js/src/vm - SavedFrame.h (source / functions) Hit Total Coverage
Test: output.info Lines: 18 44 40.9 %
Date: 2017-07-14 16:53:18 Functions: 8 20 40.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13