protobuf::StackFrame* getProtobufStackFrame(JS::ubi::StackFrame& frame) { MOZ_ASSERT(frame, "null frames should be represented as the lack of a serialized " "stack frame"); auto id = frame.identifier(); auto protobufStackFrame = MakeUnique<protobuf::StackFrame>(); if (!protobufStackFrame) return nullptr; if (framesAlreadySerialized.has(id)) { protobufStackFrame->set_ref(id); return protobufStackFrame.release(); } auto data = MakeUnique<protobuf::StackFrame_Data>(); if (!data) return nullptr; data->set_id(id); data->set_line(frame.line()); data->set_column(frame.column()); data->set_issystem(frame.isSystem()); data->set_isselfhosted(frame.isSelfHosted()); auto source = MakeUnique<std::string>(frame.sourceLength() * sizeof(char16_t), '\0'); if (!source) return nullptr; auto buf = const_cast<char16_t*>(reinterpret_cast<const char16_t*>(source->data())); frame.source(RangedPtr<char16_t>(buf, frame.sourceLength()), frame.sourceLength()); data->set_allocated_source(source.release()); auto nameLength = frame.functionDisplayNameLength(); if (nameLength > 0) { auto functionDisplayName = MakeUnique<std::string>(nameLength * sizeof(char16_t), '\0'); if (!functionDisplayName) return nullptr; auto buf = const_cast<char16_t*>(reinterpret_cast<const char16_t*>(functionDisplayName->data())); frame.functionDisplayName(RangedPtr<char16_t>(buf, nameLength), nameLength); data->set_allocated_functiondisplayname(functionDisplayName.release()); } auto parent = frame.parent(); if (parent) { auto protobufParent = getProtobufStackFrame(parent); if (!protobufParent) return nullptr; data->set_allocated_parent(protobufParent); } protobufStackFrame->set_allocated_data(data.release()); if (!framesAlreadySerialized.put(id)) return nullptr; return protobufStackFrame.release(); }
protobuf::StackFrame* getProtobufStackFrame(JS::ubi::StackFrame& frame, size_t depth = 1) { // NB: de-duplicated string properties must be written in the same order // here as they are read in `HeapSnapshot::saveStackFrame` or else indices // in references to already serialized strings will be off. MOZ_ASSERT(frame, "null frames should be represented as the lack of a serialized " "stack frame"); auto id = frame.identifier(); auto protobufStackFrame = MakeUnique<protobuf::StackFrame>(); if (!protobufStackFrame) return nullptr; if (framesAlreadySerialized.has(id)) { protobufStackFrame->set_ref(id); return protobufStackFrame.release(); } auto data = MakeUnique<protobuf::StackFrame_Data>(); if (!data) return nullptr; data->set_id(id); data->set_line(frame.line()); data->set_column(frame.column()); data->set_issystem(frame.isSystem()); data->set_isselfhosted(frame.isSelfHosted()); auto dupeSource = TwoByteString::from(frame.source()); if (!attachTwoByteString(dupeSource, [&] (std::string* source) { data->set_allocated_source(source); }, [&] (uint64_t ref) { data->set_sourceref(ref); })) { return nullptr; } auto dupeName = TwoByteString::from(frame.functionDisplayName()); if (dupeName.isNonNull()) { if (!attachTwoByteString(dupeName, [&] (std::string* name) { data->set_allocated_functiondisplayname(name); }, [&] (uint64_t ref) { data->set_functiondisplaynameref(ref); })) { return nullptr; } } auto parent = frame.parent(); if (parent && depth < HeapSnapshot::MAX_STACK_DEPTH) { auto protobufParent = getProtobufStackFrame(parent, depth + 1); if (!protobufParent) return nullptr; data->set_allocated_parent(protobufParent); } protobufStackFrame->set_allocated_data(data.release()); if (!framesAlreadySerialized.put(id)) return nullptr; return protobufStackFrame.release(); }