mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1196498 - Include objects' [[class]] names in heap snapshots; r=sfink
This commit is contained in:
parent
93acb863e9
commit
aca9830bfe
@ -108,12 +108,13 @@ void protobuf_AssignDesc_CoreDump_2eproto() {
|
||||
::google::protobuf::MessageFactory::generated_factory(),
|
||||
sizeof(StackFrame_Data));
|
||||
Node_descriptor_ = file->message_type(2);
|
||||
static const int Node_offsets_[5] = {
|
||||
static const int Node_offsets_[6] = {
|
||||
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, id_),
|
||||
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, typename__),
|
||||
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, size_),
|
||||
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, edges_),
|
||||
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, allocationstack_),
|
||||
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, jsobjectclassname_),
|
||||
};
|
||||
Node_reflection_ =
|
||||
new ::google::protobuf::internal::GeneratedMessageReflection(
|
||||
@ -198,12 +199,13 @@ void protobuf_AddDesc_CoreDump_2eproto() {
|
||||
"\022\014\n\004line\030\003 \001(\r\022\016\n\006column\030\004 \001(\r\022\016\n\006source"
|
||||
"\030\005 \001(\014\022\033\n\023functionDisplayName\030\006 \001(\014\022\020\n\010i"
|
||||
"sSystem\030\007 \001(\010\022\024\n\014isSelfHosted\030\010 \001(\010B\020\n\016S"
|
||||
"tackFrameType\"\242\001\n\004Node\022\n\n\002id\030\001 \001(\004\022\020\n\010ty"
|
||||
"tackFrameType\"\275\001\n\004Node\022\n\n\002id\030\001 \001(\004\022\020\n\010ty"
|
||||
"peName\030\002 \001(\014\022\014\n\004size\030\003 \001(\004\022.\n\005edges\030\004 \003("
|
||||
"\0132\037.mozilla.devtools.protobuf.Edge\022>\n\017al"
|
||||
"locationStack\030\005 \001(\0132%.mozilla.devtools.p"
|
||||
"rotobuf.StackFrame\"&\n\004Edge\022\020\n\010referent\030\001"
|
||||
" \001(\004\022\014\n\004name\030\002 \001(\014", 578);
|
||||
"rotobuf.StackFrame\022\031\n\021jsObjectClassName\030"
|
||||
"\006 \001(\014\"&\n\004Edge\022\020\n\010referent\030\001 \001(\004\022\014\n\004name\030"
|
||||
"\002 \001(\014", 605);
|
||||
::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
|
||||
"CoreDump.proto", &protobuf_RegisterTypes);
|
||||
Metadata::default_instance_ = new Metadata();
|
||||
@ -1276,6 +1278,7 @@ const int Node::kTypeNameFieldNumber;
|
||||
const int Node::kSizeFieldNumber;
|
||||
const int Node::kEdgesFieldNumber;
|
||||
const int Node::kAllocationStackFieldNumber;
|
||||
const int Node::kJsObjectClassNameFieldNumber;
|
||||
#endif // !_MSC_VER
|
||||
|
||||
Node::Node()
|
||||
@ -1302,6 +1305,7 @@ void Node::SharedCtor() {
|
||||
typename__ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
|
||||
size_ = GOOGLE_ULONGLONG(0);
|
||||
allocationstack_ = NULL;
|
||||
jsobjectclassname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
|
||||
::memset(_has_bits_, 0, sizeof(_has_bits_));
|
||||
}
|
||||
|
||||
@ -1314,6 +1318,9 @@ void Node::SharedDtor() {
|
||||
if (typename__ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
delete typename__;
|
||||
}
|
||||
if (jsobjectclassname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
delete jsobjectclassname_;
|
||||
}
|
||||
if (this != default_instance_) {
|
||||
delete allocationstack_;
|
||||
}
|
||||
@ -1341,7 +1348,7 @@ Node* Node::New() const {
|
||||
}
|
||||
|
||||
void Node::Clear() {
|
||||
if (_has_bits_[0 / 32] & 23) {
|
||||
if (_has_bits_[0 / 32] & 55) {
|
||||
id_ = GOOGLE_ULONGLONG(0);
|
||||
if (has_typename_()) {
|
||||
if (typename__ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
@ -1352,6 +1359,11 @@ void Node::Clear() {
|
||||
if (has_allocationstack()) {
|
||||
if (allocationstack_ != NULL) allocationstack_->::mozilla::devtools::protobuf::StackFrame::Clear();
|
||||
}
|
||||
if (has_jsobjectclassname()) {
|
||||
if (jsobjectclassname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
jsobjectclassname_->clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
edges_.Clear();
|
||||
::memset(_has_bits_, 0, sizeof(_has_bits_));
|
||||
@ -1433,6 +1445,19 @@ bool Node::MergePartialFromCodedStream(
|
||||
} else {
|
||||
goto handle_unusual;
|
||||
}
|
||||
if (input->ExpectTag(50)) goto parse_jsObjectClassName;
|
||||
break;
|
||||
}
|
||||
|
||||
// optional bytes jsObjectClassName = 6;
|
||||
case 6: {
|
||||
if (tag == 50) {
|
||||
parse_jsObjectClassName:
|
||||
DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
|
||||
input, this->mutable_jsobjectclassname()));
|
||||
} else {
|
||||
goto handle_unusual;
|
||||
}
|
||||
if (input->ExpectAtEnd()) goto success;
|
||||
break;
|
||||
}
|
||||
@ -1490,6 +1515,12 @@ void Node::SerializeWithCachedSizes(
|
||||
5, this->allocationstack(), output);
|
||||
}
|
||||
|
||||
// optional bytes jsObjectClassName = 6;
|
||||
if (has_jsobjectclassname()) {
|
||||
::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
|
||||
6, this->jsobjectclassname(), output);
|
||||
}
|
||||
|
||||
if (!unknown_fields().empty()) {
|
||||
::google::protobuf::internal::WireFormat::SerializeUnknownFields(
|
||||
unknown_fields(), output);
|
||||
@ -1531,6 +1562,13 @@ void Node::SerializeWithCachedSizes(
|
||||
5, this->allocationstack(), target);
|
||||
}
|
||||
|
||||
// optional bytes jsObjectClassName = 6;
|
||||
if (has_jsobjectclassname()) {
|
||||
target =
|
||||
::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
|
||||
6, this->jsobjectclassname(), target);
|
||||
}
|
||||
|
||||
if (!unknown_fields().empty()) {
|
||||
target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
|
||||
unknown_fields(), target);
|
||||
@ -1571,6 +1609,13 @@ int Node::ByteSize() const {
|
||||
this->allocationstack());
|
||||
}
|
||||
|
||||
// optional bytes jsObjectClassName = 6;
|
||||
if (has_jsobjectclassname()) {
|
||||
total_size += 1 +
|
||||
::google::protobuf::internal::WireFormatLite::BytesSize(
|
||||
this->jsobjectclassname());
|
||||
}
|
||||
|
||||
}
|
||||
// repeated .mozilla.devtools.protobuf.Edge edges = 4;
|
||||
total_size += 1 * this->edges_size();
|
||||
@ -1619,6 +1664,9 @@ void Node::MergeFrom(const Node& from) {
|
||||
if (from.has_allocationstack()) {
|
||||
mutable_allocationstack()->::mozilla::devtools::protobuf::StackFrame::MergeFrom(from.allocationstack());
|
||||
}
|
||||
if (from.has_jsobjectclassname()) {
|
||||
set_jsobjectclassname(from.jsobjectclassname());
|
||||
}
|
||||
}
|
||||
mutable_unknown_fields()->MergeFrom(from.unknown_fields());
|
||||
}
|
||||
@ -1647,6 +1695,7 @@ void Node::Swap(Node* other) {
|
||||
std::swap(size_, other->size_);
|
||||
edges_.Swap(&other->edges_);
|
||||
std::swap(allocationstack_, other->allocationstack_);
|
||||
std::swap(jsobjectclassname_, other->jsobjectclassname_);
|
||||
std::swap(_has_bits_[0], other->_has_bits_[0]);
|
||||
_unknown_fields_.Swap(&other->_unknown_fields_);
|
||||
std::swap(_cached_size_, other->_cached_size_);
|
||||
|
@ -489,6 +489,18 @@ class Node : public ::google::protobuf::Message {
|
||||
inline ::mozilla::devtools::protobuf::StackFrame* release_allocationstack();
|
||||
inline void set_allocated_allocationstack(::mozilla::devtools::protobuf::StackFrame* allocationstack);
|
||||
|
||||
// optional bytes jsObjectClassName = 6;
|
||||
inline bool has_jsobjectclassname() const;
|
||||
inline void clear_jsobjectclassname();
|
||||
static const int kJsObjectClassNameFieldNumber = 6;
|
||||
inline const ::std::string& jsobjectclassname() const;
|
||||
inline void set_jsobjectclassname(const ::std::string& value);
|
||||
inline void set_jsobjectclassname(const char* value);
|
||||
inline void set_jsobjectclassname(const void* value, size_t size);
|
||||
inline ::std::string* mutable_jsobjectclassname();
|
||||
inline ::std::string* release_jsobjectclassname();
|
||||
inline void set_allocated_jsobjectclassname(::std::string* jsobjectclassname);
|
||||
|
||||
// @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.Node)
|
||||
private:
|
||||
inline void set_has_id();
|
||||
@ -499,6 +511,8 @@ class Node : public ::google::protobuf::Message {
|
||||
inline void clear_has_size();
|
||||
inline void set_has_allocationstack();
|
||||
inline void clear_has_allocationstack();
|
||||
inline void set_has_jsobjectclassname();
|
||||
inline void clear_has_jsobjectclassname();
|
||||
|
||||
::google::protobuf::UnknownFieldSet _unknown_fields_;
|
||||
|
||||
@ -509,6 +523,7 @@ class Node : public ::google::protobuf::Message {
|
||||
::google::protobuf::uint64 size_;
|
||||
::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge > edges_;
|
||||
::mozilla::devtools::protobuf::StackFrame* allocationstack_;
|
||||
::std::string* jsobjectclassname_;
|
||||
friend void protobuf_AddDesc_CoreDump_2eproto();
|
||||
friend void protobuf_AssignDesc_CoreDump_2eproto();
|
||||
friend void protobuf_ShutdownFile_CoreDump_2eproto();
|
||||
@ -1240,6 +1255,82 @@ inline void Node::set_allocated_allocationstack(::mozilla::devtools::protobuf::S
|
||||
// @@protoc_insertion_point(field_set_allocated:mozilla.devtools.protobuf.Node.allocationStack)
|
||||
}
|
||||
|
||||
// optional bytes jsObjectClassName = 6;
|
||||
inline bool Node::has_jsobjectclassname() const {
|
||||
return (_has_bits_[0] & 0x00000020u) != 0;
|
||||
}
|
||||
inline void Node::set_has_jsobjectclassname() {
|
||||
_has_bits_[0] |= 0x00000020u;
|
||||
}
|
||||
inline void Node::clear_has_jsobjectclassname() {
|
||||
_has_bits_[0] &= ~0x00000020u;
|
||||
}
|
||||
inline void Node::clear_jsobjectclassname() {
|
||||
if (jsobjectclassname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
jsobjectclassname_->clear();
|
||||
}
|
||||
clear_has_jsobjectclassname();
|
||||
}
|
||||
inline const ::std::string& Node::jsobjectclassname() const {
|
||||
// @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.jsObjectClassName)
|
||||
return *jsobjectclassname_;
|
||||
}
|
||||
inline void Node::set_jsobjectclassname(const ::std::string& value) {
|
||||
set_has_jsobjectclassname();
|
||||
if (jsobjectclassname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
jsobjectclassname_ = new ::std::string;
|
||||
}
|
||||
jsobjectclassname_->assign(value);
|
||||
// @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Node.jsObjectClassName)
|
||||
}
|
||||
inline void Node::set_jsobjectclassname(const char* value) {
|
||||
set_has_jsobjectclassname();
|
||||
if (jsobjectclassname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
jsobjectclassname_ = new ::std::string;
|
||||
}
|
||||
jsobjectclassname_->assign(value);
|
||||
// @@protoc_insertion_point(field_set_char:mozilla.devtools.protobuf.Node.jsObjectClassName)
|
||||
}
|
||||
inline void Node::set_jsobjectclassname(const void* value, size_t size) {
|
||||
set_has_jsobjectclassname();
|
||||
if (jsobjectclassname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
jsobjectclassname_ = new ::std::string;
|
||||
}
|
||||
jsobjectclassname_->assign(reinterpret_cast<const char*>(value), size);
|
||||
// @@protoc_insertion_point(field_set_pointer:mozilla.devtools.protobuf.Node.jsObjectClassName)
|
||||
}
|
||||
inline ::std::string* Node::mutable_jsobjectclassname() {
|
||||
set_has_jsobjectclassname();
|
||||
if (jsobjectclassname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
jsobjectclassname_ = new ::std::string;
|
||||
}
|
||||
// @@protoc_insertion_point(field_mutable:mozilla.devtools.protobuf.Node.jsObjectClassName)
|
||||
return jsobjectclassname_;
|
||||
}
|
||||
inline ::std::string* Node::release_jsobjectclassname() {
|
||||
clear_has_jsobjectclassname();
|
||||
if (jsobjectclassname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
return NULL;
|
||||
} else {
|
||||
::std::string* temp = jsobjectclassname_;
|
||||
jsobjectclassname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
inline void Node::set_allocated_jsobjectclassname(::std::string* jsobjectclassname) {
|
||||
if (jsobjectclassname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
|
||||
delete jsobjectclassname_;
|
||||
}
|
||||
if (jsobjectclassname) {
|
||||
set_has_jsobjectclassname();
|
||||
jsobjectclassname_ = jsobjectclassname;
|
||||
} else {
|
||||
clear_has_jsobjectclassname();
|
||||
jsobjectclassname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
|
||||
}
|
||||
// @@protoc_insertion_point(field_set_allocated:mozilla.devtools.protobuf.Node.jsObjectClassName)
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Edge
|
||||
|
@ -86,6 +86,8 @@ message Node {
|
||||
optional uint64 size = 3;
|
||||
repeated Edge edges = 4;
|
||||
optional StackFrame allocationStack = 5;
|
||||
// char[]
|
||||
optional bytes jsObjectClassName = 6;
|
||||
}
|
||||
|
||||
// A serialized edge from the heap graph.
|
||||
@ -93,4 +95,4 @@ message Edge {
|
||||
optional uint64 referent = 1;
|
||||
// char16_t[]
|
||||
optional bytes name = 2;
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ DeserializedNode::DeserializedNode(DeserializedNode&& rhs)
|
||||
rhs.size = 0;
|
||||
|
||||
edges = Move(rhs.edges);
|
||||
jsObjectClassName = Move(rhs.jsObjectClassName);
|
||||
|
||||
owner = rhs.owner;
|
||||
rhs.owner = nullptr;
|
||||
|
@ -64,6 +64,7 @@ struct DeserializedNode {
|
||||
uint64_t size;
|
||||
EdgeVector edges;
|
||||
Maybe<StackFrameId> allocationStack;
|
||||
UniquePtr<char[]> jsObjectClassName;
|
||||
// A weak pointer to this node's owning `HeapSnapshot`. Safe without
|
||||
// AddRef'ing because this node's lifetime is equal to that of its owner.
|
||||
HeapSnapshot* owner;
|
||||
@ -73,12 +74,14 @@ struct DeserializedNode {
|
||||
uint64_t size,
|
||||
EdgeVector&& edges,
|
||||
Maybe<StackFrameId> allocationStack,
|
||||
UniquePtr<char[]>&& className,
|
||||
HeapSnapshot& owner)
|
||||
: id(id)
|
||||
, typeName(typeName)
|
||||
, size(size)
|
||||
, edges(Move(edges))
|
||||
, allocationStack(allocationStack)
|
||||
, jsObjectClassName(Move(className))
|
||||
, owner(&owner)
|
||||
{ }
|
||||
virtual ~DeserializedNode() { }
|
||||
@ -226,6 +229,7 @@ public:
|
||||
bool isLive() const override { return false; }
|
||||
const char16_t* typeName() const override;
|
||||
size_t size(mozilla::MallocSizeOf mallocSizeof) const override;
|
||||
const char* jsObjectClassName() const override { return get().jsObjectClassName.get(); }
|
||||
|
||||
// We ignore the `bool wantNames` parameter because we can't control whether
|
||||
// the core dump was serialized with edge names or not.
|
||||
|
@ -123,6 +123,10 @@ HeapSnapshot::saveNode(const protobuf::Node& node)
|
||||
return false;
|
||||
NodeId id = node.id();
|
||||
|
||||
// Should only deserialize each node once.
|
||||
if (nodes.has(id))
|
||||
return false;
|
||||
|
||||
if (!node.has_typename_())
|
||||
return false;
|
||||
|
||||
@ -157,8 +161,21 @@ HeapSnapshot::saveNode(const protobuf::Node& node)
|
||||
allocationStack = Some(id);
|
||||
}
|
||||
|
||||
DeserializedNode dn(id, typeName, size, Move(edges), allocationStack, *this);
|
||||
return nodes.putNew(id, Move(dn));
|
||||
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, typeName, size, Move(edges),
|
||||
allocationStack,
|
||||
Move(jsObjectClassName),
|
||||
*this));
|
||||
}
|
||||
|
||||
bool
|
||||
@ -594,6 +611,11 @@ public:
|
||||
protobufNode.set_allocated_allocationstack(protoStackFrame);
|
||||
}
|
||||
|
||||
if (auto className = ubiNode.jsObjectClassName()) {
|
||||
size_t length = strlen(className);
|
||||
protobufNode.set_jsobjectclassname(className, length);
|
||||
}
|
||||
|
||||
if (includeEdges) {
|
||||
auto edges = ubiNode.edges(cx, wantNames);
|
||||
if (NS_WARN_IF(!edges))
|
||||
|
@ -38,10 +38,13 @@ size_t fakeMallocSizeOf(const void*) {
|
||||
|
||||
DEF_TEST(DeserializedNodeUbiNodes, {
|
||||
const char16_t* typeName = MOZ_UTF16("TestTypeName");
|
||||
const char* className = "MyObjectClassName";
|
||||
|
||||
NodeId id = 1L << 33;
|
||||
uint64_t size = 1L << 60;
|
||||
MockDeserializedNode mocked(id, typeName, size);
|
||||
mocked.jsObjectClassName = mozilla::UniquePtr<char[]>(strdup(className));
|
||||
ASSERT_TRUE(!!mocked.jsObjectClassName);
|
||||
|
||||
DeserializedNode& deserialized = mocked;
|
||||
JS::ubi::Node ubi(&deserialized);
|
||||
@ -52,6 +55,7 @@ DEF_TEST(DeserializedNodeUbiNodes, {
|
||||
EXPECT_EQ(typeName, ubi.typeName());
|
||||
EXPECT_EQ(id, ubi.identifier());
|
||||
EXPECT_FALSE(ubi.isLive());
|
||||
EXPECT_EQ(strcmp(ubi.jsObjectClassName(), className), 0);
|
||||
|
||||
// Test the ubi::Node's edges.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user