From 2207125d2098b00a575227a4a74f701dbd8f22d0 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 30 Sep 2015 16:03:31 -0700 Subject: [PATCH] Bug 1196461 - De-duplicate strings in heap snapshot core dumps; r=shu,jimb This changeset replaces all of the // char16_t[] optional bytes someProperty = 1; one- and two-byte string properties in the CoreDump.proto protobuf definition file with: oneof { // char16_t[] bytes someProperty = 1; uint64 somePropertyRef = 2; } The first time the N^th unique string is serialized, then someProperty is used and the full string is serialized in the protobuf message. All following times that string is serialized, somePropertyRef is used and its value is N. Among the other things, this also changes JS::ubi::Edge::name from a raw pointer with commented rules about who does or doesn't own and should and shouldn't free the raw pointer to a UniquePtr that enforces those rules rather than relying on developers reading and obeying the rules in the comments. --- devtools/shared/heapsnapshot/.gitattributes | 1 + devtools/shared/heapsnapshot/AutoMemMap.h | 5 + devtools/shared/heapsnapshot/CoreDump.pb.cc | 767 ++++++++++++----- devtools/shared/heapsnapshot/CoreDump.pb.h | 799 ++++++++++++------ devtools/shared/heapsnapshot/CoreDump.proto | 89 +- .../shared/heapsnapshot/DeserializedNode.cpp | 25 - .../shared/heapsnapshot/DeserializedNode.h | 19 +- devtools/shared/heapsnapshot/HeapSnapshot.cpp | 593 ++++++++++--- devtools/shared/heapsnapshot/HeapSnapshot.h | 46 +- .../tests/gtest/DeserializedNodeUbiNodes.cpp | 16 +- .../heapsnapshot/tests/gtest/DevTools.h | 10 +- .../tests/gtest/SerializesEdgeNames.cpp | 6 +- .../tests/gtest/UniqueStringHashPolicy.cpp | 25 - .../shared/heapsnapshot/tests/gtest/moz.build | 1 - js/public/UbiNode.h | 52 +- js/public/Utility.h | 10 +- js/src/builtin/TestingFunctions.cpp | 2 +- js/src/vm/UbiNode.cpp | 64 +- xpcom/glue/nsCRTGlue.cpp | 12 +- xpcom/glue/nsCRTGlue.h | 10 +- 20 files changed, 1788 insertions(+), 764 deletions(-) create mode 100644 devtools/shared/heapsnapshot/.gitattributes delete mode 100644 devtools/shared/heapsnapshot/tests/gtest/UniqueStringHashPolicy.cpp diff --git a/devtools/shared/heapsnapshot/.gitattributes b/devtools/shared/heapsnapshot/.gitattributes new file mode 100644 index 00000000000..44e248a8dd5 --- /dev/null +++ b/devtools/shared/heapsnapshot/.gitattributes @@ -0,0 +1 @@ +CoreDump.pb.* binary diff --git a/devtools/shared/heapsnapshot/AutoMemMap.h b/devtools/shared/heapsnapshot/AutoMemMap.h index a086a4590b0..2b378704eb0 100644 --- a/devtools/shared/heapsnapshot/AutoMemMap.h +++ b/devtools/shared/heapsnapshot/AutoMemMap.h @@ -4,6 +4,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef mozilla_devtools_AutoMemMap_h +#define mozilla_devtools_AutoMemMap_h + #include #include "mozilla/GuardObjects.h" @@ -68,3 +71,5 @@ public: } // namespace devtools } // namespace mozilla + +#endif // mozilla_devtools_AutoMemMap_h diff --git a/devtools/shared/heapsnapshot/CoreDump.pb.cc b/devtools/shared/heapsnapshot/CoreDump.pb.cc index 168feed16c7..5cc020f9965 100644 --- a/devtools/shared/heapsnapshot/CoreDump.pb.cc +++ b/devtools/shared/heapsnapshot/CoreDump.pb.cc @@ -35,12 +35,28 @@ struct StackFrameOneofInstance { const ::google::protobuf::Descriptor* StackFrame_Data_descriptor_ = NULL; const ::google::protobuf::internal::GeneratedMessageReflection* StackFrame_Data_reflection_ = NULL; +struct StackFrame_DataOneofInstance { + const ::std::string* source_; + ::google::protobuf::uint64 sourceref_; + const ::std::string* functiondisplayname_; + ::google::protobuf::uint64 functiondisplaynameref_; +}* StackFrame_Data_default_oneof_instance_ = NULL; const ::google::protobuf::Descriptor* Node_descriptor_ = NULL; const ::google::protobuf::internal::GeneratedMessageReflection* Node_reflection_ = NULL; +struct NodeOneofInstance { + const ::std::string* typename__; + ::google::protobuf::uint64 typenameref_; + const ::std::string* jsobjectclassname_; + ::google::protobuf::uint64 jsobjectclassnameref_; +}* Node_default_oneof_instance_ = NULL; const ::google::protobuf::Descriptor* Edge_descriptor_ = NULL; const ::google::protobuf::internal::GeneratedMessageReflection* Edge_reflection_ = NULL; +struct EdgeOneofInstance { + const ::std::string* name_; + ::google::protobuf::uint64 nameref_; +}* Edge_default_oneof_instance_ = NULL; } // namespace @@ -86,15 +102,19 @@ void protobuf_AssignDesc_CoreDump_2eproto() { ::google::protobuf::MessageFactory::generated_factory(), sizeof(StackFrame)); StackFrame_Data_descriptor_ = StackFrame_descriptor_->nested_type(0); - static const int StackFrame_Data_offsets_[8] = { + static const int StackFrame_Data_offsets_[12] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, id_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, parent_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, line_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, column_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, source_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, functiondisplayname_), + PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_Data_default_oneof_instance_, source_), + PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_Data_default_oneof_instance_, sourceref_), + PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_Data_default_oneof_instance_, functiondisplayname_), + PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(StackFrame_Data_default_oneof_instance_, functiondisplaynameref_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, issystem_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, isselfhosted_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, SourceOrRef_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, FunctionDisplayNameOrRef_), }; StackFrame_Data_reflection_ = new ::google::protobuf::internal::GeneratedMessageReflection( @@ -104,18 +124,24 @@ void protobuf_AssignDesc_CoreDump_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, _has_bits_[0]), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, _unknown_fields_), -1, + StackFrame_Data_default_oneof_instance_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(StackFrame_Data, _oneof_case_[0]), ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), sizeof(StackFrame_Data)); Node_descriptor_ = file->message_type(2); - static const int Node_offsets_[7] = { + static const int Node_offsets_[11] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, id_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, typename__), + PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, typename__), + PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, typenameref_), 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_), + PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, jsobjectclassname_), + PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Node_default_oneof_instance_, jsobjectclassnameref_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, coarsetype_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, TypeNameOrRef_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, JSObjectClassNameOrRef_), }; Node_reflection_ = new ::google::protobuf::internal::GeneratedMessageReflection( @@ -125,13 +151,17 @@ void protobuf_AssignDesc_CoreDump_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, _has_bits_[0]), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, _unknown_fields_), -1, + Node_default_oneof_instance_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Node, _oneof_case_[0]), ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), sizeof(Node)); Edge_descriptor_ = file->message_type(3); - static const int Edge_offsets_[2] = { + static const int Edge_offsets_[4] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, referent_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, name_), + PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Edge_default_oneof_instance_, name_), + PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(Edge_default_oneof_instance_, nameref_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, EdgeNameOrRef_), }; Edge_reflection_ = new ::google::protobuf::internal::GeneratedMessageReflection( @@ -141,6 +171,8 @@ void protobuf_AssignDesc_CoreDump_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, _has_bits_[0]), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, _unknown_fields_), -1, + Edge_default_oneof_instance_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Edge, _oneof_case_[0]), ::google::protobuf::DescriptorPool::generated_pool(), ::google::protobuf::MessageFactory::generated_factory(), sizeof(Edge)); @@ -177,10 +209,13 @@ void protobuf_ShutdownFile_CoreDump_2eproto() { delete StackFrame_default_oneof_instance_; delete StackFrame_reflection_; delete StackFrame_Data::default_instance_; + delete StackFrame_Data_default_oneof_instance_; delete StackFrame_Data_reflection_; delete Node::default_instance_; + delete Node_default_oneof_instance_; delete Node_reflection_; delete Edge::default_instance_; + delete Edge_default_oneof_instance_; delete Edge_reflection_; } @@ -192,29 +227,38 @@ void protobuf_AddDesc_CoreDump_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\016CoreDump.proto\022\031mozilla.devtools.proto" - "buf\"\035\n\010Metadata\022\021\n\ttimeStamp\030\001 \001(\004\"\250\002\n\nS" + "buf\"\035\n\010Metadata\022\021\n\ttimeStamp\030\001 \001(\004\"\216\003\n\nS" "tackFrame\022:\n\004data\030\001 \001(\0132*.mozilla.devtoo" "ls.protobuf.StackFrame.DataH\000\022\r\n\003ref\030\002 \001" - "(\004H\000\032\274\001\n\004Data\022\n\n\002id\030\001 \001(\004\0225\n\006parent\030\002 \001(" + "(\004H\000\032\242\002\n\004Data\022\n\n\002id\030\001 \001(\004\0225\n\006parent\030\002 \001(" "\0132%.mozilla.devtools.protobuf.StackFrame" - "\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\"\324\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\022\031\n\021jsObjectClassName\030" - "\006 \001(\014\022\025\n\ncoarseType\030\007 \001(\r:\0010\"&\n\004Edge\022\020\n\010" - "referent\030\001 \001(\004\022\014\n\004name\030\002 \001(\014", 628); + "\022\014\n\004line\030\003 \001(\r\022\016\n\006column\030\004 \001(\r\022\020\n\006source" + "\030\005 \001(\014H\000\022\023\n\tsourceRef\030\006 \001(\004H\000\022\035\n\023functio" + "nDisplayName\030\007 \001(\014H\001\022 \n\026functionDisplayN" + "ameRef\030\010 \001(\004H\001\022\020\n\010isSystem\030\t \001(\010\022\024\n\014isSe" + "lfHosted\030\n \001(\010B\r\n\013SourceOrRefB\032\n\030Functio" + "nDisplayNameOrRefB\020\n\016StackFrameType\"\272\002\n\004" + "Node\022\n\n\002id\030\001 \001(\004\022\022\n\010typeName\030\002 \001(\014H\000\022\025\n\013" + "typeNameRef\030\003 \001(\004H\000\022\014\n\004size\030\004 \001(\004\022.\n\005edg" + "es\030\005 \003(\0132\037.mozilla.devtools.protobuf.Edg" + "e\022>\n\017allocationStack\030\006 \001(\0132%.mozilla.dev" + "tools.protobuf.StackFrame\022\033\n\021jsObjectCla" + "ssName\030\007 \001(\014H\001\022\036\n\024jsObjectClassNameRef\030\010" + " \001(\004H\001\022\025\n\ncoarseType\030\t \001(\r:\0010B\017\n\rTypeNam" + "eOrRefB\030\n\026JSObjectClassNameOrRef\"L\n\004Edge" + "\022\020\n\010referent\030\001 \001(\004\022\016\n\004name\030\002 \001(\014H\000\022\021\n\007na" + "meRef\030\003 \001(\004H\000B\017\n\rEdgeNameOrRef", 870); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "CoreDump.proto", &protobuf_RegisterTypes); Metadata::default_instance_ = new Metadata(); StackFrame::default_instance_ = new StackFrame(); StackFrame_default_oneof_instance_ = new StackFrameOneofInstance; StackFrame_Data::default_instance_ = new StackFrame_Data(); + StackFrame_Data_default_oneof_instance_ = new StackFrame_DataOneofInstance; Node::default_instance_ = new Node(); + Node_default_oneof_instance_ = new NodeOneofInstance; Edge::default_instance_ = new Edge(); + Edge_default_oneof_instance_ = new EdgeOneofInstance; Metadata::default_instance_->InitAsDefaultInstance(); StackFrame::default_instance_->InitAsDefaultInstance(); StackFrame_Data::default_instance_->InitAsDefaultInstance(); @@ -460,7 +504,9 @@ const int StackFrame_Data::kParentFieldNumber; const int StackFrame_Data::kLineFieldNumber; const int StackFrame_Data::kColumnFieldNumber; const int StackFrame_Data::kSourceFieldNumber; +const int StackFrame_Data::kSourceRefFieldNumber; const int StackFrame_Data::kFunctionDisplayNameFieldNumber; +const int StackFrame_Data::kFunctionDisplayNameRefFieldNumber; const int StackFrame_Data::kIsSystemFieldNumber; const int StackFrame_Data::kIsSelfHostedFieldNumber; #endif // !_MSC_VER @@ -473,6 +519,10 @@ StackFrame_Data::StackFrame_Data() void StackFrame_Data::InitAsDefaultInstance() { parent_ = const_cast< ::mozilla::devtools::protobuf::StackFrame*>(&::mozilla::devtools::protobuf::StackFrame::default_instance()); + StackFrame_Data_default_oneof_instance_->source_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited(); + StackFrame_Data_default_oneof_instance_->sourceref_ = GOOGLE_ULONGLONG(0); + StackFrame_Data_default_oneof_instance_->functiondisplayname_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited(); + StackFrame_Data_default_oneof_instance_->functiondisplaynameref_ = GOOGLE_ULONGLONG(0); } StackFrame_Data::StackFrame_Data(const StackFrame_Data& from) @@ -489,11 +539,11 @@ void StackFrame_Data::SharedCtor() { parent_ = NULL; line_ = 0u; column_ = 0u; - source_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - functiondisplayname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); issystem_ = false; isselfhosted_ = false; ::memset(_has_bits_, 0, sizeof(_has_bits_)); + clear_has_SourceOrRef(); + clear_has_FunctionDisplayNameOrRef(); } StackFrame_Data::~StackFrame_Data() { @@ -502,11 +552,11 @@ StackFrame_Data::~StackFrame_Data() { } void StackFrame_Data::SharedDtor() { - if (source_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete source_; + if (has_SourceOrRef()) { + clear_SourceOrRef(); } - if (functiondisplayname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete functiondisplayname_; + if (has_FunctionDisplayNameOrRef()) { + clear_FunctionDisplayNameOrRef(); } if (this != default_instance_) { delete parent_; @@ -534,6 +584,41 @@ StackFrame_Data* StackFrame_Data::New() const { return new StackFrame_Data; } +void StackFrame_Data::clear_SourceOrRef() { + switch(SourceOrRef_case()) { + case kSource: { + delete SourceOrRef_.source_; + break; + } + case kSourceRef: { + // No need to clear + break; + } + case SOURCEORREF_NOT_SET: { + break; + } + } + _oneof_case_[0] = SOURCEORREF_NOT_SET; +} + +void StackFrame_Data::clear_FunctionDisplayNameOrRef() { + switch(FunctionDisplayNameOrRef_case()) { + case kFunctionDisplayName: { + delete FunctionDisplayNameOrRef_.functiondisplayname_; + break; + } + case kFunctionDisplayNameRef: { + // No need to clear + break; + } + case FUNCTIONDISPLAYNAMEORREF_NOT_SET: { + break; + } + } + _oneof_case_[1] = FUNCTIONDISPLAYNAMEORREF_NOT_SET; +} + + void StackFrame_Data::Clear() { #define OFFSET_OF_FIELD_(f) (reinterpret_cast( \ &reinterpret_cast(16)->f) - \ @@ -545,28 +630,20 @@ void StackFrame_Data::Clear() { ::memset(&first, 0, n); \ } while (0) - if (_has_bits_[0 / 32] & 255) { + if (_has_bits_[0 / 32] & 15) { ZR_(line_, column_); - ZR_(issystem_, isselfhosted_); id_ = GOOGLE_ULONGLONG(0); if (has_parent()) { if (parent_ != NULL) parent_->::mozilla::devtools::protobuf::StackFrame::Clear(); } - if (has_source()) { - if (source_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - source_->clear(); - } - } - if (has_functiondisplayname()) { - if (functiondisplayname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - functiondisplayname_->clear(); - } - } } + ZR_(issystem_, isselfhosted_); #undef OFFSET_OF_FIELD_ #undef ZR_ + clear_SourceOrRef(); + clear_FunctionDisplayNameOrRef(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); mutable_unknown_fields()->Clear(); } @@ -647,26 +724,58 @@ bool StackFrame_Data::MergePartialFromCodedStream( } else { goto handle_unusual; } - if (input->ExpectTag(50)) goto parse_functionDisplayName; + if (input->ExpectTag(48)) goto parse_sourceRef; break; } - // optional bytes functionDisplayName = 6; + // optional uint64 sourceRef = 6; case 6: { - if (tag == 50) { + if (tag == 48) { + parse_sourceRef: + clear_SourceOrRef(); + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( + input, &SourceOrRef_.sourceref_))); + set_has_sourceref(); + } else { + goto handle_unusual; + } + if (input->ExpectTag(58)) goto parse_functionDisplayName; + break; + } + + // optional bytes functionDisplayName = 7; + case 7: { + if (tag == 58) { parse_functionDisplayName: DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( input, this->mutable_functiondisplayname())); } else { goto handle_unusual; } - if (input->ExpectTag(56)) goto parse_isSystem; + if (input->ExpectTag(64)) goto parse_functionDisplayNameRef; break; } - // optional bool isSystem = 7; - case 7: { - if (tag == 56) { + // optional uint64 functionDisplayNameRef = 8; + case 8: { + if (tag == 64) { + parse_functionDisplayNameRef: + clear_FunctionDisplayNameOrRef(); + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( + input, &FunctionDisplayNameOrRef_.functiondisplaynameref_))); + set_has_functiondisplaynameref(); + } else { + goto handle_unusual; + } + if (input->ExpectTag(72)) goto parse_isSystem; + break; + } + + // optional bool isSystem = 9; + case 9: { + if (tag == 72) { parse_isSystem: DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( @@ -675,13 +784,13 @@ bool StackFrame_Data::MergePartialFromCodedStream( } else { goto handle_unusual; } - if (input->ExpectTag(64)) goto parse_isSelfHosted; + if (input->ExpectTag(80)) goto parse_isSelfHosted; break; } - // optional bool isSelfHosted = 8; - case 8: { - if (tag == 64) { + // optional bool isSelfHosted = 10; + case 10: { + if (tag == 80) { parse_isSelfHosted: DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( @@ -746,20 +855,30 @@ void StackFrame_Data::SerializeWithCachedSizes( 5, this->source(), output); } - // optional bytes functionDisplayName = 6; + // optional uint64 sourceRef = 6; + if (has_sourceref()) { + ::google::protobuf::internal::WireFormatLite::WriteUInt64(6, this->sourceref(), output); + } + + // optional bytes functionDisplayName = 7; if (has_functiondisplayname()) { ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 6, this->functiondisplayname(), output); + 7, this->functiondisplayname(), output); } - // optional bool isSystem = 7; + // optional uint64 functionDisplayNameRef = 8; + if (has_functiondisplaynameref()) { + ::google::protobuf::internal::WireFormatLite::WriteUInt64(8, this->functiondisplaynameref(), output); + } + + // optional bool isSystem = 9; if (has_issystem()) { - ::google::protobuf::internal::WireFormatLite::WriteBool(7, this->issystem(), output); + ::google::protobuf::internal::WireFormatLite::WriteBool(9, this->issystem(), output); } - // optional bool isSelfHosted = 8; + // optional bool isSelfHosted = 10; if (has_isselfhosted()) { - ::google::protobuf::internal::WireFormatLite::WriteBool(8, this->isselfhosted(), output); + ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->isselfhosted(), output); } if (!unknown_fields().empty()) { @@ -801,21 +920,31 @@ void StackFrame_Data::SerializeWithCachedSizes( 5, this->source(), target); } - // optional bytes functionDisplayName = 6; + // optional uint64 sourceRef = 6; + if (has_sourceref()) { + target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(6, this->sourceref(), target); + } + + // optional bytes functionDisplayName = 7; if (has_functiondisplayname()) { target = ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 6, this->functiondisplayname(), target); + 7, this->functiondisplayname(), target); } - // optional bool isSystem = 7; + // optional uint64 functionDisplayNameRef = 8; + if (has_functiondisplaynameref()) { + target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(8, this->functiondisplaynameref(), target); + } + + // optional bool isSystem = 9; if (has_issystem()) { - target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(7, this->issystem(), target); + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(9, this->issystem(), target); } - // optional bool isSelfHosted = 8; + // optional bool isSelfHosted = 10; if (has_isselfhosted()) { - target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(8, this->isselfhosted(), target); + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->isselfhosted(), target); } if (!unknown_fields().empty()) { @@ -858,31 +987,57 @@ int StackFrame_Data::ByteSize() const { this->column()); } - // optional bytes source = 5; - if (has_source()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->source()); - } - - // optional bytes functionDisplayName = 6; - if (has_functiondisplayname()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->functiondisplayname()); - } - - // optional bool isSystem = 7; + } + if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) { + // optional bool isSystem = 9; if (has_issystem()) { total_size += 1 + 1; } - // optional bool isSelfHosted = 8; + // optional bool isSelfHosted = 10; if (has_isselfhosted()) { total_size += 1 + 1; } } + switch (SourceOrRef_case()) { + // optional bytes source = 5; + case kSource: { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::BytesSize( + this->source()); + break; + } + // optional uint64 sourceRef = 6; + case kSourceRef: { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::UInt64Size( + this->sourceref()); + break; + } + case SOURCEORREF_NOT_SET: { + break; + } + } + switch (FunctionDisplayNameOrRef_case()) { + // optional bytes functionDisplayName = 7; + case kFunctionDisplayName: { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::BytesSize( + this->functiondisplayname()); + break; + } + // optional uint64 functionDisplayNameRef = 8; + case kFunctionDisplayNameRef: { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::UInt64Size( + this->functiondisplaynameref()); + break; + } + case FUNCTIONDISPLAYNAMEORREF_NOT_SET: { + break; + } + } if (!unknown_fields().empty()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( @@ -908,6 +1063,32 @@ void StackFrame_Data::MergeFrom(const ::google::protobuf::Message& from) { void StackFrame_Data::MergeFrom(const StackFrame_Data& from) { GOOGLE_CHECK_NE(&from, this); + switch (from.SourceOrRef_case()) { + case kSource: { + set_source(from.source()); + break; + } + case kSourceRef: { + set_sourceref(from.sourceref()); + break; + } + case SOURCEORREF_NOT_SET: { + break; + } + } + switch (from.FunctionDisplayNameOrRef_case()) { + case kFunctionDisplayName: { + set_functiondisplayname(from.functiondisplayname()); + break; + } + case kFunctionDisplayNameRef: { + set_functiondisplaynameref(from.functiondisplaynameref()); + break; + } + case FUNCTIONDISPLAYNAMEORREF_NOT_SET: { + break; + } + } if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_id()) { set_id(from.id()); @@ -921,12 +1102,8 @@ void StackFrame_Data::MergeFrom(const StackFrame_Data& from) { if (from.has_column()) { set_column(from.column()); } - if (from.has_source()) { - set_source(from.source()); - } - if (from.has_functiondisplayname()) { - set_functiondisplayname(from.functiondisplayname()); - } + } + if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) { if (from.has_issystem()) { set_issystem(from.issystem()); } @@ -960,10 +1137,12 @@ void StackFrame_Data::Swap(StackFrame_Data* other) { std::swap(parent_, other->parent_); std::swap(line_, other->line_); std::swap(column_, other->column_); - std::swap(source_, other->source_); - std::swap(functiondisplayname_, other->functiondisplayname_); std::swap(issystem_, other->issystem_); std::swap(isselfhosted_, other->isselfhosted_); + std::swap(SourceOrRef_, other->SourceOrRef_); + std::swap(_oneof_case_[0], other->_oneof_case_[0]); + std::swap(FunctionDisplayNameOrRef_, other->FunctionDisplayNameOrRef_); + std::swap(_oneof_case_[1], other->_oneof_case_[1]); std::swap(_has_bits_[0], other->_has_bits_[0]); _unknown_fields_.Swap(&other->_unknown_fields_); std::swap(_cached_size_, other->_cached_size_); @@ -1276,10 +1455,12 @@ void StackFrame::Swap(StackFrame* other) { #ifndef _MSC_VER const int Node::kIdFieldNumber; const int Node::kTypeNameFieldNumber; +const int Node::kTypeNameRefFieldNumber; const int Node::kSizeFieldNumber; const int Node::kEdgesFieldNumber; const int Node::kAllocationStackFieldNumber; const int Node::kJsObjectClassNameFieldNumber; +const int Node::kJsObjectClassNameRefFieldNumber; const int Node::kCoarseTypeFieldNumber; #endif // !_MSC_VER @@ -1290,7 +1471,11 @@ Node::Node() } void Node::InitAsDefaultInstance() { + Node_default_oneof_instance_->typename__ = &::google::protobuf::internal::GetEmptyStringAlreadyInited(); + Node_default_oneof_instance_->typenameref_ = GOOGLE_ULONGLONG(0); allocationstack_ = const_cast< ::mozilla::devtools::protobuf::StackFrame*>(&::mozilla::devtools::protobuf::StackFrame::default_instance()); + Node_default_oneof_instance_->jsobjectclassname_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited(); + Node_default_oneof_instance_->jsobjectclassnameref_ = GOOGLE_ULONGLONG(0); } Node::Node(const Node& from) @@ -1304,12 +1489,12 @@ void Node::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; id_ = GOOGLE_ULONGLONG(0); - typename__ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); size_ = GOOGLE_ULONGLONG(0); allocationstack_ = NULL; - jsobjectclassname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); coarsetype_ = 0u; ::memset(_has_bits_, 0, sizeof(_has_bits_)); + clear_has_TypeNameOrRef(); + clear_has_JSObjectClassNameOrRef(); } Node::~Node() { @@ -1318,11 +1503,11 @@ Node::~Node() { } void Node::SharedDtor() { - if (typename__ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete typename__; + if (has_TypeNameOrRef()) { + clear_TypeNameOrRef(); } - if (jsobjectclassname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete jsobjectclassname_; + if (has_JSObjectClassNameOrRef()) { + clear_JSObjectClassNameOrRef(); } if (this != default_instance_) { delete allocationstack_; @@ -1350,26 +1535,66 @@ Node* Node::New() const { return new Node; } -void Node::Clear() { - if (_has_bits_[0 / 32] & 119) { - id_ = GOOGLE_ULONGLONG(0); - if (has_typename_()) { - if (typename__ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - typename__->clear(); - } +void Node::clear_TypeNameOrRef() { + switch(TypeNameOrRef_case()) { + case kTypeName: { + delete TypeNameOrRef_.typename__; + break; } - size_ = GOOGLE_ULONGLONG(0); + case kTypeNameRef: { + // No need to clear + break; + } + case TYPENAMEORREF_NOT_SET: { + break; + } + } + _oneof_case_[0] = TYPENAMEORREF_NOT_SET; +} + +void Node::clear_JSObjectClassNameOrRef() { + switch(JSObjectClassNameOrRef_case()) { + case kJsObjectClassName: { + delete JSObjectClassNameOrRef_.jsobjectclassname_; + break; + } + case kJsObjectClassNameRef: { + // No need to clear + break; + } + case JSOBJECTCLASSNAMEORREF_NOT_SET: { + break; + } + } + _oneof_case_[1] = JSOBJECTCLASSNAMEORREF_NOT_SET; +} + + +void Node::Clear() { +#define OFFSET_OF_FIELD_(f) (reinterpret_cast( \ + &reinterpret_cast(16)->f) - \ + reinterpret_cast(16)) + +#define ZR_(first, last) do { \ + size_t f = OFFSET_OF_FIELD_(first); \ + size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last); \ + ::memset(&first, 0, n); \ + } while (0) + + if (_has_bits_[0 / 32] & 41) { + ZR_(id_, size_); if (has_allocationstack()) { if (allocationstack_ != NULL) allocationstack_->::mozilla::devtools::protobuf::StackFrame::Clear(); } - if (has_jsobjectclassname()) { - if (jsobjectclassname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - jsobjectclassname_->clear(); - } - } - coarsetype_ = 0u; } + coarsetype_ = 0u; + +#undef OFFSET_OF_FIELD_ +#undef ZR_ + edges_.Clear(); + clear_TypeNameOrRef(); + clear_JSObjectClassNameOrRef(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); mutable_unknown_fields()->Clear(); } @@ -1407,13 +1632,29 @@ bool Node::MergePartialFromCodedStream( } else { goto handle_unusual; } - if (input->ExpectTag(24)) goto parse_size; + if (input->ExpectTag(24)) goto parse_typeNameRef; break; } - // optional uint64 size = 3; + // optional uint64 typeNameRef = 3; case 3: { if (tag == 24) { + parse_typeNameRef: + clear_TypeNameOrRef(); + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( + input, &TypeNameOrRef_.typenameref_))); + set_has_typenameref(); + } else { + goto handle_unusual; + } + if (input->ExpectTag(32)) goto parse_size; + break; + } + + // optional uint64 size = 4; + case 4: { + if (tag == 32) { parse_size: DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( @@ -1422,53 +1663,69 @@ bool Node::MergePartialFromCodedStream( } else { goto handle_unusual; } - if (input->ExpectTag(34)) goto parse_edges; + if (input->ExpectTag(42)) goto parse_edges; break; } - // repeated .mozilla.devtools.protobuf.Edge edges = 4; - case 4: { - if (tag == 34) { + // repeated .mozilla.devtools.protobuf.Edge edges = 5; + case 5: { + if (tag == 42) { parse_edges: DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( input, add_edges())); } else { goto handle_unusual; } - if (input->ExpectTag(34)) goto parse_edges; - if (input->ExpectTag(42)) goto parse_allocationStack; + if (input->ExpectTag(42)) goto parse_edges; + if (input->ExpectTag(50)) goto parse_allocationStack; break; } - // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 5; - case 5: { - if (tag == 42) { + // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6; + case 6: { + if (tag == 50) { parse_allocationStack: DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( input, mutable_allocationstack())); } else { goto handle_unusual; } - if (input->ExpectTag(50)) goto parse_jsObjectClassName; + if (input->ExpectTag(58)) goto parse_jsObjectClassName; break; } - // optional bytes jsObjectClassName = 6; - case 6: { - if (tag == 50) { + // optional bytes jsObjectClassName = 7; + case 7: { + if (tag == 58) { parse_jsObjectClassName: DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( input, this->mutable_jsobjectclassname())); } else { goto handle_unusual; } - if (input->ExpectTag(56)) goto parse_coarseType; + if (input->ExpectTag(64)) goto parse_jsObjectClassNameRef; break; } - // optional uint32 coarseType = 7 [default = 0]; - case 7: { - if (tag == 56) { + // optional uint64 jsObjectClassNameRef = 8; + case 8: { + if (tag == 64) { + parse_jsObjectClassNameRef: + clear_JSObjectClassNameOrRef(); + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( + input, &JSObjectClassNameOrRef_.jsobjectclassnameref_))); + set_has_jsobjectclassnameref(); + } else { + goto handle_unusual; + } + if (input->ExpectTag(72)) goto parse_coarseType; + break; + } + + // optional uint32 coarseType = 9 [default = 0]; + case 9: { + if (tag == 72) { parse_coarseType: DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>( @@ -1517,32 +1774,42 @@ void Node::SerializeWithCachedSizes( 2, this->typename_(), output); } - // optional uint64 size = 3; - if (has_size()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(3, this->size(), output); + // optional uint64 typeNameRef = 3; + if (has_typenameref()) { + ::google::protobuf::internal::WireFormatLite::WriteUInt64(3, this->typenameref(), output); } - // repeated .mozilla.devtools.protobuf.Edge edges = 4; + // optional uint64 size = 4; + if (has_size()) { + ::google::protobuf::internal::WireFormatLite::WriteUInt64(4, this->size(), output); + } + + // repeated .mozilla.devtools.protobuf.Edge edges = 5; for (int i = 0; i < this->edges_size(); i++) { ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 4, this->edges(i), output); + 5, this->edges(i), output); } - // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 5; + // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6; if (has_allocationstack()) { ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 5, this->allocationstack(), output); + 6, this->allocationstack(), output); } - // optional bytes jsObjectClassName = 6; + // optional bytes jsObjectClassName = 7; if (has_jsobjectclassname()) { ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 6, this->jsobjectclassname(), output); + 7, this->jsobjectclassname(), output); } - // optional uint32 coarseType = 7 [default = 0]; + // optional uint64 jsObjectClassNameRef = 8; + if (has_jsobjectclassnameref()) { + ::google::protobuf::internal::WireFormatLite::WriteUInt64(8, this->jsobjectclassnameref(), output); + } + + // optional uint32 coarseType = 9 [default = 0]; if (has_coarsetype()) { - ::google::protobuf::internal::WireFormatLite::WriteUInt32(7, this->coarsetype(), output); + ::google::protobuf::internal::WireFormatLite::WriteUInt32(9, this->coarsetype(), output); } if (!unknown_fields().empty()) { @@ -1567,35 +1834,45 @@ void Node::SerializeWithCachedSizes( 2, this->typename_(), target); } - // optional uint64 size = 3; - if (has_size()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(3, this->size(), target); + // optional uint64 typeNameRef = 3; + if (has_typenameref()) { + target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(3, this->typenameref(), target); } - // repeated .mozilla.devtools.protobuf.Edge edges = 4; + // optional uint64 size = 4; + if (has_size()) { + target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(4, this->size(), target); + } + + // repeated .mozilla.devtools.protobuf.Edge edges = 5; for (int i = 0; i < this->edges_size(); i++) { target = ::google::protobuf::internal::WireFormatLite:: WriteMessageNoVirtualToArray( - 4, this->edges(i), target); + 5, this->edges(i), target); } - // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 5; + // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6; if (has_allocationstack()) { target = ::google::protobuf::internal::WireFormatLite:: WriteMessageNoVirtualToArray( - 5, this->allocationstack(), target); + 6, this->allocationstack(), target); } - // optional bytes jsObjectClassName = 6; + // optional bytes jsObjectClassName = 7; if (has_jsobjectclassname()) { target = ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 6, this->jsobjectclassname(), target); + 7, this->jsobjectclassname(), target); } - // optional uint32 coarseType = 7 [default = 0]; + // optional uint64 jsObjectClassNameRef = 8; + if (has_jsobjectclassnameref()) { + target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(8, this->jsobjectclassnameref(), target); + } + + // optional uint32 coarseType = 9 [default = 0]; if (has_coarsetype()) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(7, this->coarsetype(), target); + target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(9, this->coarsetype(), target); } if (!unknown_fields().empty()) { @@ -1617,35 +1894,23 @@ int Node::ByteSize() const { this->id()); } - // optional bytes typeName = 2; - if (has_typename_()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->typename_()); - } - - // optional uint64 size = 3; + // optional uint64 size = 4; if (has_size()) { total_size += 1 + ::google::protobuf::internal::WireFormatLite::UInt64Size( this->size()); } - // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 5; + // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6; if (has_allocationstack()) { total_size += 1 + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( this->allocationstack()); } - // optional bytes jsObjectClassName = 6; - if (has_jsobjectclassname()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->jsobjectclassname()); - } - - // optional uint32 coarseType = 7 [default = 0]; + } + if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) { + // optional uint32 coarseType = 9 [default = 0]; if (has_coarsetype()) { total_size += 1 + ::google::protobuf::internal::WireFormatLite::UInt32Size( @@ -1653,7 +1918,7 @@ int Node::ByteSize() const { } } - // repeated .mozilla.devtools.protobuf.Edge edges = 4; + // repeated .mozilla.devtools.protobuf.Edge edges = 5; total_size += 1 * this->edges_size(); for (int i = 0; i < this->edges_size(); i++) { total_size += @@ -1661,6 +1926,44 @@ int Node::ByteSize() const { this->edges(i)); } + switch (TypeNameOrRef_case()) { + // optional bytes typeName = 2; + case kTypeName: { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::BytesSize( + this->typename_()); + break; + } + // optional uint64 typeNameRef = 3; + case kTypeNameRef: { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::UInt64Size( + this->typenameref()); + break; + } + case TYPENAMEORREF_NOT_SET: { + break; + } + } + switch (JSObjectClassNameOrRef_case()) { + // optional bytes jsObjectClassName = 7; + case kJsObjectClassName: { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::BytesSize( + this->jsobjectclassname()); + break; + } + // optional uint64 jsObjectClassNameRef = 8; + case kJsObjectClassNameRef: { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::UInt64Size( + this->jsobjectclassnameref()); + break; + } + case JSOBJECTCLASSNAMEORREF_NOT_SET: { + break; + } + } if (!unknown_fields().empty()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( @@ -1687,22 +1990,44 @@ void Node::MergeFrom(const ::google::protobuf::Message& from) { void Node::MergeFrom(const Node& from) { GOOGLE_CHECK_NE(&from, this); edges_.MergeFrom(from.edges_); + switch (from.TypeNameOrRef_case()) { + case kTypeName: { + set_typename_(from.typename_()); + break; + } + case kTypeNameRef: { + set_typenameref(from.typenameref()); + break; + } + case TYPENAMEORREF_NOT_SET: { + break; + } + } + switch (from.JSObjectClassNameOrRef_case()) { + case kJsObjectClassName: { + set_jsobjectclassname(from.jsobjectclassname()); + break; + } + case kJsObjectClassNameRef: { + set_jsobjectclassnameref(from.jsobjectclassnameref()); + break; + } + case JSOBJECTCLASSNAMEORREF_NOT_SET: { + break; + } + } if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_id()) { set_id(from.id()); } - if (from.has_typename_()) { - set_typename_(from.typename_()); - } if (from.has_size()) { set_size(from.size()); } if (from.has_allocationstack()) { mutable_allocationstack()->::mozilla::devtools::protobuf::StackFrame::MergeFrom(from.allocationstack()); } - if (from.has_jsobjectclassname()) { - set_jsobjectclassname(from.jsobjectclassname()); - } + } + if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) { if (from.has_coarsetype()) { set_coarsetype(from.coarsetype()); } @@ -1730,12 +2055,14 @@ bool Node::IsInitialized() const { void Node::Swap(Node* other) { if (other != this) { std::swap(id_, other->id_); - std::swap(typename__, other->typename__); std::swap(size_, other->size_); edges_.Swap(&other->edges_); std::swap(allocationstack_, other->allocationstack_); - std::swap(jsobjectclassname_, other->jsobjectclassname_); std::swap(coarsetype_, other->coarsetype_); + std::swap(TypeNameOrRef_, other->TypeNameOrRef_); + std::swap(_oneof_case_[0], other->_oneof_case_[0]); + std::swap(JSObjectClassNameOrRef_, other->JSObjectClassNameOrRef_); + std::swap(_oneof_case_[1], other->_oneof_case_[1]); std::swap(_has_bits_[0], other->_has_bits_[0]); _unknown_fields_.Swap(&other->_unknown_fields_); std::swap(_cached_size_, other->_cached_size_); @@ -1756,6 +2083,7 @@ void Node::Swap(Node* other) { #ifndef _MSC_VER const int Edge::kReferentFieldNumber; const int Edge::kNameFieldNumber; +const int Edge::kNameRefFieldNumber; #endif // !_MSC_VER Edge::Edge() @@ -1765,6 +2093,8 @@ Edge::Edge() } void Edge::InitAsDefaultInstance() { + Edge_default_oneof_instance_->name_ = &::google::protobuf::internal::GetEmptyStringAlreadyInited(); + Edge_default_oneof_instance_->nameref_ = GOOGLE_ULONGLONG(0); } Edge::Edge(const Edge& from) @@ -1778,8 +2108,8 @@ void Edge::SharedCtor() { ::google::protobuf::internal::GetEmptyString(); _cached_size_ = 0; referent_ = GOOGLE_ULONGLONG(0); - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); ::memset(_has_bits_, 0, sizeof(_has_bits_)); + clear_has_EdgeNameOrRef(); } Edge::~Edge() { @@ -1788,8 +2118,8 @@ Edge::~Edge() { } void Edge::SharedDtor() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_; + if (has_EdgeNameOrRef()) { + clear_EdgeNameOrRef(); } if (this != default_instance_) { } @@ -1816,15 +2146,27 @@ Edge* Edge::New() const { return new Edge; } -void Edge::Clear() { - if (_has_bits_[0 / 32] & 3) { - referent_ = GOOGLE_ULONGLONG(0); - if (has_name()) { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); - } +void Edge::clear_EdgeNameOrRef() { + switch(EdgeNameOrRef_case()) { + case kName: { + delete EdgeNameOrRef_.name_; + break; + } + case kNameRef: { + // No need to clear + break; + } + case EDGENAMEORREF_NOT_SET: { + break; } } + _oneof_case_[0] = EDGENAMEORREF_NOT_SET; +} + + +void Edge::Clear() { + referent_ = GOOGLE_ULONGLONG(0); + clear_EdgeNameOrRef(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); mutable_unknown_fields()->Clear(); } @@ -1862,6 +2204,22 @@ bool Edge::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(24)) goto parse_nameRef; + break; + } + + // optional uint64 nameRef = 3; + case 3: { + if (tag == 24) { + parse_nameRef: + clear_EdgeNameOrRef(); + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( + input, &EdgeNameOrRef_.nameref_))); + set_has_nameref(); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -1902,6 +2260,11 @@ void Edge::SerializeWithCachedSizes( 2, this->name(), output); } + // optional uint64 nameRef = 3; + if (has_nameref()) { + ::google::protobuf::internal::WireFormatLite::WriteUInt64(3, this->nameref(), output); + } + if (!unknown_fields().empty()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); @@ -1924,6 +2287,11 @@ void Edge::SerializeWithCachedSizes( 2, this->name(), target); } + // optional uint64 nameRef = 3; + if (has_nameref()) { + target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(3, this->nameref(), target); + } + if (!unknown_fields().empty()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); @@ -1943,13 +2311,25 @@ int Edge::ByteSize() const { this->referent()); } + } + switch (EdgeNameOrRef_case()) { // optional bytes name = 2; - if (has_name()) { + case kName: { total_size += 1 + ::google::protobuf::internal::WireFormatLite::BytesSize( this->name()); + break; + } + // optional uint64 nameRef = 3; + case kNameRef: { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::UInt64Size( + this->nameref()); + break; + } + case EDGENAMEORREF_NOT_SET: { + break; } - } if (!unknown_fields().empty()) { total_size += @@ -1976,13 +2356,23 @@ void Edge::MergeFrom(const ::google::protobuf::Message& from) { void Edge::MergeFrom(const Edge& from) { GOOGLE_CHECK_NE(&from, this); + switch (from.EdgeNameOrRef_case()) { + case kName: { + set_name(from.name()); + break; + } + case kNameRef: { + set_nameref(from.nameref()); + break; + } + case EDGENAMEORREF_NOT_SET: { + break; + } + } if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_referent()) { set_referent(from.referent()); } - if (from.has_name()) { - set_name(from.name()); - } } mutable_unknown_fields()->MergeFrom(from.unknown_fields()); } @@ -2007,7 +2397,8 @@ bool Edge::IsInitialized() const { void Edge::Swap(Edge* other) { if (other != this) { std::swap(referent_, other->referent_); - std::swap(name_, other->name_); + std::swap(EdgeNameOrRef_, other->EdgeNameOrRef_); + std::swap(_oneof_case_[0], other->_oneof_case_[0]); std::swap(_has_bits_[0], other->_has_bits_[0]); _unknown_fields_.Swap(&other->_unknown_fields_); std::swap(_cached_size_, other->_cached_size_); diff --git a/devtools/shared/heapsnapshot/CoreDump.pb.h b/devtools/shared/heapsnapshot/CoreDump.pb.h index d63895100d5..79025dd3ac9 100644 --- a/devtools/shared/heapsnapshot/CoreDump.pb.h +++ b/devtools/shared/heapsnapshot/CoreDump.pb.h @@ -145,6 +145,18 @@ class StackFrame_Data : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const StackFrame_Data& default_instance(); + enum SourceOrRefCase { + kSource = 5, + kSourceRef = 6, + SOURCEORREF_NOT_SET = 0, + }; + + enum FunctionDisplayNameOrRefCase { + kFunctionDisplayName = 7, + kFunctionDisplayNameRef = 8, + FUNCTIONDISPLAYNAMEORREF_NOT_SET = 0, + }; + void Swap(StackFrame_Data* other); // implements Message ---------------------------------------------- @@ -217,10 +229,17 @@ class StackFrame_Data : public ::google::protobuf::Message { inline ::std::string* release_source(); inline void set_allocated_source(::std::string* source); - // optional bytes functionDisplayName = 6; + // optional uint64 sourceRef = 6; + inline bool has_sourceref() const; + inline void clear_sourceref(); + static const int kSourceRefFieldNumber = 6; + inline ::google::protobuf::uint64 sourceref() const; + inline void set_sourceref(::google::protobuf::uint64 value); + + // optional bytes functionDisplayName = 7; inline bool has_functiondisplayname() const; inline void clear_functiondisplayname(); - static const int kFunctionDisplayNameFieldNumber = 6; + static const int kFunctionDisplayNameFieldNumber = 7; inline const ::std::string& functiondisplayname() const; inline void set_functiondisplayname(const ::std::string& value); inline void set_functiondisplayname(const char* value); @@ -229,20 +248,29 @@ class StackFrame_Data : public ::google::protobuf::Message { inline ::std::string* release_functiondisplayname(); inline void set_allocated_functiondisplayname(::std::string* functiondisplayname); - // optional bool isSystem = 7; + // optional uint64 functionDisplayNameRef = 8; + inline bool has_functiondisplaynameref() const; + inline void clear_functiondisplaynameref(); + static const int kFunctionDisplayNameRefFieldNumber = 8; + inline ::google::protobuf::uint64 functiondisplaynameref() const; + inline void set_functiondisplaynameref(::google::protobuf::uint64 value); + + // optional bool isSystem = 9; inline bool has_issystem() const; inline void clear_issystem(); - static const int kIsSystemFieldNumber = 7; + static const int kIsSystemFieldNumber = 9; inline bool issystem() const; inline void set_issystem(bool value); - // optional bool isSelfHosted = 8; + // optional bool isSelfHosted = 10; inline bool has_isselfhosted() const; inline void clear_isselfhosted(); - static const int kIsSelfHostedFieldNumber = 8; + static const int kIsSelfHostedFieldNumber = 10; inline bool isselfhosted() const; inline void set_isselfhosted(bool value); + inline SourceOrRefCase SourceOrRef_case() const; + inline FunctionDisplayNameOrRefCase FunctionDisplayNameOrRef_case() const; // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.StackFrame.Data) private: inline void set_has_id(); @@ -254,14 +282,22 @@ class StackFrame_Data : public ::google::protobuf::Message { inline void set_has_column(); inline void clear_has_column(); inline void set_has_source(); - inline void clear_has_source(); + inline void set_has_sourceref(); inline void set_has_functiondisplayname(); - inline void clear_has_functiondisplayname(); + inline void set_has_functiondisplaynameref(); inline void set_has_issystem(); inline void clear_has_issystem(); inline void set_has_isselfhosted(); inline void clear_has_isselfhosted(); + inline bool has_SourceOrRef(); + void clear_SourceOrRef(); + inline void clear_has_SourceOrRef(); + + inline bool has_FunctionDisplayNameOrRef(); + void clear_FunctionDisplayNameOrRef(); + inline void clear_has_FunctionDisplayNameOrRef(); + ::google::protobuf::UnknownFieldSet _unknown_fields_; ::google::protobuf::uint32 _has_bits_[1]; @@ -270,10 +306,18 @@ class StackFrame_Data : public ::google::protobuf::Message { ::mozilla::devtools::protobuf::StackFrame* parent_; ::google::protobuf::uint32 line_; ::google::protobuf::uint32 column_; - ::std::string* source_; - ::std::string* functiondisplayname_; bool issystem_; bool isselfhosted_; + union SourceOrRefUnion { + ::std::string* source_; + ::google::protobuf::uint64 sourceref_; + } SourceOrRef_; + union FunctionDisplayNameOrRefUnion { + ::std::string* functiondisplayname_; + ::google::protobuf::uint64 functiondisplaynameref_; + } FunctionDisplayNameOrRef_; + ::google::protobuf::uint32 _oneof_case_[2]; + friend void protobuf_AddDesc_CoreDump_2eproto(); friend void protobuf_AssignDesc_CoreDump_2eproto(); friend void protobuf_ShutdownFile_CoreDump_2eproto(); @@ -412,6 +456,18 @@ class Node : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const Node& default_instance(); + enum TypeNameOrRefCase { + kTypeName = 2, + kTypeNameRef = 3, + TYPENAMEORREF_NOT_SET = 0, + }; + + enum JSObjectClassNameOrRefCase { + kJsObjectClassName = 7, + kJsObjectClassNameRef = 8, + JSOBJECTCLASSNAMEORREF_NOT_SET = 0, + }; + void Swap(Node* other); // implements Message ---------------------------------------------- @@ -461,17 +517,24 @@ class Node : public ::google::protobuf::Message { inline ::std::string* release_typename_(); inline void set_allocated_typename_(::std::string* typename_); - // optional uint64 size = 3; + // optional uint64 typeNameRef = 3; + inline bool has_typenameref() const; + inline void clear_typenameref(); + static const int kTypeNameRefFieldNumber = 3; + inline ::google::protobuf::uint64 typenameref() const; + inline void set_typenameref(::google::protobuf::uint64 value); + + // optional uint64 size = 4; inline bool has_size() const; inline void clear_size(); - static const int kSizeFieldNumber = 3; + static const int kSizeFieldNumber = 4; inline ::google::protobuf::uint64 size() const; inline void set_size(::google::protobuf::uint64 value); - // repeated .mozilla.devtools.protobuf.Edge edges = 4; + // repeated .mozilla.devtools.protobuf.Edge edges = 5; inline int edges_size() const; inline void clear_edges(); - static const int kEdgesFieldNumber = 4; + static const int kEdgesFieldNumber = 5; inline const ::mozilla::devtools::protobuf::Edge& edges(int index) const; inline ::mozilla::devtools::protobuf::Edge* mutable_edges(int index); inline ::mozilla::devtools::protobuf::Edge* add_edges(); @@ -480,19 +543,19 @@ class Node : public ::google::protobuf::Message { inline ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge >* mutable_edges(); - // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 5; + // optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6; inline bool has_allocationstack() const; inline void clear_allocationstack(); - static const int kAllocationStackFieldNumber = 5; + static const int kAllocationStackFieldNumber = 6; inline const ::mozilla::devtools::protobuf::StackFrame& allocationstack() const; inline ::mozilla::devtools::protobuf::StackFrame* mutable_allocationstack(); inline ::mozilla::devtools::protobuf::StackFrame* release_allocationstack(); inline void set_allocated_allocationstack(::mozilla::devtools::protobuf::StackFrame* allocationstack); - // optional bytes jsObjectClassName = 6; + // optional bytes jsObjectClassName = 7; inline bool has_jsobjectclassname() const; inline void clear_jsobjectclassname(); - static const int kJsObjectClassNameFieldNumber = 6; + static const int kJsObjectClassNameFieldNumber = 7; inline const ::std::string& jsobjectclassname() const; inline void set_jsobjectclassname(const ::std::string& value); inline void set_jsobjectclassname(const char* value); @@ -501,39 +564,64 @@ class Node : public ::google::protobuf::Message { inline ::std::string* release_jsobjectclassname(); inline void set_allocated_jsobjectclassname(::std::string* jsobjectclassname); - // optional uint32 coarseType = 7 [default = 0]; + // optional uint64 jsObjectClassNameRef = 8; + inline bool has_jsobjectclassnameref() const; + inline void clear_jsobjectclassnameref(); + static const int kJsObjectClassNameRefFieldNumber = 8; + inline ::google::protobuf::uint64 jsobjectclassnameref() const; + inline void set_jsobjectclassnameref(::google::protobuf::uint64 value); + + // optional uint32 coarseType = 9 [default = 0]; inline bool has_coarsetype() const; inline void clear_coarsetype(); - static const int kCoarseTypeFieldNumber = 7; + static const int kCoarseTypeFieldNumber = 9; inline ::google::protobuf::uint32 coarsetype() const; inline void set_coarsetype(::google::protobuf::uint32 value); + inline TypeNameOrRefCase TypeNameOrRef_case() const; + inline JSObjectClassNameOrRefCase JSObjectClassNameOrRef_case() const; // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.Node) private: inline void set_has_id(); inline void clear_has_id(); inline void set_has_typename_(); - inline void clear_has_typename_(); + inline void set_has_typenameref(); inline void set_has_size(); 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(); + inline void set_has_jsobjectclassnameref(); inline void set_has_coarsetype(); inline void clear_has_coarsetype(); + inline bool has_TypeNameOrRef(); + void clear_TypeNameOrRef(); + inline void clear_has_TypeNameOrRef(); + + inline bool has_JSObjectClassNameOrRef(); + void clear_JSObjectClassNameOrRef(); + inline void clear_has_JSObjectClassNameOrRef(); + ::google::protobuf::UnknownFieldSet _unknown_fields_; ::google::protobuf::uint32 _has_bits_[1]; mutable int _cached_size_; ::google::protobuf::uint64 id_; - ::std::string* typename__; ::google::protobuf::uint64 size_; ::google::protobuf::RepeatedPtrField< ::mozilla::devtools::protobuf::Edge > edges_; ::mozilla::devtools::protobuf::StackFrame* allocationstack_; - ::std::string* jsobjectclassname_; ::google::protobuf::uint32 coarsetype_; + union TypeNameOrRefUnion { + ::std::string* typename__; + ::google::protobuf::uint64 typenameref_; + } TypeNameOrRef_; + union JSObjectClassNameOrRefUnion { + ::std::string* jsobjectclassname_; + ::google::protobuf::uint64 jsobjectclassnameref_; + } JSObjectClassNameOrRef_; + ::google::protobuf::uint32 _oneof_case_[2]; + friend void protobuf_AddDesc_CoreDump_2eproto(); friend void protobuf_AssignDesc_CoreDump_2eproto(); friend void protobuf_ShutdownFile_CoreDump_2eproto(); @@ -566,6 +654,12 @@ class Edge : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const Edge& default_instance(); + enum EdgeNameOrRefCase { + kName = 2, + kNameRef = 3, + EDGENAMEORREF_NOT_SET = 0, + }; + void Swap(Edge* other); // implements Message ---------------------------------------------- @@ -615,19 +709,36 @@ class Edge : public ::google::protobuf::Message { inline ::std::string* release_name(); inline void set_allocated_name(::std::string* name); + // optional uint64 nameRef = 3; + inline bool has_nameref() const; + inline void clear_nameref(); + static const int kNameRefFieldNumber = 3; + inline ::google::protobuf::uint64 nameref() const; + inline void set_nameref(::google::protobuf::uint64 value); + + inline EdgeNameOrRefCase EdgeNameOrRef_case() const; // @@protoc_insertion_point(class_scope:mozilla.devtools.protobuf.Edge) private: inline void set_has_referent(); inline void clear_has_referent(); inline void set_has_name(); - inline void clear_has_name(); + inline void set_has_nameref(); + + inline bool has_EdgeNameOrRef(); + void clear_EdgeNameOrRef(); + inline void clear_has_EdgeNameOrRef(); ::google::protobuf::UnknownFieldSet _unknown_fields_; ::google::protobuf::uint32 _has_bits_[1]; mutable int _cached_size_; ::google::protobuf::uint64 referent_; - ::std::string* name_; + union EdgeNameOrRefUnion { + ::std::string* name_; + ::google::protobuf::uint64 nameref_; + } EdgeNameOrRef_; + ::google::protobuf::uint32 _oneof_case_[1]; + friend void protobuf_AddDesc_CoreDump_2eproto(); friend void protobuf_AssignDesc_CoreDump_2eproto(); friend void protobuf_ShutdownFile_CoreDump_2eproto(); @@ -785,165 +896,207 @@ inline void StackFrame_Data::set_column(::google::protobuf::uint32 value) { // optional bytes source = 5; inline bool StackFrame_Data::has_source() const { - return (_has_bits_[0] & 0x00000010u) != 0; + return SourceOrRef_case() == kSource; } inline void StackFrame_Data::set_has_source() { - _has_bits_[0] |= 0x00000010u; -} -inline void StackFrame_Data::clear_has_source() { - _has_bits_[0] &= ~0x00000010u; + _oneof_case_[0] = kSource; } inline void StackFrame_Data::clear_source() { - if (source_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - source_->clear(); + if (has_source()) { + delete SourceOrRef_.source_; + clear_has_SourceOrRef(); } - clear_has_source(); } inline const ::std::string& StackFrame_Data::source() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.source) - return *source_; + if (has_source()) { + return *SourceOrRef_.source_; + } + return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); } inline void StackFrame_Data::set_source(const ::std::string& value) { - set_has_source(); - if (source_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - source_ = new ::std::string; + if (!has_source()) { + clear_SourceOrRef(); + set_has_source(); + SourceOrRef_.source_ = new ::std::string; } - source_->assign(value); - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.source) + SourceOrRef_.source_->assign(value); } inline void StackFrame_Data::set_source(const char* value) { - set_has_source(); - if (source_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - source_ = new ::std::string; + if (!has_source()) { + clear_SourceOrRef(); + set_has_source(); + SourceOrRef_.source_ = new ::std::string; } - source_->assign(value); - // @@protoc_insertion_point(field_set_char:mozilla.devtools.protobuf.StackFrame.Data.source) + SourceOrRef_.source_->assign(value); } inline void StackFrame_Data::set_source(const void* value, size_t size) { - set_has_source(); - if (source_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - source_ = new ::std::string; + if (!has_source()) { + clear_SourceOrRef(); + set_has_source(); + SourceOrRef_.source_ = new ::std::string; } - source_->assign(reinterpret_cast(value), size); - // @@protoc_insertion_point(field_set_pointer:mozilla.devtools.protobuf.StackFrame.Data.source) + SourceOrRef_.source_->assign( + reinterpret_cast(value), size); } inline ::std::string* StackFrame_Data::mutable_source() { - set_has_source(); - if (source_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - source_ = new ::std::string; + if (!has_source()) { + clear_SourceOrRef(); + set_has_source(); + SourceOrRef_.source_ = new ::std::string; } - // @@protoc_insertion_point(field_mutable:mozilla.devtools.protobuf.StackFrame.Data.source) - return source_; + return SourceOrRef_.source_; } inline ::std::string* StackFrame_Data::release_source() { - clear_has_source(); - if (source_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = source_; - source_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + if (has_source()) { + clear_has_SourceOrRef(); + ::std::string* temp = SourceOrRef_.source_; + SourceOrRef_.source_ = NULL; return temp; + } else { + return NULL; } } inline void StackFrame_Data::set_allocated_source(::std::string* source) { - if (source_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete source_; - } + clear_SourceOrRef(); if (source) { set_has_source(); - source_ = source; - } else { - clear_has_source(); - source_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + SourceOrRef_.source_ = source; } - // @@protoc_insertion_point(field_set_allocated:mozilla.devtools.protobuf.StackFrame.Data.source) } -// optional bytes functionDisplayName = 6; +// optional uint64 sourceRef = 6; +inline bool StackFrame_Data::has_sourceref() const { + return SourceOrRef_case() == kSourceRef; +} +inline void StackFrame_Data::set_has_sourceref() { + _oneof_case_[0] = kSourceRef; +} +inline void StackFrame_Data::clear_sourceref() { + if (has_sourceref()) { + SourceOrRef_.sourceref_ = GOOGLE_ULONGLONG(0); + clear_has_SourceOrRef(); + } +} +inline ::google::protobuf::uint64 StackFrame_Data::sourceref() const { + if (has_sourceref()) { + return SourceOrRef_.sourceref_; + } + return GOOGLE_ULONGLONG(0); +} +inline void StackFrame_Data::set_sourceref(::google::protobuf::uint64 value) { + if (!has_sourceref()) { + clear_SourceOrRef(); + set_has_sourceref(); + } + SourceOrRef_.sourceref_ = value; +} + +// optional bytes functionDisplayName = 7; inline bool StackFrame_Data::has_functiondisplayname() const { - return (_has_bits_[0] & 0x00000020u) != 0; + return FunctionDisplayNameOrRef_case() == kFunctionDisplayName; } inline void StackFrame_Data::set_has_functiondisplayname() { - _has_bits_[0] |= 0x00000020u; -} -inline void StackFrame_Data::clear_has_functiondisplayname() { - _has_bits_[0] &= ~0x00000020u; + _oneof_case_[1] = kFunctionDisplayName; } inline void StackFrame_Data::clear_functiondisplayname() { - if (functiondisplayname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - functiondisplayname_->clear(); + if (has_functiondisplayname()) { + delete FunctionDisplayNameOrRef_.functiondisplayname_; + clear_has_FunctionDisplayNameOrRef(); } - clear_has_functiondisplayname(); } inline const ::std::string& StackFrame_Data::functiondisplayname() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.StackFrame.Data.functionDisplayName) - return *functiondisplayname_; + if (has_functiondisplayname()) { + return *FunctionDisplayNameOrRef_.functiondisplayname_; + } + return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); } inline void StackFrame_Data::set_functiondisplayname(const ::std::string& value) { - set_has_functiondisplayname(); - if (functiondisplayname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - functiondisplayname_ = new ::std::string; + if (!has_functiondisplayname()) { + clear_FunctionDisplayNameOrRef(); + set_has_functiondisplayname(); + FunctionDisplayNameOrRef_.functiondisplayname_ = new ::std::string; } - functiondisplayname_->assign(value); - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.functionDisplayName) + FunctionDisplayNameOrRef_.functiondisplayname_->assign(value); } inline void StackFrame_Data::set_functiondisplayname(const char* value) { - set_has_functiondisplayname(); - if (functiondisplayname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - functiondisplayname_ = new ::std::string; + if (!has_functiondisplayname()) { + clear_FunctionDisplayNameOrRef(); + set_has_functiondisplayname(); + FunctionDisplayNameOrRef_.functiondisplayname_ = new ::std::string; } - functiondisplayname_->assign(value); - // @@protoc_insertion_point(field_set_char:mozilla.devtools.protobuf.StackFrame.Data.functionDisplayName) + FunctionDisplayNameOrRef_.functiondisplayname_->assign(value); } inline void StackFrame_Data::set_functiondisplayname(const void* value, size_t size) { - set_has_functiondisplayname(); - if (functiondisplayname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - functiondisplayname_ = new ::std::string; + if (!has_functiondisplayname()) { + clear_FunctionDisplayNameOrRef(); + set_has_functiondisplayname(); + FunctionDisplayNameOrRef_.functiondisplayname_ = new ::std::string; } - functiondisplayname_->assign(reinterpret_cast(value), size); - // @@protoc_insertion_point(field_set_pointer:mozilla.devtools.protobuf.StackFrame.Data.functionDisplayName) + FunctionDisplayNameOrRef_.functiondisplayname_->assign( + reinterpret_cast(value), size); } inline ::std::string* StackFrame_Data::mutable_functiondisplayname() { - set_has_functiondisplayname(); - if (functiondisplayname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - functiondisplayname_ = new ::std::string; + if (!has_functiondisplayname()) { + clear_FunctionDisplayNameOrRef(); + set_has_functiondisplayname(); + FunctionDisplayNameOrRef_.functiondisplayname_ = new ::std::string; } - // @@protoc_insertion_point(field_mutable:mozilla.devtools.protobuf.StackFrame.Data.functionDisplayName) - return functiondisplayname_; + return FunctionDisplayNameOrRef_.functiondisplayname_; } inline ::std::string* StackFrame_Data::release_functiondisplayname() { - clear_has_functiondisplayname(); - if (functiondisplayname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = functiondisplayname_; - functiondisplayname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + if (has_functiondisplayname()) { + clear_has_FunctionDisplayNameOrRef(); + ::std::string* temp = FunctionDisplayNameOrRef_.functiondisplayname_; + FunctionDisplayNameOrRef_.functiondisplayname_ = NULL; return temp; + } else { + return NULL; } } inline void StackFrame_Data::set_allocated_functiondisplayname(::std::string* functiondisplayname) { - if (functiondisplayname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete functiondisplayname_; - } + clear_FunctionDisplayNameOrRef(); if (functiondisplayname) { set_has_functiondisplayname(); - functiondisplayname_ = functiondisplayname; - } else { - clear_has_functiondisplayname(); - functiondisplayname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + FunctionDisplayNameOrRef_.functiondisplayname_ = functiondisplayname; } - // @@protoc_insertion_point(field_set_allocated:mozilla.devtools.protobuf.StackFrame.Data.functionDisplayName) } -// optional bool isSystem = 7; +// optional uint64 functionDisplayNameRef = 8; +inline bool StackFrame_Data::has_functiondisplaynameref() const { + return FunctionDisplayNameOrRef_case() == kFunctionDisplayNameRef; +} +inline void StackFrame_Data::set_has_functiondisplaynameref() { + _oneof_case_[1] = kFunctionDisplayNameRef; +} +inline void StackFrame_Data::clear_functiondisplaynameref() { + if (has_functiondisplaynameref()) { + FunctionDisplayNameOrRef_.functiondisplaynameref_ = GOOGLE_ULONGLONG(0); + clear_has_FunctionDisplayNameOrRef(); + } +} +inline ::google::protobuf::uint64 StackFrame_Data::functiondisplaynameref() const { + if (has_functiondisplaynameref()) { + return FunctionDisplayNameOrRef_.functiondisplaynameref_; + } + return GOOGLE_ULONGLONG(0); +} +inline void StackFrame_Data::set_functiondisplaynameref(::google::protobuf::uint64 value) { + if (!has_functiondisplaynameref()) { + clear_FunctionDisplayNameOrRef(); + set_has_functiondisplaynameref(); + } + FunctionDisplayNameOrRef_.functiondisplaynameref_ = value; +} + +// optional bool isSystem = 9; inline bool StackFrame_Data::has_issystem() const { - return (_has_bits_[0] & 0x00000040u) != 0; + return (_has_bits_[0] & 0x00000100u) != 0; } inline void StackFrame_Data::set_has_issystem() { - _has_bits_[0] |= 0x00000040u; + _has_bits_[0] |= 0x00000100u; } inline void StackFrame_Data::clear_has_issystem() { - _has_bits_[0] &= ~0x00000040u; + _has_bits_[0] &= ~0x00000100u; } inline void StackFrame_Data::clear_issystem() { issystem_ = false; @@ -959,15 +1112,15 @@ inline void StackFrame_Data::set_issystem(bool value) { // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.isSystem) } -// optional bool isSelfHosted = 8; +// optional bool isSelfHosted = 10; inline bool StackFrame_Data::has_isselfhosted() const { - return (_has_bits_[0] & 0x00000080u) != 0; + return (_has_bits_[0] & 0x00000200u) != 0; } inline void StackFrame_Data::set_has_isselfhosted() { - _has_bits_[0] |= 0x00000080u; + _has_bits_[0] |= 0x00000200u; } inline void StackFrame_Data::clear_has_isselfhosted() { - _has_bits_[0] &= ~0x00000080u; + _has_bits_[0] &= ~0x00000200u; } inline void StackFrame_Data::clear_isselfhosted() { isselfhosted_ = false; @@ -983,6 +1136,24 @@ inline void StackFrame_Data::set_isselfhosted(bool value) { // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.StackFrame.Data.isSelfHosted) } +inline bool StackFrame_Data::has_SourceOrRef() { + return SourceOrRef_case() != SOURCEORREF_NOT_SET; +} +inline void StackFrame_Data::clear_has_SourceOrRef() { + _oneof_case_[0] = SOURCEORREF_NOT_SET; +} +inline bool StackFrame_Data::has_FunctionDisplayNameOrRef() { + return FunctionDisplayNameOrRef_case() != FUNCTIONDISPLAYNAMEORREF_NOT_SET; +} +inline void StackFrame_Data::clear_has_FunctionDisplayNameOrRef() { + _oneof_case_[1] = FUNCTIONDISPLAYNAMEORREF_NOT_SET; +} +inline StackFrame_Data::SourceOrRefCase StackFrame_Data::SourceOrRef_case() const { + return StackFrame_Data::SourceOrRefCase(_oneof_case_[0]); +} +inline StackFrame_Data::FunctionDisplayNameOrRefCase StackFrame_Data::FunctionDisplayNameOrRef_case() const { + return StackFrame_Data::FunctionDisplayNameOrRefCase(_oneof_case_[1]); +} // ------------------------------------------------------------------- // StackFrame @@ -1096,89 +1267,110 @@ inline void Node::set_id(::google::protobuf::uint64 value) { // optional bytes typeName = 2; inline bool Node::has_typename_() const { - return (_has_bits_[0] & 0x00000002u) != 0; + return TypeNameOrRef_case() == kTypeName; } inline void Node::set_has_typename_() { - _has_bits_[0] |= 0x00000002u; -} -inline void Node::clear_has_typename_() { - _has_bits_[0] &= ~0x00000002u; + _oneof_case_[0] = kTypeName; } inline void Node::clear_typename_() { - if (typename__ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - typename__->clear(); + if (has_typename_()) { + delete TypeNameOrRef_.typename__; + clear_has_TypeNameOrRef(); } - clear_has_typename_(); } inline const ::std::string& Node::typename_() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.typeName) - return *typename__; + if (has_typename_()) { + return *TypeNameOrRef_.typename__; + } + return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); } inline void Node::set_typename_(const ::std::string& value) { - set_has_typename_(); - if (typename__ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - typename__ = new ::std::string; + if (!has_typename_()) { + clear_TypeNameOrRef(); + set_has_typename_(); + TypeNameOrRef_.typename__ = new ::std::string; } - typename__->assign(value); - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Node.typeName) + TypeNameOrRef_.typename__->assign(value); } inline void Node::set_typename_(const char* value) { - set_has_typename_(); - if (typename__ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - typename__ = new ::std::string; + if (!has_typename_()) { + clear_TypeNameOrRef(); + set_has_typename_(); + TypeNameOrRef_.typename__ = new ::std::string; } - typename__->assign(value); - // @@protoc_insertion_point(field_set_char:mozilla.devtools.protobuf.Node.typeName) + TypeNameOrRef_.typename__->assign(value); } inline void Node::set_typename_(const void* value, size_t size) { - set_has_typename_(); - if (typename__ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - typename__ = new ::std::string; + if (!has_typename_()) { + clear_TypeNameOrRef(); + set_has_typename_(); + TypeNameOrRef_.typename__ = new ::std::string; } - typename__->assign(reinterpret_cast(value), size); - // @@protoc_insertion_point(field_set_pointer:mozilla.devtools.protobuf.Node.typeName) + TypeNameOrRef_.typename__->assign( + reinterpret_cast(value), size); } inline ::std::string* Node::mutable_typename_() { - set_has_typename_(); - if (typename__ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - typename__ = new ::std::string; + if (!has_typename_()) { + clear_TypeNameOrRef(); + set_has_typename_(); + TypeNameOrRef_.typename__ = new ::std::string; } - // @@protoc_insertion_point(field_mutable:mozilla.devtools.protobuf.Node.typeName) - return typename__; + return TypeNameOrRef_.typename__; } inline ::std::string* Node::release_typename_() { - clear_has_typename_(); - if (typename__ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = typename__; - typename__ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + if (has_typename_()) { + clear_has_TypeNameOrRef(); + ::std::string* temp = TypeNameOrRef_.typename__; + TypeNameOrRef_.typename__ = NULL; return temp; + } else { + return NULL; } } inline void Node::set_allocated_typename_(::std::string* typename_) { - if (typename__ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete typename__; - } + clear_TypeNameOrRef(); if (typename_) { set_has_typename_(); - typename__ = typename_; - } else { - clear_has_typename_(); - typename__ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + TypeNameOrRef_.typename__ = typename_; } - // @@protoc_insertion_point(field_set_allocated:mozilla.devtools.protobuf.Node.typeName) } -// optional uint64 size = 3; +// optional uint64 typeNameRef = 3; +inline bool Node::has_typenameref() const { + return TypeNameOrRef_case() == kTypeNameRef; +} +inline void Node::set_has_typenameref() { + _oneof_case_[0] = kTypeNameRef; +} +inline void Node::clear_typenameref() { + if (has_typenameref()) { + TypeNameOrRef_.typenameref_ = GOOGLE_ULONGLONG(0); + clear_has_TypeNameOrRef(); + } +} +inline ::google::protobuf::uint64 Node::typenameref() const { + if (has_typenameref()) { + return TypeNameOrRef_.typenameref_; + } + return GOOGLE_ULONGLONG(0); +} +inline void Node::set_typenameref(::google::protobuf::uint64 value) { + if (!has_typenameref()) { + clear_TypeNameOrRef(); + set_has_typenameref(); + } + TypeNameOrRef_.typenameref_ = value; +} + +// optional uint64 size = 4; inline bool Node::has_size() const { - return (_has_bits_[0] & 0x00000004u) != 0; + return (_has_bits_[0] & 0x00000008u) != 0; } inline void Node::set_has_size() { - _has_bits_[0] |= 0x00000004u; + _has_bits_[0] |= 0x00000008u; } inline void Node::clear_has_size() { - _has_bits_[0] &= ~0x00000004u; + _has_bits_[0] &= ~0x00000008u; } inline void Node::clear_size() { size_ = GOOGLE_ULONGLONG(0); @@ -1194,7 +1386,7 @@ inline void Node::set_size(::google::protobuf::uint64 value) { // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Node.size) } -// repeated .mozilla.devtools.protobuf.Edge edges = 4; +// repeated .mozilla.devtools.protobuf.Edge edges = 5; inline int Node::edges_size() const { return edges_.size(); } @@ -1224,15 +1416,15 @@ Node::mutable_edges() { return &edges_; } -// optional .mozilla.devtools.protobuf.StackFrame allocationStack = 5; +// optional .mozilla.devtools.protobuf.StackFrame allocationStack = 6; inline bool Node::has_allocationstack() const { - return (_has_bits_[0] & 0x00000010u) != 0; + return (_has_bits_[0] & 0x00000020u) != 0; } inline void Node::set_has_allocationstack() { - _has_bits_[0] |= 0x00000010u; + _has_bits_[0] |= 0x00000020u; } inline void Node::clear_has_allocationstack() { - _has_bits_[0] &= ~0x00000010u; + _has_bits_[0] &= ~0x00000020u; } inline void Node::clear_allocationstack() { if (allocationstack_ != NULL) allocationstack_->::mozilla::devtools::protobuf::StackFrame::Clear(); @@ -1265,91 +1457,112 @@ 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; +// optional bytes jsObjectClassName = 7; inline bool Node::has_jsobjectclassname() const { - return (_has_bits_[0] & 0x00000020u) != 0; + return JSObjectClassNameOrRef_case() == kJsObjectClassName; } inline void Node::set_has_jsobjectclassname() { - _has_bits_[0] |= 0x00000020u; -} -inline void Node::clear_has_jsobjectclassname() { - _has_bits_[0] &= ~0x00000020u; + _oneof_case_[1] = kJsObjectClassName; } inline void Node::clear_jsobjectclassname() { - if (jsobjectclassname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - jsobjectclassname_->clear(); + if (has_jsobjectclassname()) { + delete JSObjectClassNameOrRef_.jsobjectclassname_; + clear_has_JSObjectClassNameOrRef(); } - clear_has_jsobjectclassname(); } inline const ::std::string& Node::jsobjectclassname() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Node.jsObjectClassName) - return *jsobjectclassname_; + if (has_jsobjectclassname()) { + return *JSObjectClassNameOrRef_.jsobjectclassname_; + } + return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); } inline void Node::set_jsobjectclassname(const ::std::string& value) { - set_has_jsobjectclassname(); - if (jsobjectclassname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - jsobjectclassname_ = new ::std::string; + if (!has_jsobjectclassname()) { + clear_JSObjectClassNameOrRef(); + set_has_jsobjectclassname(); + JSObjectClassNameOrRef_.jsobjectclassname_ = new ::std::string; } - jsobjectclassname_->assign(value); - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Node.jsObjectClassName) + JSObjectClassNameOrRef_.jsobjectclassname_->assign(value); } inline void Node::set_jsobjectclassname(const char* value) { - set_has_jsobjectclassname(); - if (jsobjectclassname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - jsobjectclassname_ = new ::std::string; + if (!has_jsobjectclassname()) { + clear_JSObjectClassNameOrRef(); + set_has_jsobjectclassname(); + JSObjectClassNameOrRef_.jsobjectclassname_ = new ::std::string; } - jsobjectclassname_->assign(value); - // @@protoc_insertion_point(field_set_char:mozilla.devtools.protobuf.Node.jsObjectClassName) + JSObjectClassNameOrRef_.jsobjectclassname_->assign(value); } inline void Node::set_jsobjectclassname(const void* value, size_t size) { - set_has_jsobjectclassname(); - if (jsobjectclassname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - jsobjectclassname_ = new ::std::string; + if (!has_jsobjectclassname()) { + clear_JSObjectClassNameOrRef(); + set_has_jsobjectclassname(); + JSObjectClassNameOrRef_.jsobjectclassname_ = new ::std::string; } - jsobjectclassname_->assign(reinterpret_cast(value), size); - // @@protoc_insertion_point(field_set_pointer:mozilla.devtools.protobuf.Node.jsObjectClassName) + JSObjectClassNameOrRef_.jsobjectclassname_->assign( + reinterpret_cast(value), size); } inline ::std::string* Node::mutable_jsobjectclassname() { - set_has_jsobjectclassname(); - if (jsobjectclassname_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - jsobjectclassname_ = new ::std::string; + if (!has_jsobjectclassname()) { + clear_JSObjectClassNameOrRef(); + set_has_jsobjectclassname(); + JSObjectClassNameOrRef_.jsobjectclassname_ = new ::std::string; } - // @@protoc_insertion_point(field_mutable:mozilla.devtools.protobuf.Node.jsObjectClassName) - return jsobjectclassname_; + return JSObjectClassNameOrRef_.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()); + if (has_jsobjectclassname()) { + clear_has_JSObjectClassNameOrRef(); + ::std::string* temp = JSObjectClassNameOrRef_.jsobjectclassname_; + JSObjectClassNameOrRef_.jsobjectclassname_ = NULL; return temp; + } else { + return NULL; } } inline void Node::set_allocated_jsobjectclassname(::std::string* jsobjectclassname) { - if (jsobjectclassname_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete jsobjectclassname_; - } + clear_JSObjectClassNameOrRef(); if (jsobjectclassname) { set_has_jsobjectclassname(); - jsobjectclassname_ = jsobjectclassname; - } else { - clear_has_jsobjectclassname(); - jsobjectclassname_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + JSObjectClassNameOrRef_.jsobjectclassname_ = jsobjectclassname; } - // @@protoc_insertion_point(field_set_allocated:mozilla.devtools.protobuf.Node.jsObjectClassName) } -// optional uint32 coarseType = 7 [default = 0]; +// optional uint64 jsObjectClassNameRef = 8; +inline bool Node::has_jsobjectclassnameref() const { + return JSObjectClassNameOrRef_case() == kJsObjectClassNameRef; +} +inline void Node::set_has_jsobjectclassnameref() { + _oneof_case_[1] = kJsObjectClassNameRef; +} +inline void Node::clear_jsobjectclassnameref() { + if (has_jsobjectclassnameref()) { + JSObjectClassNameOrRef_.jsobjectclassnameref_ = GOOGLE_ULONGLONG(0); + clear_has_JSObjectClassNameOrRef(); + } +} +inline ::google::protobuf::uint64 Node::jsobjectclassnameref() const { + if (has_jsobjectclassnameref()) { + return JSObjectClassNameOrRef_.jsobjectclassnameref_; + } + return GOOGLE_ULONGLONG(0); +} +inline void Node::set_jsobjectclassnameref(::google::protobuf::uint64 value) { + if (!has_jsobjectclassnameref()) { + clear_JSObjectClassNameOrRef(); + set_has_jsobjectclassnameref(); + } + JSObjectClassNameOrRef_.jsobjectclassnameref_ = value; +} + +// optional uint32 coarseType = 9 [default = 0]; inline bool Node::has_coarsetype() const { - return (_has_bits_[0] & 0x00000040u) != 0; + return (_has_bits_[0] & 0x00000100u) != 0; } inline void Node::set_has_coarsetype() { - _has_bits_[0] |= 0x00000040u; + _has_bits_[0] |= 0x00000100u; } inline void Node::clear_has_coarsetype() { - _has_bits_[0] &= ~0x00000040u; + _has_bits_[0] &= ~0x00000100u; } inline void Node::clear_coarsetype() { coarsetype_ = 0u; @@ -1365,6 +1578,24 @@ inline void Node::set_coarsetype(::google::protobuf::uint32 value) { // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Node.coarseType) } +inline bool Node::has_TypeNameOrRef() { + return TypeNameOrRef_case() != TYPENAMEORREF_NOT_SET; +} +inline void Node::clear_has_TypeNameOrRef() { + _oneof_case_[0] = TYPENAMEORREF_NOT_SET; +} +inline bool Node::has_JSObjectClassNameOrRef() { + return JSObjectClassNameOrRef_case() != JSOBJECTCLASSNAMEORREF_NOT_SET; +} +inline void Node::clear_has_JSObjectClassNameOrRef() { + _oneof_case_[1] = JSOBJECTCLASSNAMEORREF_NOT_SET; +} +inline Node::TypeNameOrRefCase Node::TypeNameOrRef_case() const { + return Node::TypeNameOrRefCase(_oneof_case_[0]); +} +inline Node::JSObjectClassNameOrRefCase Node::JSObjectClassNameOrRef_case() const { + return Node::JSObjectClassNameOrRefCase(_oneof_case_[1]); +} // ------------------------------------------------------------------- // Edge @@ -1395,80 +1626,110 @@ inline void Edge::set_referent(::google::protobuf::uint64 value) { // optional bytes name = 2; inline bool Edge::has_name() const { - return (_has_bits_[0] & 0x00000002u) != 0; + return EdgeNameOrRef_case() == kName; } inline void Edge::set_has_name() { - _has_bits_[0] |= 0x00000002u; -} -inline void Edge::clear_has_name() { - _has_bits_[0] &= ~0x00000002u; + _oneof_case_[0] = kName; } inline void Edge::clear_name() { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_->clear(); + if (has_name()) { + delete EdgeNameOrRef_.name_; + clear_has_EdgeNameOrRef(); } - clear_has_name(); } inline const ::std::string& Edge::name() const { - // @@protoc_insertion_point(field_get:mozilla.devtools.protobuf.Edge.name) - return *name_; + if (has_name()) { + return *EdgeNameOrRef_.name_; + } + return ::google::protobuf::internal::GetEmptyStringAlreadyInited(); } inline void Edge::set_name(const ::std::string& value) { - set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; + if (!has_name()) { + clear_EdgeNameOrRef(); + set_has_name(); + EdgeNameOrRef_.name_ = new ::std::string; } - name_->assign(value); - // @@protoc_insertion_point(field_set:mozilla.devtools.protobuf.Edge.name) + EdgeNameOrRef_.name_->assign(value); } inline void Edge::set_name(const char* value) { - set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; + if (!has_name()) { + clear_EdgeNameOrRef(); + set_has_name(); + EdgeNameOrRef_.name_ = new ::std::string; } - name_->assign(value); - // @@protoc_insertion_point(field_set_char:mozilla.devtools.protobuf.Edge.name) + EdgeNameOrRef_.name_->assign(value); } inline void Edge::set_name(const void* value, size_t size) { - set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; + if (!has_name()) { + clear_EdgeNameOrRef(); + set_has_name(); + EdgeNameOrRef_.name_ = new ::std::string; } - name_->assign(reinterpret_cast(value), size); - // @@protoc_insertion_point(field_set_pointer:mozilla.devtools.protobuf.Edge.name) + EdgeNameOrRef_.name_->assign( + reinterpret_cast(value), size); } inline ::std::string* Edge::mutable_name() { - set_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - name_ = new ::std::string; + if (!has_name()) { + clear_EdgeNameOrRef(); + set_has_name(); + EdgeNameOrRef_.name_ = new ::std::string; } - // @@protoc_insertion_point(field_mutable:mozilla.devtools.protobuf.Edge.name) - return name_; + return EdgeNameOrRef_.name_; } inline ::std::string* Edge::release_name() { - clear_has_name(); - if (name_ == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - return NULL; - } else { - ::std::string* temp = name_; - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + if (has_name()) { + clear_has_EdgeNameOrRef(); + ::std::string* temp = EdgeNameOrRef_.name_; + EdgeNameOrRef_.name_ = NULL; return temp; + } else { + return NULL; } } inline void Edge::set_allocated_name(::std::string* name) { - if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) { - delete name_; - } + clear_EdgeNameOrRef(); if (name) { set_has_name(); - name_ = name; - } else { - clear_has_name(); - name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + EdgeNameOrRef_.name_ = name; } - // @@protoc_insertion_point(field_set_allocated:mozilla.devtools.protobuf.Edge.name) } +// optional uint64 nameRef = 3; +inline bool Edge::has_nameref() const { + return EdgeNameOrRef_case() == kNameRef; +} +inline void Edge::set_has_nameref() { + _oneof_case_[0] = kNameRef; +} +inline void Edge::clear_nameref() { + if (has_nameref()) { + EdgeNameOrRef_.nameref_ = GOOGLE_ULONGLONG(0); + clear_has_EdgeNameOrRef(); + } +} +inline ::google::protobuf::uint64 Edge::nameref() const { + if (has_nameref()) { + return EdgeNameOrRef_.nameref_; + } + return GOOGLE_ULONGLONG(0); +} +inline void Edge::set_nameref(::google::protobuf::uint64 value) { + if (!has_nameref()) { + clear_EdgeNameOrRef(); + set_has_nameref(); + } + EdgeNameOrRef_.nameref_ = value; +} + +inline bool Edge::has_EdgeNameOrRef() { + return EdgeNameOrRef_case() != EDGENAMEORREF_NOT_SET; +} +inline void Edge::clear_has_EdgeNameOrRef() { + _oneof_case_[0] = EDGENAMEORREF_NOT_SET; +} +inline Edge::EdgeNameOrRefCase Edge::EdgeNameOrRef_case() const { + return Edge::EdgeNameOrRefCase(_oneof_case_[0]); +} // @@protoc_insertion_point(namespace_scope) diff --git a/devtools/shared/heapsnapshot/CoreDump.proto b/devtools/shared/heapsnapshot/CoreDump.proto index a97ac364a5a..450833807d3 100644 --- a/devtools/shared/heapsnapshot/CoreDump.proto +++ b/devtools/shared/heapsnapshot/CoreDump.proto @@ -38,11 +38,25 @@ // | . | // +-----------------------------------------------------------------------+ // -// In practice, certain message fields have a lot of duplication (such as type -// or edge name strings). Rather than try and de-duplicate this information at -// the protobuf message and field level, core dumps should be written with -// `google::protobuf::io::GzipOutputStream` and read from +// Core dumps should always be written with a +// `google::protobuf::io::GzipOutputStream` and read from a // `google::protobuf::io::GzipInputStream`. +// +// Note that all strings are de-duplicated. The first time the N^th unique +// string is encountered, the full string is serialized. Subsequent times that +// same string is encountered, it is referenced by N. This de-duplication +// happens across string properties, not on a per-property basis. For example, +// if the same K^th unique string is first used as an Edge::EdgeNameOrRef and +// then as a StackFrame::Data::FunctionDisplayNameOrRef, the first will be the +// actual string as the functionDisplayName oneof property, and the second will +// be a reference to the first as the edgeNameRef oneof property whose value is +// K. +// +// We would ordinarily abstract these de-duplicated strings with messages of +// their own, but unfortunately, the protobuf compiler does not have a way to +// inline a messsage within another message and the child message must be +// referenced by pointer. This leads to extra mallocs that we wish to avoid. + package mozilla.devtools.protobuf; @@ -65,36 +79,59 @@ message StackFrame { } message Data { - optional uint64 id = 1; - optional StackFrame parent = 2; - optional uint32 line = 3; - optional uint32 column = 4; - // char16_t[] - optional bytes source = 5; - // char16_t[] - optional bytes functionDisplayName = 6; - optional bool isSystem = 7; - optional bool isSelfHosted = 8; + optional uint64 id = 1; + optional StackFrame parent = 2; + optional uint32 line = 3; + optional uint32 column = 4; + + // De-duplicated two-byte string. + oneof SourceOrRef { + bytes source = 5; + uint64 sourceRef = 6; + } + + // De-duplicated two-byte string. + oneof FunctionDisplayNameOrRef { + bytes functionDisplayName = 7; + uint64 functionDisplayNameRef = 8; + } + + optional bool isSystem = 9; + optional bool isSelfHosted = 10; } } // A serialized version of `JS::ubi::Node` and its outgoing edges. message Node { - optional uint64 id = 1; - // char16_t[] - optional bytes typeName = 2; - optional uint64 size = 3; - repeated Edge edges = 4; - optional StackFrame allocationStack = 5; - // char[] - optional bytes jsObjectClassName = 6; + optional uint64 id = 1; + + // De-duplicated two-byte string. + oneof TypeNameOrRef { + bytes typeName = 2; + uint64 typeNameRef = 3; + } + + optional uint64 size = 4; + repeated Edge edges = 5; + optional StackFrame allocationStack = 6; + + // De-duplicated one-byte string. + oneof JSObjectClassNameOrRef { + bytes jsObjectClassName = 7; + uint64 jsObjectClassNameRef = 8; + } + // JS::ubi::CoarseType. Defaults to Other. - optional uint32 coarseType = 7 [default = 0]; + optional uint32 coarseType = 9 [default = 0]; } // A serialized edge from the heap graph. message Edge { - optional uint64 referent = 1; - // char16_t[] - optional bytes name = 2; + optional uint64 referent = 1; + + // De-duplicated two-byte string. + oneof EdgeNameOrRef { + bytes name = 2; + uint64 nameRef = 3; + } } diff --git a/devtools/shared/heapsnapshot/DeserializedNode.cpp b/devtools/shared/heapsnapshot/DeserializedNode.cpp index 4b5b118c35b..edf01e7d486 100644 --- a/devtools/shared/heapsnapshot/DeserializedNode.cpp +++ b/devtools/shared/heapsnapshot/DeserializedNode.cpp @@ -10,11 +10,6 @@ namespace mozilla { namespace devtools { -DeserializedEdge::DeserializedEdge() - : referent(0) - , name(nullptr) -{ } - DeserializedEdge::DeserializedEdge(DeserializedEdge&& rhs) { referent = rhs.referent; @@ -29,26 +24,6 @@ DeserializedEdge& DeserializedEdge::operator=(DeserializedEdge&& rhs) return *this; } -bool -DeserializedEdge::init(const protobuf::Edge& edge, HeapSnapshot& owner) -{ - // Although the referent property is optional in the protobuf format for - // future compatibility, we can't semantically have an edge to nowhere and - // require a referent here. - if (!edge.has_referent()) - return false; - referent = edge.referent(); - - if (edge.has_name()) { - const char16_t* duplicateEdgeName = reinterpret_cast(edge.name().c_str()); - name = owner.borrowUniqueString(duplicateEdgeName, edge.name().length() / sizeof(char16_t)); - if (!name) - return false; - } - - return true; -} - JS::ubi::Node DeserializedNode::getEdgeReferent(const DeserializedEdge& edge) { diff --git a/devtools/shared/heapsnapshot/DeserializedNode.h b/devtools/shared/heapsnapshot/DeserializedNode.h index 390d0fd984c..52b9cf287aa 100644 --- a/devtools/shared/heapsnapshot/DeserializedNode.h +++ b/devtools/shared/heapsnapshot/DeserializedNode.h @@ -40,13 +40,13 @@ struct DeserializedEdge { // A borrowed reference to a string owned by this node's owning HeapSnapshot. const char16_t* name; - explicit DeserializedEdge(); + explicit DeserializedEdge(NodeId referent, const char16_t* edgeName = nullptr) + : referent(referent) + , name(edgeName) + { } DeserializedEdge(DeserializedEdge&& rhs); DeserializedEdge& operator=(DeserializedEdge&& rhs); - // Initialize this `DeserializedEdge` from the given `protobuf::Edge` message. - bool init(const protobuf::Edge& edge, HeapSnapshot& owner); - private: DeserializedEdge(const DeserializedEdge&) = delete; DeserializedEdge& operator=(const DeserializedEdge&) = delete; @@ -65,7 +65,8 @@ struct DeserializedNode { uint64_t size; EdgeVector edges; Maybe allocationStack; - UniquePtr jsObjectClassName; + // A borrowed reference to a string owned by this node's owning HeapSnapshot. + const 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; @@ -76,7 +77,7 @@ struct DeserializedNode { uint64_t size, EdgeVector&& edges, Maybe allocationStack, - UniquePtr&& className, + const char* className, HeapSnapshot& owner) : id(id) , coarseType(coarseType) @@ -84,7 +85,7 @@ struct DeserializedNode { , size(size) , edges(Move(edges)) , allocationStack(allocationStack) - , jsObjectClassName(Move(className)) + , jsObjectClassName(className) , owner(&owner) { } virtual ~DeserializedNode() { } @@ -96,7 +97,7 @@ struct DeserializedNode { , size(rhs.size) , edges(Move(rhs.edges)) , allocationStack(rhs.allocationStack) - , jsObjectClassName(Move(rhs.jsObjectClassName)) + , jsObjectClassName(rhs.jsObjectClassName) , owner(rhs.owner) { } @@ -258,7 +259,7 @@ public: bool isLive() const override { return false; } const char16_t* typeName() const override; Node::Size size(mozilla::MallocSizeOf mallocSizeof) const override; - const char* jsObjectClassName() const override { return get().jsObjectClassName.get(); } + const char* jsObjectClassName() const override { return get().jsObjectClassName; } bool hasAllocationStack() const override { return get().allocationStack.isSome(); } StackFrame allocationStack() const override; diff --git a/devtools/shared/heapsnapshot/HeapSnapshot.cpp b/devtools/shared/heapsnapshot/HeapSnapshot.cpp index a0ef56ab1ff..3377401d3dd 100644 --- a/devtools/shared/heapsnapshot/HeapSnapshot.cpp +++ b/devtools/shared/heapsnapshot/HeapSnapshot.cpp @@ -50,6 +50,8 @@ using ::google::protobuf::io::CodedInputStream; using ::google::protobuf::io::GzipInputStream; using ::google::protobuf::io::ZeroCopyInputStream; +using JS::ubi::AtomOrTwoByteChars; + NS_IMPL_CYCLE_COLLECTION_CLASS(HeapSnapshot) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(HeapSnapshot) @@ -122,76 +124,159 @@ parseMessage(ZeroCopyInputStream& stream, MessageType& message) return true; } +template +struct GetOrInternStringMatcher +{ + using ReturnType = const CharT*; + + InternedStringSet& internedStrings; + + explicit GetOrInternStringMatcher(InternedStringSet& strings) : internedStrings(strings) { } + + const CharT* match(const std::string* str) { + MOZ_ASSERT(str); + size_t length = str->length() / sizeof(CharT); + auto tempString = reinterpret_cast(str->data()); + + UniquePtr owned(NS_strndup(tempString, length)); + if (!owned || !internedStrings.append(Move(owned))) + return nullptr; + + return internedStrings.back().get(); + } + + const CharT* match(uint64_t ref) { + if (MOZ_LIKELY(ref < internedStrings.length())) { + auto& string = internedStrings[ref]; + MOZ_ASSERT(string); + return string.get(); + } + + return nullptr; + } +}; + +template< + // Either char or char16_t. + typename CharT, + // A reference to either `internedOneByteStrings` or `internedTwoByteStrings` + // if CharT is char or char16_t respectively. + typename InternedStringSet> +const CharT* +HeapSnapshot::getOrInternString(InternedStringSet& internedStrings, + Maybe& maybeStrOrRef) +{ + // Incomplete message: has neither a string nor a reference to an already + // interned string. + if (MOZ_UNLIKELY(maybeStrOrRef.isNothing())) + return nullptr; + + GetOrInternStringMatcher m(internedStrings); + return maybeStrOrRef->match(m); +} + +// Get a de-duplicated string as a Maybe from the given `msg`. +#define GET_STRING_OR_REF_WITH_PROP_NAMES(msg, strPropertyName, refPropertyName) \ + (msg.has_##refPropertyName() \ + ? Some(StringOrRef(msg.refPropertyName())) \ + : msg.has_##strPropertyName() \ + ? Some(StringOrRef(&msg.strPropertyName())) \ + : Nothing()) + +#define GET_STRING_OR_REF(msg, property) \ + (msg.has_##property##ref() \ + ? Some(StringOrRef(msg.property##ref())) \ + : msg.has_##property() \ + ? Some(StringOrRef(&msg.property())) \ + : Nothing()) + bool HeapSnapshot::saveNode(const protobuf::Node& node) { - if (!node.has_id()) + // 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(); // Should only deserialize each node once. - if (nodes.has(id)) + if (NS_WARN_IF(nodes.has(id))) return false; - if (!JS::ubi::Uint32IsValidCoarseType(node.coarsetype())) + if (NS_WARN_IF(!JS::ubi::Uint32IsValidCoarseType(node.coarsetype()))) return false; auto coarseType = JS::ubi::Uint32ToCoarseType(node.coarsetype()); - if (!node.has_typename_()) + Maybe typeNameOrRef = GET_STRING_OR_REF_WITH_PROP_NAMES(node, typename_, typenameref); + auto typeName = getOrInternString(internedTwoByteStrings, typeNameOrRef); + if (NS_WARN_IF(!typeName)) return false; - auto duplicatedTypeName = reinterpret_cast( - node.typename_().data()); - auto length = node.typename_().length() / sizeof(char16_t); - auto typeName = borrowUniqueString(duplicatedTypeName, length); - if (!typeName) - return false; - - if (!node.has_size()) + if (NS_WARN_IF(!node.has_size())) return false; uint64_t size = node.size(); auto edgesLength = node.edges_size(); DeserializedNode::EdgeVector edges; - if (!edges.reserve(edgesLength)) + if (NS_WARN_IF(!edges.reserve(edgesLength))) return false; for (decltype(edgesLength) i = 0; i < edgesLength; i++) { - DeserializedEdge edge; - if (!edge.init(node.edges(i), *this)) + auto& protoEdge = node.edges(i); + + if (NS_WARN_IF(!protoEdge.has_referent())) return false; - edges.infallibleAppend(Move(edge)); + NodeId referent = protoEdge.referent(); + + const char16_t* edgeName = nullptr; + if (protoEdge.EdgeNameOrRef_case() != protobuf::Edge::EDGENAMEORREF_NOT_SET) { + Maybe edgeNameOrRef = GET_STRING_OR_REF(protoEdge, name); + edgeName = getOrInternString(internedTwoByteStrings, edgeNameOrRef); + if (NS_WARN_IF(!edgeName)) + return false; + } + + edges.infallibleAppend(DeserializedEdge(referent, edgeName)); } Maybe allocationStack; if (node.has_allocationstack()) { StackFrameId id = 0; - if (!saveStackFrame(node.allocationstack(), id)) + if (NS_WARN_IF(!saveStackFrame(node.allocationstack(), id))) return false; allocationStack.emplace(id); } MOZ_ASSERT(allocationStack.isSome() == node.has_allocationstack()); - UniquePtr jsObjectClassName; - if (node.has_jsobjectclassname()) { - auto length = node.jsobjectclassname().length(); - jsObjectClassName.reset(static_cast(malloc(length + 1))); - if (!jsObjectClassName) + const char* jsObjectClassName = nullptr; + if (node.JSObjectClassNameOrRef_case() != protobuf::Node::JSOBJECTCLASSNAMEORREF_NOT_SET) { + Maybe clsNameOrRef = GET_STRING_OR_REF(node, jsobjectclassname); + jsObjectClassName = getOrInternString(internedOneByteStrings, clsNameOrRef); + if (NS_WARN_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)); + if (NS_WARN_IF(!nodes.putNew(id, DeserializedNode(id, coarseType, typeName, + size, Move(edges), + allocationStack, + jsObjectClassName, *this)))) + { + return false; + }; + + return true; } 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. @@ -216,14 +301,6 @@ HeapSnapshot::saveStackFrame(const protobuf::StackFrame& frame, if (frames.has(id)) return false; - Maybe 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(); @@ -232,25 +309,6 @@ HeapSnapshot::saveStackFrame(const protobuf::StackFrame& frame, return false; uint32_t column = data.column(); - auto duplicatedSource = reinterpret_cast( - 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( - 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(); @@ -259,6 +317,29 @@ HeapSnapshot::saveStackFrame(const protobuf::StackFrame& frame, return false; bool isSelfHosted = data.isselfhosted(); + Maybe sourceOrRef = GET_STRING_OR_REF(data, source); + auto source = getOrInternString(internedTwoByteStrings, sourceOrRef); + if (!source) + return false; + + const char16_t* functionDisplayName = nullptr; + if (data.FunctionDisplayNameOrRef_case() != + protobuf::StackFrame_Data::FUNCTIONDISPLAYNAMEORREF_NOT_SET) + { + Maybe nameOrRef = GET_STRING_OR_REF(data, functiondisplayname); + functionDisplayName = getOrInternString(internedTwoByteStrings, nameOrRef); + if (!functionDisplayName) + return false; + } + + Maybe 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))) @@ -296,7 +377,7 @@ StreamHasData(GzipInputStream& stream) bool HeapSnapshot::init(const uint8_t* buffer, uint32_t size) { - if (!nodes.init() || !frames.init() || !strings.init()) + if (!nodes.init() || !frames.init()) return false; ArrayInputStream stream(buffer, size); @@ -338,22 +419,6 @@ HeapSnapshot::init(const uint8_t* buffer, uint32_t size) return true; } -const char16_t* -HeapSnapshot::borrowUniqueString(const char16_t* duplicateString, size_t length) -{ - MOZ_ASSERT(duplicateString); - UniqueStringHashPolicy::Lookup lookup(duplicateString, length); - auto ptr = strings.lookupForAdd(lookup); - - if (!ptr) { - UniqueString owned(NS_strndup(duplicateString, length)); - if (!owned || !strings.add(ptr, Move(owned))) - return nullptr; - } - - MOZ_ASSERT(ptr->get() != duplicateString); - return ptr->get(); -} /*** Heap Snapshot Analyses ***********************************************************************/ @@ -407,6 +472,10 @@ HeapSnapshot::TakeCensus(JSContext* cx, JS::HandleObject options, } } +#undef GET_STRING_OR_REF_WITH_PROP_NAMES +#undef GET_STRING_OR_REF + + /*** Saving Heap Snapshots ************************************************************************/ // If we are only taking a snapshot of the heap affected by the given set of @@ -549,17 +618,225 @@ EstablishBoundaries(JSContext* cx, } +// A variant covering all the various two-byte strings that we can get from the +// ubi::Node API. +class TwoByteString : public Variant +{ + using Base = Variant; + + struct AsTwoByteStringMatcher + { + using ReturnType = TwoByteString; + + TwoByteString match(JSAtom* atom) { + return TwoByteString(atom); + } + + TwoByteString match(const char16_t* chars) { + return TwoByteString(chars); + } + }; + + struct IsNonNullMatcher + { + using ReturnType = bool; + + template + bool match(const T& t) { return t != nullptr; } + }; + + struct LengthMatcher + { + using ReturnType = size_t; + + size_t match(JSAtom* atom) { + MOZ_ASSERT(atom); + JS::ubi::AtomOrTwoByteChars s(atom); + return s.length(); + } + + size_t match(const char16_t* chars) { + MOZ_ASSERT(chars); + return NS_strlen(chars); + } + + size_t match(const JS::ubi::EdgeName& ptr) { + MOZ_ASSERT(ptr); + return NS_strlen(ptr.get()); + } + }; + + struct CopyToBufferMatcher + { + using ReturnType = size_t; + + RangedPtr destination; + size_t maxLength; + + CopyToBufferMatcher(RangedPtr destination, size_t maxLength) + : destination(destination) + , maxLength(maxLength) + { } + + size_t match(JS::ubi::EdgeName& ptr) { + return ptr ? match(ptr.get()) : 0; + } + + size_t match(JSAtom* atom) { + MOZ_ASSERT(atom); + JS::ubi::AtomOrTwoByteChars s(atom); + return s.copyToBuffer(destination, maxLength); + } + + size_t match(const char16_t* chars) { + MOZ_ASSERT(chars); + JS::ubi::AtomOrTwoByteChars s(chars); + return s.copyToBuffer(destination, maxLength); + } + }; + +public: + template + MOZ_IMPLICIT TwoByteString(T&& rhs) : Base(Forward(rhs)) { } + + template + TwoByteString& operator=(T&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move disallowed"); + this->~TwoByteString(); + new (this) TwoByteString(Forward(rhs)); + return *this; + } + + TwoByteString(const TwoByteString&) = delete; + TwoByteString& operator=(const TwoByteString&) = delete; + + // Rewrap the inner value of a JS::ubi::AtomOrTwoByteChars as a TwoByteString. + static TwoByteString from(JS::ubi::AtomOrTwoByteChars&& s) { + AsTwoByteStringMatcher m; + return s.match(m); + } + + // Returns true if the given TwoByteString is non-null, false otherwise. + bool isNonNull() const { + IsNonNullMatcher m; + return match(m); + } + + // Return the length of the string, 0 if it is null. + size_t length() const { + LengthMatcher m; + return match(m); + } + + // Copy the contents of a TwoByteString into the provided buffer. The buffer + // is NOT null terminated. The number of characters written is returned. + size_t copyToBuffer(RangedPtr destination, size_t maxLength) { + CopyToBufferMatcher m(destination, maxLength); + return match(m); + } + + struct HashPolicy; +}; + +// A hashing policy for TwoByteString. +// +// Atoms are pointer hashed and use pointer equality, which means that we +// tolerate some duplication across atoms and the other two types of two-byte +// strings. In practice, we expect the amount of this duplication to be very low +// because each type is generally a different semantic thing in addition to +// having a slightly different representation. For example, the set of edge +// names and the set stack frames' source names naturally tend not to overlap +// very much if at all. +struct TwoByteString::HashPolicy { + using Lookup = TwoByteString; + + struct HashingMatcher { + using ReturnType = js::HashNumber; + + js::HashNumber match(const JSAtom* atom) { + return js::DefaultHasher::hash(atom); + } + + js::HashNumber match(const char16_t* chars) { + MOZ_ASSERT(chars); + auto length = NS_strlen(chars); + return HashString(chars, length); + } + + js::HashNumber match(const JS::ubi::EdgeName& ptr) { + MOZ_ASSERT(ptr); + return match(ptr.get()); + } + }; + + static js::HashNumber hash(const Lookup& l) { + HashingMatcher hasher; + return l.match(hasher); + } + + struct EqualityMatcher { + using ReturnType = bool; + const TwoByteString& rhs; + explicit EqualityMatcher(const TwoByteString& rhs) : rhs(rhs) { } + + bool match(const JSAtom* atom) { + return rhs.is() && rhs.as() == atom; + } + + bool match(const char16_t* chars) { + MOZ_ASSERT(chars); + + const char16_t* rhsChars = nullptr; + if (rhs.is()) + rhsChars = rhs.as(); + else if (rhs.is()) + rhsChars = rhs.as().get(); + else + return false; + MOZ_ASSERT(rhsChars); + + auto length = NS_strlen(chars); + if (NS_strlen(rhsChars) != length) + return false; + + return memcmp(chars, rhsChars, length * sizeof(char16_t)) == 0; + } + + bool match(const JS::ubi::EdgeName& ptr) { + MOZ_ASSERT(ptr); + return match(ptr.get()); + } + }; + + static bool match(const TwoByteString& k, const Lookup& l) { + EqualityMatcher eq(l); + return k.match(eq); + } + + static void rekey(TwoByteString& k, TwoByteString&& newKey) { + k = Move(newKey); + } +}; + // A `CoreDumpWriter` that serializes nodes to protobufs and writes them to the // given `ZeroCopyOutputStream`. class MOZ_STACK_CLASS StreamWriter : public CoreDumpWriter { - using Set = js::HashSet; + using FrameSet = js::HashSet; + using TwoByteStringMap = js::HashMap; + using OneByteStringMap = js::HashMap; - JSContext* cx; - bool wantNames; + JSContext* cx; + bool wantNames; // The set of |JS::ubi::StackFrame::identifier()|s that have already been // serialized and written to the core dump. - Set framesAlreadySerialized; + FrameSet framesAlreadySerialized; + // The set of two-byte strings that have already been serialized and written + // to the core dump. + TwoByteStringMap twoByteStringsAlreadySerialized; + // The set of one-byte strings that have already been serialized and written + // to the core dump. + OneByteStringMap oneByteStringsAlreadySerialized; ::google::protobuf::io::ZeroCopyOutputStream& stream; @@ -573,7 +850,64 @@ class MOZ_STACK_CLASS StreamWriter : public CoreDumpWriter return !codedStream.HadError(); } + // Attach the full two-byte string or a reference to a two-byte string that + // has already been serialized to a protobuf message. + template + bool attachTwoByteString(TwoByteString& string, SetStringFunction setString, + SetRefFunction setRef) { + auto ptr = twoByteStringsAlreadySerialized.lookupForAdd(string); + if (ptr) { + setRef(ptr->value()); + return true; + } + + auto length = string.length(); + auto stringData = MakeUnique(length * sizeof(char16_t), '\0'); + if (!stringData) + return false; + + auto buf = const_cast(reinterpret_cast(stringData->data())); + string.copyToBuffer(RangedPtr(buf, length), length); + + uint64_t ref = twoByteStringsAlreadySerialized.count(); + if (!twoByteStringsAlreadySerialized.add(ptr, Move(string), ref)) + return false; + + setString(stringData.release()); + return true; + } + + // Attach the full one-byte string or a reference to a one-byte string that + // has already been serialized to a protobuf message. + template + bool attachOneByteString(const char* string, SetStringFunction setString, + SetRefFunction setRef) { + auto ptr = oneByteStringsAlreadySerialized.lookupForAdd(string); + if (ptr) { + setRef(ptr->value()); + return true; + } + + auto length = strlen(string); + auto stringData = MakeUnique(string, length); + if (!stringData) + return false; + + uint64_t ref = oneByteStringsAlreadySerialized.count(); + if (!oneByteStringsAlreadySerialized.add(ptr, string, ref)) + return false; + + setString(stringData.release()); + return true; + } + protobuf::StackFrame* getProtobufStackFrame(JS::ubi::StackFrame& frame) { + // 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"); @@ -598,24 +932,22 @@ class MOZ_STACK_CLASS StreamWriter : public CoreDumpWriter data->set_issystem(frame.isSystem()); data->set_isselfhosted(frame.isSelfHosted()); - auto source = MakeUnique(frame.sourceLength() * sizeof(char16_t), - '\0'); - if (!source) + 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 buf = const_cast(reinterpret_cast(source->data())); - frame.source(RangedPtr(buf, frame.sourceLength()), - frame.sourceLength()); - data->set_allocated_source(source.release()); + } - auto nameLength = frame.functionDisplayNameLength(); - if (nameLength > 0) { - auto functionDisplayName = MakeUnique(nameLength * sizeof(char16_t), - '\0'); - if (!functionDisplayName) + 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 buf = const_cast(reinterpret_cast(functionDisplayName->data())); - frame.functionDisplayName(RangedPtr(buf, nameLength), nameLength); - data->set_allocated_functiondisplayname(functionDisplayName.release()); + } } auto parent = frame.parent(); @@ -641,14 +973,20 @@ public: : cx(cx) , wantNames(wantNames) , framesAlreadySerialized(cx) + , twoByteStringsAlreadySerialized(cx) + , oneByteStringsAlreadySerialized(cx) , stream(stream) { } - bool init() { return framesAlreadySerialized.init(); } + bool init() { + return framesAlreadySerialized.init() && + twoByteStringsAlreadySerialized.init() && + oneByteStringsAlreadySerialized.init(); + } ~StreamWriter() override { } - virtual bool writeMetadata(uint64_t timestamp) override { + virtual bool writeMetadata(uint64_t timestamp) final { protobuf::Metadata metadata; metadata.set_timestamp(timestamp); return writeMessage(metadata); @@ -656,20 +994,55 @@ public: virtual bool writeNode(const JS::ubi::Node& ubiNode, EdgePolicy includeEdges) final { + // NB: de-duplicated string properties must be written in the same order + // here as they are read in `HeapSnapshot::saveNode` or else indices in + // references to already serialized strings will be off. + protobuf::Node protobufNode; protobufNode.set_id(ubiNode.identifier()); protobufNode.set_coarsetype(JS::ubi::CoarseTypeToUint32(ubiNode.coarseType())); - const char16_t* typeName = ubiNode.typeName(); - size_t length = NS_strlen(typeName) * sizeof(char16_t); - protobufNode.set_typename_(typeName, length); + auto typeName = TwoByteString(ubiNode.typeName()); + if (NS_WARN_IF(!attachTwoByteString(typeName, + [&] (std::string* name) { protobufNode.set_allocated_typename_(name); }, + [&] (uint64_t ref) { protobufNode.set_typenameref(ref); }))) + { + return false; + } JSRuntime* rt = JS_GetRuntime(cx); mozilla::MallocSizeOf mallocSizeOf = dbg::GetDebuggerMallocSizeOf(rt); MOZ_ASSERT(mallocSizeOf); protobufNode.set_size(ubiNode.size(mallocSizeOf)); + if (includeEdges) { + auto edges = ubiNode.edges(JS_GetRuntime(cx), wantNames); + if (NS_WARN_IF(!edges)) + return false; + + for ( ; !edges->empty(); edges->popFront()) { + ubi::Edge& ubiEdge = edges->front(); + + protobuf::Edge* protobufEdge = protobufNode.add_edges(); + if (NS_WARN_IF(!protobufEdge)) { + return false; + } + + protobufEdge->set_referent(ubiEdge.referent.identifier()); + + if (wantNames && ubiEdge.name) { + TwoByteString edgeName(Move(ubiEdge.name)); + if (NS_WARN_IF(!attachTwoByteString(edgeName, + [&] (std::string* name) { protobufEdge->set_allocated_name(name); }, + [&] (uint64_t ref) { protobufEdge->set_nameref(ref); }))) + { + return false; + } + } + } + } + if (ubiNode.hasAllocationStack()) { auto ubiStackFrame = ubiNode.allocationStack(); auto protoStackFrame = getProtobufStackFrame(ubiStackFrame); @@ -679,29 +1052,11 @@ public: } if (auto className = ubiNode.jsObjectClassName()) { - size_t length = strlen(className); - protobufNode.set_jsobjectclassname(className, length); - } - - if (includeEdges) { - auto edges = ubiNode.edges(JS_GetRuntime(cx), wantNames); - if (NS_WARN_IF(!edges)) + if (NS_WARN_IF(!attachOneByteString(className, + [&] (std::string* name) { protobufNode.set_allocated_jsobjectclassname(name); }, + [&] (uint64_t ref) { protobufNode.set_jsobjectclassnameref(ref); }))) + { return false; - - for ( ; !edges->empty(); edges->popFront()) { - const ubi::Edge& ubiEdge = edges->front(); - - protobuf::Edge* protobufEdge = protobufNode.add_edges(); - if (NS_WARN_IF(!protobufEdge)) { - return false; - } - - protobufEdge->set_referent(ubiEdge.referent.identifier()); - - if (wantNames && ubiEdge.name) { - size_t length = NS_strlen(ubiEdge.name) * sizeof(char16_t); - protobufEdge->set_name(ubiEdge.name, length); - } } } diff --git a/devtools/shared/heapsnapshot/HeapSnapshot.h b/devtools/shared/heapsnapshot/HeapSnapshot.h index 8c4de6fb2a2..b4c9593cd71 100644 --- a/devtools/shared/heapsnapshot/HeapSnapshot.h +++ b/devtools/shared/heapsnapshot/HeapSnapshot.h @@ -34,36 +34,14 @@ struct NSFreePolicy { } }; -using UniqueString = UniquePtr; - -struct UniqueStringHashPolicy { - struct Lookup { - const char16_t* str; - size_t length; - - Lookup(const char16_t* str, size_t length) - : str(str) - , length(length) - { } - }; - - static js::HashNumber hash(const Lookup& lookup) { - MOZ_ASSERT(lookup.str); - return HashString(lookup.str, lookup.length); - } - - static bool match(const UniqueString& existing, const Lookup& lookup) { - MOZ_ASSERT(lookup.str); - if (NS_strlen(existing.get()) != lookup.length) - return false; - return memcmp(existing.get(), lookup.str, lookup.length * sizeof(char16_t)) == 0; - } -}; +using UniqueTwoByteString = UniquePtr; +using UniqueOneByteString = UniquePtr; class HeapSnapshot final : public nsISupports , public nsWrapperCache { friend struct DeserializedNode; + friend struct DeserializedEdge; friend struct DeserializedStackFrame; friend struct JS::ubi::Concrete; @@ -72,7 +50,6 @@ class HeapSnapshot final : public nsISupports , rootId(0) , nodes(cx) , frames(cx) - , strings(cx) , mParent(aParent) { MOZ_ASSERT(aParent); @@ -108,14 +85,15 @@ class HeapSnapshot final : public nsISupports DeserializedStackFrame::HashPolicy>; FrameSet frames; - // Core dump files have many duplicate strings: type names are repeated for - // each node, and although in theory edge names are highly customizable for - // specific edges, in practice they are also highly duplicated. Rather than - // make each Deserialized{Node,Edge} malloc their own copy of their edge and - // type names, we de-duplicate the strings here and Deserialized{Node,Edge} - // get borrowed pointers into this set. - using UniqueStringSet = js::HashSet; - UniqueStringSet strings; + Vector internedTwoByteStrings; + Vector internedOneByteStrings; + + using StringOrRef = Variant; + + template + const CharT* getOrInternString(InternedStringSet& internedStrings, + Maybe& maybeStrOrRef); protected: nsCOMPtr mParent; diff --git a/devtools/shared/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp b/devtools/shared/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp index c098287cf16..f984f0e8927 100644 --- a/devtools/shared/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp +++ b/devtools/shared/heapsnapshot/tests/gtest/DeserializedNodeUbiNodes.cpp @@ -43,9 +43,8 @@ DEF_TEST(DeserializedNodeUbiNodes, { NodeId id = uint64_t(1) << 33; uint64_t size = uint64_t(1) << 60; MockDeserializedNode mocked(id, typeName, size); - mocked.jsObjectClassName = mozilla::UniquePtr(strdup(className)); - ASSERT_TRUE(!!mocked.jsObjectClassName); mocked.coarseType = JS::ubi::CoarseType::Script; + mocked.jsObjectClassName = className; DeserializedNode& deserialized = mocked; JS::ubi::Node ubi(&deserialized); @@ -57,15 +56,14 @@ DEF_TEST(DeserializedNodeUbiNodes, { EXPECT_EQ(JS::ubi::CoarseType::Script, ubi.coarseType()); EXPECT_EQ(id, ubi.identifier()); EXPECT_FALSE(ubi.isLive()); - EXPECT_EQ(strcmp(ubi.jsObjectClassName(), className), 0); + EXPECT_EQ(ubi.jsObjectClassName(), className); // Test the ubi::Node's edges. UniquePtr referent1(new MockDeserializedNode(1, nullptr, 10)); - DeserializedEdge edge1; - edge1.referent = referent1->id; + DeserializedEdge edge1(referent1->id); mocked.addEdge(Move(edge1)); EXPECT_CALL(mocked, getEdgeReferent(Field(&DeserializedEdge::referent, @@ -76,8 +74,7 @@ DEF_TEST(DeserializedNodeUbiNodes, { UniquePtr referent2(new MockDeserializedNode(2, nullptr, 20)); - DeserializedEdge edge2; - edge2.referent = referent2->id; + DeserializedEdge edge2(referent2->id); mocked.addEdge(Move(edge2)); EXPECT_CALL(mocked, getEdgeReferent(Field(&DeserializedEdge::referent, @@ -88,8 +85,7 @@ DEF_TEST(DeserializedNodeUbiNodes, { UniquePtr referent3(new MockDeserializedNode(3, nullptr, 30)); - DeserializedEdge edge3; - edge3.referent = referent3->id; + DeserializedEdge edge3(referent3->id); mocked.addEdge(Move(edge3)); EXPECT_CALL(mocked, getEdgeReferent(Field(&DeserializedEdge::referent, @@ -97,5 +93,5 @@ DEF_TEST(DeserializedNodeUbiNodes, { .Times(1) .WillOnce(Return(JS::ubi::Node(referent3.get()))); - ubi.edges(JS_GetRuntime(cx)); + ubi.edges(rt); }); diff --git a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h b/devtools/shared/heapsnapshot/tests/gtest/DevTools.h index 20b272064e6..1146833f7c9 100644 --- a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h +++ b/devtools/shared/heapsnapshot/tests/gtest/DevTools.h @@ -182,7 +182,7 @@ class Concrete : public Base return concreteTypeName; } - UniquePtr edges(JSRuntime* rt, bool wantNames) const override { + UniquePtr edges(JSRuntime*, bool) const override { return UniquePtr(js_new(get().edges)); } @@ -270,6 +270,14 @@ MATCHER_P(UTF16StrEq, str, "") { return NS_strcmp(arg, str) == 0; } +MATCHER_P(UniqueUTF16StrEq, str, "") { + return NS_strcmp(arg.get(), str) == 0; +} + +MATCHER(UniqueIsNull, "") { + return arg.get() == nullptr; +} + } // namespace testing diff --git a/devtools/shared/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp b/devtools/shared/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp index 234463618a5..5b22342447c 100644 --- a/devtools/shared/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp +++ b/devtools/shared/heapsnapshot/tests/gtest/SerializesEdgeNames.cpp @@ -30,11 +30,11 @@ DEF_TEST(SerializesEdgeNames, { writer, writeNode(AllOf(EdgesLength(rt, 3), Edge(rt, 0, Field(&JS::ubi::Edge::name, - UTF16StrEq(edgeName))), + UniqueUTF16StrEq(edgeName))), Edge(rt, 1, Field(&JS::ubi::Edge::name, - UTF16StrEq(emptyStr))), + UniqueUTF16StrEq(emptyStr))), Edge(rt, 2, Field(&JS::ubi::Edge::name, - IsNull()))), + UniqueIsNull()))), _) ) .Times(1) diff --git a/devtools/shared/heapsnapshot/tests/gtest/UniqueStringHashPolicy.cpp b/devtools/shared/heapsnapshot/tests/gtest/UniqueStringHashPolicy.cpp deleted file mode 100644 index 3c210d5e82f..00000000000 --- a/devtools/shared/heapsnapshot/tests/gtest/UniqueStringHashPolicy.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Bug 1171226 - Test UniqueStringHashPolicy::match - -#include "DevTools.h" -#include "mozilla/devtools/HeapSnapshot.h" - -using mozilla::devtools::UniqueString; -using mozilla::devtools::UniqueStringHashPolicy; - -DEF_TEST(UniqueStringHashPolicy_match, { - // 1 - // 01234567890123456 - UniqueString str1(NS_strdup(MOZ_UTF16("some long string and a tail"))); - ASSERT_TRUE(!!str1); - - UniqueStringHashPolicy::Lookup lookup(MOZ_UTF16("some long string with same prefix"), 16); - - // str1 is longer than Lookup.length, so they shouldn't match, even though - // the first 16 chars are equal! - ASSERT_FALSE(UniqueStringHashPolicy::match(str1, lookup)); - }); diff --git a/devtools/shared/heapsnapshot/tests/gtest/moz.build b/devtools/shared/heapsnapshot/tests/gtest/moz.build index 14f7fa6b104..fb10b1419ec 100644 --- a/devtools/shared/heapsnapshot/tests/gtest/moz.build +++ b/devtools/shared/heapsnapshot/tests/gtest/moz.build @@ -18,7 +18,6 @@ UNIFIED_SOURCES = [ 'SerializesEdgeNames.cpp', 'SerializesEverythingInHeapGraphOnce.cpp', 'SerializesTypeNames.cpp', - 'UniqueStringHashPolicy.cpp', ] # THE MOCK_METHOD2 macro from gtest triggers this clang warning and it's hard diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h index 74a0bfb46c7..9822ac5f98a 100644 --- a/js/public/UbiNode.h +++ b/js/public/UbiNode.h @@ -25,6 +25,7 @@ #include "js/RootingAPI.h" #include "js/TracingAPI.h" #include "js/TypeDecls.h" +#include "js/Value.h" #include "js/Vector.h" // JS::ubi::Node @@ -186,6 +187,7 @@ class DefaultDelete : public JS::DeletePolicy; +class AtomOrTwoByteChars : public Variant { + using Base = Variant; + + public: + template + MOZ_IMPLICIT AtomOrTwoByteChars(T&& rhs) : Base(Forward(rhs)) { } + + template + AtomOrTwoByteChars& operator=(T&& rhs) { + MOZ_ASSERT(this != &rhs, "self-move disallowed"); + this->~AtomOrTwoByteChars(); + new (this) AtomOrTwoByteChars(Forward(rhs)); + return *this; + } + + // Return the length of the given AtomOrTwoByteChars string. + size_t length(); + + // Copy the given AtomOrTwoByteChars string into the destination buffer, + // inflating if necessary. Does NOT null terminate. Returns the number of + // characters written to destination. + size_t copyToBuffer(RangedPtr destination, size_t length); +}; // The base class implemented by each ConcreteStackFrame type. Subclasses // must not add data members to this class. @@ -786,23 +810,25 @@ class Node { /*** Edge and EdgeRange ***************************************************************************/ +using EdgeName = UniquePtr; + // An outgoing edge to a referent node. class Edge { public: Edge() : name(nullptr), referent() { } // Construct an initialized Edge, taking ownership of |name|. - Edge(char16_t* name, const Node& referent) { - this->name = name; - this->referent = referent; - } + Edge(char16_t* name, const Node& referent) + : name(name) + , referent(referent) + { } // Move construction and assignment. - Edge(Edge&& rhs) { - name = rhs.name; - referent = rhs.referent; - rhs.name = nullptr; - } + Edge(Edge&& rhs) + : name(mozilla::Move(rhs.name)) + , referent(rhs.referent) + { } + Edge& operator=(Edge&& rhs) { MOZ_ASSERT(&rhs != this); this->~Edge(); @@ -810,10 +836,6 @@ class Edge { return *this; } - ~Edge() { - js_free(const_cast(name)); - } - Edge(const Edge&) = delete; Edge& operator=(const Edge&) = delete; @@ -826,7 +848,7 @@ class Edge { // (In real life we'll want a better representation for names, to avoid // creating tons of strings when the names follow a pattern; and we'll need // to think about lifetimes carefully to ensure traversal stays cheap.) - const char16_t* name; + EdgeName name; // This edge's referent. Node referent; diff --git a/js/public/Utility.h b/js/public/Utility.h index 5aaafca6382..3279b0c23f4 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -128,7 +128,7 @@ extern JS_PUBLIC_DATA(uint32_t) targetThread; static inline bool OOMThreadCheck() { - return (!js::oom::targetThread + return (!js::oom::targetThread || js::oom::targetThread == js::oom::GetThreadType()); } @@ -435,15 +435,15 @@ namespace JS { template struct DeletePolicy { - void operator()(T* ptr) { - js_delete(ptr); + void operator()(const T* ptr) { + js_delete(const_cast(ptr)); } }; struct FreePolicy { - void operator()(void* ptr) { - js_free(ptr); + void operator()(const void* ptr) { + js_free(const_cast(ptr)); } }; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 6281d620ae5..7312fe332c5 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -2141,7 +2141,7 @@ struct FindPathHandler { // Record how we reached this node. This is the last edge on a // shortest path to this node. - EdgeName edgeName = DuplicateString(cx, edge.name); + EdgeName edgeName = DuplicateString(cx, edge.name.get()); if (!edgeName) return false; *backEdge = mozilla::Move(BackEdge(origin, Move(edgeName))); diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp index f1badf95771..3e682a7a33d 100644 --- a/js/src/vm/UbiNode.cpp +++ b/js/src/vm/UbiNode.cpp @@ -52,16 +52,6 @@ using JS::ubi::StackFrame; using JS::ubi::TracerConcrete; using JS::ubi::TracerConcreteWithCompartment; -template -static size_t -copyToBuffer(const CharT* src, RangedPtr dest, size_t length) -{ - size_t i = 0; - for ( ; i < length; i++) - dest[i] = src[i]; - return i; -} - struct CopyToBufferMatcher { using ReturnType = size_t; @@ -74,6 +64,16 @@ struct CopyToBufferMatcher , maxLength(maxLength) { } + template + static size_t + copyToBufferHelper(const CharT* src, RangedPtr dest, size_t length) + { + size_t i = 0; + for ( ; i < length; i++) + dest[i] = src[i]; + return i; + } + size_t match(JSAtom* atom) { @@ -83,8 +83,8 @@ struct CopyToBufferMatcher size_t length = std::min(atom->length(), maxLength); JS::AutoCheckCannotGC noGC; return atom->hasTwoByteChars() - ? copyToBuffer(atom->twoByteChars(noGC), destination, length) - : copyToBuffer(atom->latin1Chars(noGC), destination, length); + ? copyToBufferHelper(atom->twoByteChars(noGC), destination, length) + : copyToBufferHelper(atom->latin1Chars(noGC), destination, length); } size_t @@ -94,22 +94,15 @@ struct CopyToBufferMatcher return 0; size_t length = std::min(js_strlen(chars), maxLength); - return copyToBuffer(chars, destination, length); + return copyToBufferHelper(chars, destination, length); } }; size_t -StackFrame::source(RangedPtr destination, size_t length) const +JS::ubi::AtomOrTwoByteChars::copyToBuffer(RangedPtr destination, size_t length) { CopyToBufferMatcher m(destination, length); - return source().match(m); -} - -size_t -StackFrame::functionDisplayName(RangedPtr destination, size_t length) const -{ - CopyToBufferMatcher m(destination, length); - return functionDisplayName().match(m); + return match(m); } struct LengthMatcher @@ -130,17 +123,36 @@ struct LengthMatcher }; size_t -StackFrame::sourceLength() +JS::ubi::AtomOrTwoByteChars::length() { LengthMatcher m; - return source().match(m); + return match(m); +} + +size_t +StackFrame::source(RangedPtr destination, size_t length) const +{ + auto s = source(); + return s.copyToBuffer(destination, length); +} + +size_t +StackFrame::functionDisplayName(RangedPtr destination, size_t length) const +{ + auto name = functionDisplayName(); + return name.copyToBuffer(destination, length); +} + +size_t +StackFrame::sourceLength() +{ + return source().length(); } size_t StackFrame::functionDisplayNameLength() { - LengthMatcher m; - return functionDisplayName().match(m); + return functionDisplayName().length(); } // All operations on null ubi::Nodes crash. diff --git a/xpcom/glue/nsCRTGlue.cpp b/xpcom/glue/nsCRTGlue.cpp index 1bc4377a3f1..a050e15ea75 100644 --- a/xpcom/glue/nsCRTGlue.cpp +++ b/xpcom/glue/nsCRTGlue.cpp @@ -128,17 +128,21 @@ NS_strdup(const char16_t* aString) return NS_strndup(aString, len); } -char16_t* -NS_strndup(const char16_t* aString, uint32_t aLen) +template +CharT* +NS_strndup(const CharT* aString, uint32_t aLen) { - char16_t* newBuf = (char16_t*)NS_Alloc((aLen + 1) * sizeof(char16_t)); + auto newBuf = (CharT*)NS_Alloc((aLen + 1) * sizeof(CharT)); if (newBuf) { - memcpy(newBuf, aString, aLen * sizeof(char16_t)); + memcpy(newBuf, aString, aLen * sizeof(CharT)); newBuf[aLen] = '\0'; } return newBuf; } +template char16_t* NS_strndup(const char16_t* aString, uint32_t aLen); +template char* NS_strndup(const char* aString, uint32_t aLen); + char* NS_strdup(const char* aString) { diff --git a/xpcom/glue/nsCRTGlue.h b/xpcom/glue/nsCRTGlue.h index 4e59c137c45..8caa1ae2727 100644 --- a/xpcom/glue/nsCRTGlue.h +++ b/xpcom/glue/nsCRTGlue.h @@ -63,10 +63,14 @@ char16_t* NS_strdup(const char16_t* aString); char* NS_strdup(const char* aString); /** - * strndup for char16_t strings... this function will ensure that the - * new string is null-terminated. Uses the NS_Alloc allocator. + * strndup for char16_t or char strings (normal strndup is not available on + * windows). This function will ensure that the new string is + * null-terminated. Uses the NS_Alloc allocator. + * + * CharT may be either char16_t or char. */ -char16_t* NS_strndup(const char16_t* aString, uint32_t aLen); +template +CharT* NS_strndup(const CharT* aString, uint32_t aLen); // The following case-conversion methods only deal in the ascii repertoire // A-Z and a-z