LCOV - code coverage report
Current view: top level - devtools/shared/heapsnapshot - DeserializedNode.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 67 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 33 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #ifndef mozilla_devtools_DeserializedNode__
       7             : #define mozilla_devtools_DeserializedNode__
       8             : 
       9             : #include "js/UbiNode.h"
      10             : #include "js/UniquePtr.h"
      11             : #include "mozilla/devtools/CoreDump.pb.h"
      12             : #include "mozilla/Maybe.h"
      13             : #include "mozilla/Move.h"
      14             : #include "mozilla/Vector.h"
      15             : 
      16             : // `Deserialized{Node,Edge}` translate protobuf messages from our core dump
      17             : // format into structures we can rely upon for implementing `JS::ubi::Node`
      18             : // specializations on top of. All of the properties of the protobuf messages are
      19             : // optional for future compatibility, and this is the layer where we validate
      20             : // that the properties that do actually exist in any given message fulfill our
      21             : // semantic requirements.
      22             : //
      23             : // Both `DeserializedNode` and `DeserializedEdge` are always owned by a
      24             : // `HeapSnapshot` instance, and their lifetimes must not extend after that of
      25             : // their owning `HeapSnapshot`.
      26             : 
      27             : namespace mozilla {
      28             : namespace devtools {
      29             : 
      30             : class HeapSnapshot;
      31             : 
      32             : using NodeId = uint64_t;
      33             : using StackFrameId = uint64_t;
      34             : 
      35             : // A `DeserializedEdge` represents an edge in the heap graph pointing to the
      36             : // node with id equal to `DeserializedEdge::referent` that we deserialized from
      37             : // a core dump.
      38             : struct DeserializedEdge {
      39             :   NodeId         referent;
      40             :   // A borrowed reference to a string owned by this node's owning HeapSnapshot.
      41             :   const char16_t* name;
      42             : 
      43           0 :   explicit DeserializedEdge(NodeId referent, const char16_t* edgeName = nullptr)
      44           0 :     : referent(referent)
      45           0 :     , name(edgeName)
      46           0 :   { }
      47             :   DeserializedEdge(DeserializedEdge&& rhs);
      48             :   DeserializedEdge& operator=(DeserializedEdge&& rhs);
      49             : 
      50             : private:
      51             :   DeserializedEdge(const DeserializedEdge&) = delete;
      52             :   DeserializedEdge& operator=(const DeserializedEdge&) = delete;
      53             : };
      54             : 
      55             : // A `DeserializedNode` is a node in the heap graph that we deserialized from a
      56             : // core dump.
      57             : struct DeserializedNode {
      58             :   using EdgeVector = Vector<DeserializedEdge>;
      59             :   using UniqueStringPtr = UniquePtr<char16_t[]>;
      60             : 
      61             :   NodeId              id;
      62             :   JS::ubi::CoarseType coarseType;
      63             :   // A borrowed reference to a string owned by this node's owning HeapSnapshot.
      64             :   const char16_t*     typeName;
      65             :   uint64_t            size;
      66             :   EdgeVector          edges;
      67             :   Maybe<StackFrameId> allocationStack;
      68             :   // A borrowed reference to a string owned by this node's owning HeapSnapshot.
      69             :   const char*         jsObjectClassName;
      70             :   // A borrowed reference to a string owned by this node's owning HeapSnapshot.
      71             :   const char*         scriptFilename;
      72             :   // A weak pointer to this node's owning `HeapSnapshot`. Safe without
      73             :   // AddRef'ing because this node's lifetime is equal to that of its owner.
      74             :   HeapSnapshot*       owner;
      75             : 
      76           0 :   DeserializedNode(NodeId id,
      77             :                    JS::ubi::CoarseType coarseType,
      78             :                    const char16_t* typeName,
      79             :                    uint64_t size,
      80             :                    EdgeVector&& edges,
      81             :                    const Maybe<StackFrameId>& allocationStack,
      82             :                    const char* className,
      83             :                    const char* filename,
      84             :                    HeapSnapshot& owner)
      85           0 :     : id(id)
      86             :     , coarseType(coarseType)
      87             :     , typeName(typeName)
      88             :     , size(size)
      89           0 :     , edges(Move(edges))
      90             :     , allocationStack(allocationStack)
      91             :     , jsObjectClassName(className)
      92             :     , scriptFilename(filename)
      93           0 :     , owner(&owner)
      94           0 :   { }
      95           0 :   virtual ~DeserializedNode() { }
      96             : 
      97           0 :   DeserializedNode(DeserializedNode&& rhs)
      98           0 :     : id(rhs.id)
      99           0 :     , coarseType(rhs.coarseType)
     100           0 :     , typeName(rhs.typeName)
     101           0 :     , size(rhs.size)
     102           0 :     , edges(Move(rhs.edges))
     103             :     , allocationStack(rhs.allocationStack)
     104           0 :     , jsObjectClassName(rhs.jsObjectClassName)
     105           0 :     , scriptFilename(rhs.scriptFilename)
     106           0 :     , owner(rhs.owner)
     107           0 :   { }
     108             : 
     109             :   DeserializedNode& operator=(DeserializedNode&& rhs)
     110             :   {
     111             :     MOZ_ASSERT(&rhs != this);
     112             :     this->~DeserializedNode();
     113             :     new(this) DeserializedNode(Move(rhs));
     114             :     return *this;
     115             :   }
     116             : 
     117             :   // Get a borrowed reference to the given edge's referent. This method is
     118             :   // virtual to provide a hook for gmock and gtest.
     119             :   virtual JS::ubi::Node getEdgeReferent(const DeserializedEdge& edge);
     120             : 
     121             :   struct HashPolicy;
     122             : 
     123             : protected:
     124             :   // This is only for use with `MockDeserializedNode` in testing.
     125             :   DeserializedNode(NodeId id, const char16_t* typeName, uint64_t size)
     126             :     : id(id)
     127             :     , coarseType(JS::ubi::CoarseType::Other)
     128             :     , typeName(typeName)
     129             :     , size(size)
     130             :     , edges()
     131             :     , allocationStack(Nothing())
     132             :     , jsObjectClassName(nullptr)
     133             :     , scriptFilename(nullptr)
     134             :     , owner(nullptr)
     135             :   { }
     136             : 
     137             : private:
     138             :   DeserializedNode(const DeserializedNode&) = delete;
     139             :   DeserializedNode& operator=(const DeserializedNode&) = delete;
     140             : };
     141             : 
     142             : static inline js::HashNumber
     143           0 : hashIdDerivedFromPtr(uint64_t id)
     144             : {
     145             :     // NodeIds and StackFrameIds are always 64 bits, but they are derived from
     146             :     // the original referents' addresses, which could have been either 32 or 64
     147             :     // bits long. As such, NodeId and StackFrameId have little entropy in their
     148             :     // bottom three bits, and may or may not have entropy in their upper 32
     149             :     // bits. This hash should manage both cases well.
     150           0 :     id >>= 3;
     151           0 :     return js::HashNumber((id >> 32) ^ id);
     152             : }
     153             : 
     154             : struct DeserializedNode::HashPolicy
     155             : {
     156             :   using Lookup = NodeId;
     157             : 
     158           0 :   static js::HashNumber hash(const Lookup& lookup) {
     159           0 :     return hashIdDerivedFromPtr(lookup);
     160             :   }
     161             : 
     162           0 :   static bool match(const DeserializedNode& existing, const Lookup& lookup) {
     163           0 :     return existing.id == lookup;
     164             :   }
     165             : };
     166             : 
     167             : // A `DeserializedStackFrame` is a stack frame referred to by a thing in the
     168             : // heap graph that we deserialized from a core dump.
     169           0 : struct DeserializedStackFrame {
     170             :   StackFrameId        id;
     171             :   Maybe<StackFrameId> parent;
     172             :   uint32_t            line;
     173             :   uint32_t            column;
     174             :   // Borrowed references to strings owned by this DeserializedStackFrame's
     175             :   // owning HeapSnapshot.
     176             :   const char16_t*     source;
     177             :   const char16_t*     functionDisplayName;
     178             :   bool                isSystem;
     179             :   bool                isSelfHosted;
     180             :   // A weak pointer to this frame's owning `HeapSnapshot`. Safe without
     181             :   // AddRef'ing because this frame's lifetime is equal to that of its owner.
     182             :   HeapSnapshot*       owner;
     183             : 
     184           0 :   explicit DeserializedStackFrame(StackFrameId id,
     185             :                                   const Maybe<StackFrameId>& parent,
     186             :                                   uint32_t line,
     187             :                                   uint32_t column,
     188             :                                   const char16_t* source,
     189             :                                   const char16_t* functionDisplayName,
     190             :                                   bool isSystem,
     191             :                                   bool isSelfHosted,
     192             :                                   HeapSnapshot& owner)
     193           0 :     : id(id)
     194             :     , parent(parent)
     195             :     , line(line)
     196             :     , column(column)
     197             :     , source(source)
     198             :     , functionDisplayName(functionDisplayName)
     199             :     , isSystem(isSystem)
     200             :     , isSelfHosted(isSelfHosted)
     201           0 :     , owner(&owner)
     202             :   {
     203           0 :     MOZ_ASSERT(source);
     204           0 :   }
     205             : 
     206             :   JS::ubi::StackFrame getParentStackFrame() const;
     207             : 
     208             :   struct HashPolicy;
     209             : 
     210             : protected:
     211             :   // This is exposed only for MockDeserializedStackFrame in the gtests.
     212             :   explicit DeserializedStackFrame()
     213             :     : id(0)
     214             :     , parent(Nothing())
     215             :     , line(0)
     216             :     , column(0)
     217             :     , source(nullptr)
     218             :     , functionDisplayName(nullptr)
     219             :     , isSystem(false)
     220             :     , isSelfHosted(false)
     221             :     , owner(nullptr)
     222             :   { };
     223             : };
     224             : 
     225             : struct DeserializedStackFrame::HashPolicy {
     226             :   using Lookup = StackFrameId;
     227             : 
     228           0 :   static js::HashNumber hash(const Lookup& lookup) {
     229           0 :     return hashIdDerivedFromPtr(lookup);
     230             :   }
     231             : 
     232           0 :   static bool match(const DeserializedStackFrame& existing, const Lookup& lookup) {
     233           0 :     return existing.id == lookup;
     234             :   }
     235             : };
     236             : 
     237             : } // namespace devtools
     238             : } // namespace mozilla
     239             : 
     240             : namespace JS {
     241             : namespace ubi {
     242             : 
     243             : using mozilla::devtools::DeserializedNode;
     244             : using mozilla::devtools::DeserializedStackFrame;
     245             : 
     246             : template<>
     247             : class Concrete<DeserializedNode> : public Base
     248             : {
     249             : protected:
     250           0 :   explicit Concrete(DeserializedNode* ptr) : Base(ptr) { }
     251           0 :   DeserializedNode& get() const {
     252           0 :     return *static_cast<DeserializedNode*>(ptr);
     253             :   }
     254             : 
     255             : public:
     256           0 :   static void construct(void* storage, DeserializedNode* ptr) {
     257           0 :     new (storage) Concrete(ptr);
     258           0 :   }
     259             : 
     260           0 :   CoarseType coarseType() const final { return get().coarseType; }
     261           0 :   Id identifier() const override { return get().id; }
     262           0 :   bool isLive() const override { return false; }
     263             :   const char16_t* typeName() const override;
     264             :   Node::Size size(mozilla::MallocSizeOf mallocSizeof) const override;
     265           0 :   const char* jsObjectClassName() const override { return get().jsObjectClassName; }
     266           0 :   const char* scriptFilename() const final { return get().scriptFilename; }
     267             : 
     268           0 :   bool hasAllocationStack() const override { return get().allocationStack.isSome(); }
     269             :   StackFrame allocationStack() const override;
     270             : 
     271             :   // We ignore the `bool wantNames` parameter because we can't control whether
     272             :   // the core dump was serialized with edge names or not.
     273             :   js::UniquePtr<EdgeRange> edges(JSContext* cx, bool) const override;
     274             : 
     275             :   static const char16_t concreteTypeName[];
     276             : };
     277             : 
     278             : template<>
     279             : class ConcreteStackFrame<DeserializedStackFrame> : public BaseStackFrame
     280             : {
     281             : protected:
     282           0 :   explicit ConcreteStackFrame(DeserializedStackFrame* ptr)
     283           0 :     : BaseStackFrame(ptr)
     284           0 :   { }
     285             : 
     286           0 :   DeserializedStackFrame& get() const {
     287           0 :     return *static_cast<DeserializedStackFrame*>(ptr);
     288             :   }
     289             : 
     290             : public:
     291           0 :   static void construct(void* storage, DeserializedStackFrame* ptr) {
     292           0 :     new (storage) ConcreteStackFrame(ptr);
     293           0 :   }
     294             : 
     295           0 :   uint64_t identifier() const override { return get().id; }
     296           0 :   uint32_t line() const override { return get().line; }
     297           0 :   uint32_t column() const override { return get().column; }
     298           0 :   bool isSystem() const override { return get().isSystem; }
     299           0 :   bool isSelfHosted(JSContext* cx) const override { return get().isSelfHosted; }
     300           0 :   void trace(JSTracer* trc) override { }
     301           0 :   AtomOrTwoByteChars source() const override {
     302           0 :     return AtomOrTwoByteChars(get().source);
     303             :   }
     304           0 :   AtomOrTwoByteChars functionDisplayName() const override {
     305           0 :     return AtomOrTwoByteChars(get().functionDisplayName);
     306             :   }
     307             : 
     308             :   StackFrame parent() const override;
     309             :   bool constructSavedFrameStack(JSContext* cx,
     310             :                                 MutableHandleObject outSavedFrameStack)
     311             :     const override;
     312             : };
     313             : 
     314             : } // namespace ubi
     315             : } // namespace JS
     316             : 
     317             : #endif // mozilla_devtools_DeserializedNode__

Generated by: LCOV version 1.13