Exemple #1
0
bool
HeapSnapshot::saveStackFrame(const protobuf::StackFrame& frame,
                             StackFrameId& outFrameId)
{
  // NB: de-duplicated string properties must be read in the same order here as
  // they are written in `CoreDumpWriter::getProtobufStackFrame` or else indices
  // in references to already serialized strings will be off.

  if (frame.has_ref()) {
    // We should only get a reference to the previous frame if we have already
    // seen the previous frame.
    if (!frames.has(frame.ref()))
      return false;

    outFrameId = frame.ref();
    return true;
  }

  // Incomplete message.
  if (!frame.has_data())
    return false;

  auto data = frame.data();

  if (!data.has_id())
    return false;
  StackFrameId id = data.id();

  // This should be the first and only time we see this frame.
  if (frames.has(id))
    return false;

  if (!data.has_line())
    return false;
  uint32_t line = data.line();

  if (!data.has_column())
    return false;
  uint32_t column = data.column();

  if (!data.has_issystem())
    return false;
  bool isSystem = data.issystem();

  if (!data.has_isselfhosted())
    return false;
  bool isSelfHosted = data.isselfhosted();

  Maybe<StringOrRef> sourceOrRef = GET_STRING_OR_REF(data, source);
  auto source = getOrInternString<char16_t>(internedTwoByteStrings, sourceOrRef);
  if (!source)
    return false;

  const char16_t* functionDisplayName = nullptr;
  if (data.FunctionDisplayNameOrRef_case() !=
      protobuf::StackFrame_Data::FUNCTIONDISPLAYNAMEORREF_NOT_SET)
  {
    Maybe<StringOrRef> nameOrRef = GET_STRING_OR_REF(data, functiondisplayname);
    functionDisplayName = getOrInternString<char16_t>(internedTwoByteStrings, nameOrRef);
    if (!functionDisplayName)
      return false;
  }

  Maybe<StackFrameId> parent;
  if (data.has_parent()) {
    StackFrameId parentId = 0;
    if (!saveStackFrame(data.parent(), parentId))
      return false;
    parent = Some(parentId);
  }

  if (!frames.putNew(id, DeserializedStackFrame(id, parent, line, column,
                                                source, functionDisplayName,
                                                isSystem, isSelfHosted, *this)))
  {
    return false;
  }

  outFrameId = id;
  return true;
}
Exemple #2
0
bool
HeapSnapshot::saveStackFrame(const protobuf::StackFrame& frame,
                             StackFrameId& outFrameId)
{
  if (frame.has_ref()) {
    // We should only get a reference to the previous frame if we have already
    // seen the previous frame.
    if (!frames.has(frame.ref()))
      return false;

    outFrameId = frame.ref();
    return true;
  }

  // Incomplete message.
  if (!frame.has_data())
    return false;

  auto data = frame.data();

  if (!data.has_id())
    return false;
  StackFrameId id = data.id();

  // This should be the first and only time we see this frame.
  if (frames.has(id))
    return false;

  Maybe<StackFrameId> parent;
  if (data.has_parent()) {
    StackFrameId parentId = 0;
    if (!saveStackFrame(data.parent(), parentId))
      return false;
    parent = Some(parentId);
  }

  if (!data.has_line())
    return false;
  uint32_t line = data.line();

  if (!data.has_column())
    return false;
  uint32_t column = data.column();

  auto duplicatedSource = reinterpret_cast<const char16_t*>(
    data.source().data());
  size_t sourceLength = data.source().length() / sizeof(char16_t);
  const char16_t* source = borrowUniqueString(duplicatedSource, sourceLength);
  if (!source)
    return false;

  const char16_t* functionDisplayName = nullptr;
  if (data.has_functiondisplayname() && data.functiondisplayname().length() > 0) {
    auto duplicatedName = reinterpret_cast<const char16_t*>(
      data.functiondisplayname().data());
    size_t nameLength = data.functiondisplayname().length() / sizeof(char16_t);
    functionDisplayName = borrowUniqueString(duplicatedName, nameLength);
    if (!functionDisplayName)
      return false;
  }
  MOZ_ASSERT(!!functionDisplayName == (data.has_functiondisplayname() &&
                                       data.functiondisplayname().length() > 0));

  if (!data.has_issystem())
    return false;
  bool isSystem = data.issystem();

  if (!data.has_isselfhosted())
    return false;
  bool isSelfHosted = data.isselfhosted();

  if (!frames.putNew(id, DeserializedStackFrame(id, parent, line, column,
                                                source, functionDisplayName,
                                                isSystem, isSelfHosted, *this)))
  {
    return false;
  }

  outFrameId = id;
  return true;
}
Exemple #3
0
bool
HeapSnapshot::saveNode(const protobuf::Node& node, NodeIdSet& edgeReferents)
{
  // NB: de-duplicated string properties must be read back and interned in the
  // same order here as they are written and serialized in
  // `CoreDumpWriter::writeNode` or else indices in references to already
  // serialized strings will be off.

  if (NS_WARN_IF(!node.has_id()))
    return false;
  NodeId id = node.id();

  // NodeIds are derived from pointers (at most 48 bits) and we rely on them
  // fitting into JS numbers (IEEE 754 doubles, can precisely store 53 bit
  // integers) despite storing them on disk as 64 bit integers.
  if (NS_WARN_IF(!JS::Value::isNumberRepresentable(id)))
    return false;

  // Should only deserialize each node once.
  if (NS_WARN_IF(nodes.has(id)))
    return false;

  if (NS_WARN_IF(!JS::ubi::Uint32IsValidCoarseType(node.coarsetype())))
    return false;
  auto coarseType = JS::ubi::Uint32ToCoarseType(node.coarsetype());

  Maybe<StringOrRef> typeNameOrRef = GET_STRING_OR_REF_WITH_PROP_NAMES(node, typename_, typenameref);
  auto typeName = getOrInternString<char16_t>(internedTwoByteStrings, typeNameOrRef);
  if (NS_WARN_IF(!typeName))
    return false;

  if (NS_WARN_IF(!node.has_size()))
    return false;
  uint64_t size = node.size();

  auto edgesLength = node.edges_size();
  DeserializedNode::EdgeVector edges;
  if (NS_WARN_IF(!edges.reserve(edgesLength)))
    return false;
  for (decltype(edgesLength) i = 0; i < edgesLength; i++) {
    auto& protoEdge = node.edges(i);

    if (NS_WARN_IF(!protoEdge.has_referent()))
      return false;
    NodeId referent = protoEdge.referent();

    if (NS_WARN_IF(!edgeReferents.put(referent)))
      return false;

    const char16_t* edgeName = nullptr;
    if (protoEdge.EdgeNameOrRef_case() != protobuf::Edge::EDGENAMEORREF_NOT_SET) {
      Maybe<StringOrRef> edgeNameOrRef = GET_STRING_OR_REF(protoEdge, name);
      edgeName = getOrInternString<char16_t>(internedTwoByteStrings, edgeNameOrRef);
      if (NS_WARN_IF(!edgeName))
        return false;
    }

    edges.infallibleAppend(DeserializedEdge(referent, edgeName));
  }

  Maybe<StackFrameId> allocationStack;
  if (node.has_allocationstack()) {
    StackFrameId id = 0;
    if (NS_WARN_IF(!saveStackFrame(node.allocationstack(), id)))
      return false;
    allocationStack.emplace(id);
  }
  MOZ_ASSERT(allocationStack.isSome() == node.has_allocationstack());

  const char* jsObjectClassName = nullptr;
  if (node.JSObjectClassNameOrRef_case() != protobuf::Node::JSOBJECTCLASSNAMEORREF_NOT_SET) {
    Maybe<StringOrRef> clsNameOrRef = GET_STRING_OR_REF(node, jsobjectclassname);
    jsObjectClassName = getOrInternString<char>(internedOneByteStrings, clsNameOrRef);
    if (NS_WARN_IF(!jsObjectClassName))
      return false;
  }

  const char* scriptFilename = nullptr;
  if (node.ScriptFilenameOrRef_case() != protobuf::Node::SCRIPTFILENAMEORREF_NOT_SET) {
    Maybe<StringOrRef> scriptFilenameOrRef = GET_STRING_OR_REF(node, scriptfilename);
    scriptFilename = getOrInternString<char>(internedOneByteStrings, scriptFilenameOrRef);
    if (NS_WARN_IF(!scriptFilename))
      return false;
  }

  if (NS_WARN_IF(!nodes.putNew(id, DeserializedNode(id, coarseType, typeName,
                                                    size, Move(edges),
                                                    allocationStack,
                                                    jsObjectClassName,
                                                    scriptFilename, *this))))
  {
    return false;
  };

  return true;
}
Exemple #4
0
bool
HeapSnapshot::saveNode(const protobuf::Node& node)
{
  if (!node.has_id())
    return false;
  NodeId id = node.id();

  // Should only deserialize each node once.
  if (nodes.has(id))
    return false;

  if (!JS::ubi::Uint32IsValidCoarseType(node.coarsetype()))
    return false;
  auto coarseType = JS::ubi::Uint32ToCoarseType(node.coarsetype());

  if (!node.has_typename_())
    return false;

  auto duplicatedTypeName = reinterpret_cast<const char16_t*>(
    node.typename_().data());
  auto length = node.typename_().length() / sizeof(char16_t);
  auto typeName = borrowUniqueString(duplicatedTypeName, length);
  if (!typeName)
    return false;

  if (!node.has_size())
    return false;
  uint64_t size = node.size();

  auto edgesLength = node.edges_size();
  DeserializedNode::EdgeVector edges;
  if (!edges.reserve(edgesLength))
    return false;
  for (decltype(edgesLength) i = 0; i < edgesLength; i++) {
    DeserializedEdge edge;
    if (!edge.init(node.edges(i), *this))
      return false;
    edges.infallibleAppend(Move(edge));
  }

  Maybe<StackFrameId> allocationStack;
  if (node.has_allocationstack()) {
    StackFrameId id = 0;
    if (!saveStackFrame(node.allocationstack(), id))
      return false;
    allocationStack.emplace(id);
  }
  MOZ_ASSERT(allocationStack.isSome() == node.has_allocationstack());

  UniquePtr<char[]> jsObjectClassName;
  if (node.has_jsobjectclassname()) {
    auto length = node.jsobjectclassname().length();
    jsObjectClassName.reset(static_cast<char*>(malloc(length + 1)));
    if (!jsObjectClassName)
      return false;
    strncpy(jsObjectClassName.get(), node.jsobjectclassname().data(),
            length);
    jsObjectClassName.get()[length] = '\0';
  }

  return nodes.putNew(id, DeserializedNode(id, coarseType, typeName, size,
                                           Move(edges), allocationStack,
                                           Move(jsObjectClassName),
                                           *this));
}