From cd48a9ec00fa8926ace970d2eb5b84f1da19e4bb Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 17 Nov 2020 23:03:22 +0100 Subject: [PATCH 1/9] Get hints from the CollectionProxy to create the pair TClass --- core/meta/inc/TClass.h | 2 ++ core/meta/inc/TVirtualStreamerInfo.h | 4 ++-- core/meta/src/TClass.cxx | 7 ++++++- io/io/inc/TStreamerInfo.h | 4 ++-- io/io/src/TEmulatedCollectionProxy.cxx | 2 +- io/io/src/TGenCollectionProxy.cxx | 24 ++++++++++++++++++++++-- io/io/src/TStreamerInfo.cxx | 10 +++++++--- 7 files changed, 42 insertions(+), 11 deletions(-) diff --git a/core/meta/inc/TClass.h b/core/meta/inc/TClass.h index 99d32417ebf1e..9622cec15a7c8 100644 --- a/core/meta/inc/TClass.h +++ b/core/meta/inc/TClass.h @@ -84,6 +84,7 @@ friend void ROOT::ResetClassVersion(TClass*, const char*, Short_t); friend class ROOT::TGenericClassInfo; friend class TProtoClass; friend class ROOT::Internal::TCheckHashRecursiveRemoveConsistency; +friend class TStreamerInfo; public: // TClass status bits @@ -535,6 +536,7 @@ friend class ROOT::Internal::TCheckHashRecursiveRemoveConsistency; static void RemoveClass(TClass *cl); static void RemoveClassDeclId(TDictionary::DeclId_t id); static TClass *GetClass(const char *name, Bool_t load = kTRUE, Bool_t silent = kFALSE); + static TClass *GetClass(const char *name, Bool_t load, Bool_t silent, size_t hint_pair_offset, size_t hint_pair_size); static TClass *GetClass(const std::type_info &typeinfo, Bool_t load = kTRUE, Bool_t silent = kFALSE); static TClass *GetClass(ClassInfo_t *info, Bool_t load = kTRUE, Bool_t silent = kFALSE); template diff --git a/core/meta/inc/TVirtualStreamerInfo.h b/core/meta/inc/TVirtualStreamerInfo.h index 82113e243cb01..a7e04994ba662 100644 --- a/core/meta/inc/TVirtualStreamerInfo.h +++ b/core/meta/inc/TVirtualStreamerInfo.h @@ -185,8 +185,8 @@ class TVirtualStreamerInfo : public TNamed { // provokes the creation of the corresponding TClass. This relies on the dictionary for // std::pair to already exist (or the interpreter information being available) // as it is used as a template. - virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &pairclassname, bool silent) = 0; - virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &firstname, const std::string &secondname, bool silent) = 0; + virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &pairclassname, bool silent, size_t hint_pair_offset, size_t hint_pair_size) = 0; + virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &firstname, const std::string &secondname, bool silent, size_t hint_pair_offset, size_t hint_pair_size) = 0; virtual TVirtualCollectionProxy *GenEmulatedProxy(const char* class_name, Bool_t silent) = 0; virtual TClassStreamer *GenEmulatedClassStreamer(const char* class_name, Bool_t silent) = 0; diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index 81da4bafbbc02..fad93d2b96856 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -2927,6 +2927,11 @@ TVirtualIsAProxy* TClass::GetIsAProxy() const /// Returns 0 in case class is not found. TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent) +{ + return TClass::GetClass(name, load, silent, 0, 0); +} + +TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent, size_t hint_pair_offset, size_t hint_pair_size) { if (!name || !name[0]) return 0; @@ -3087,7 +3092,7 @@ TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent) if (cl) return cl; if (ispair) { - auto pairinfo = TVirtualStreamerInfo::Factory()->GenerateInfoForPair(normalizedName, silent); + auto pairinfo = TVirtualStreamerInfo::Factory()->GenerateInfoForPair(normalizedName, silent, hint_pair_offset, hint_pair_size); //return pairinfo ? pairinfo->GetClass() : nullptr; if (pairinfo) return pairinfo->GetClass(); diff --git a/io/io/inc/TStreamerInfo.h b/io/io/inc/TStreamerInfo.h index a9fccfde83ae8..fc76e461ee50e 100644 --- a/io/io/inc/TStreamerInfo.h +++ b/io/io/inc/TStreamerInfo.h @@ -283,8 +283,8 @@ class TStreamerInfo : public TVirtualStreamerInfo { // provokes the creation of the corresponding TClass. This relies on the dictionary for // std::pair to already exist (or the interpreter information being available) // as it is used as a template. - virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &pairclassname, bool silent); - virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &firstname, const std::string &secondname, bool silent); + virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &pairclassname, bool silent, size_t hint_pair_offset, size_t hint_pair_size); + virtual TVirtualStreamerInfo *GenerateInfoForPair(const std::string &firstname, const std::string &secondname, bool silent, size_t hint_pair_offset, size_t hint_pair_size); virtual TVirtualCollectionProxy *GenEmulatedProxy(const char* class_name, Bool_t silent); virtual TClassStreamer *GenEmulatedClassStreamer(const char* class_name, Bool_t silent); diff --git a/io/io/src/TEmulatedCollectionProxy.cxx b/io/io/src/TEmulatedCollectionProxy.cxx index add1a99d9cecd..bd79155363aa8 100644 --- a/io/io/src/TEmulatedCollectionProxy.cxx +++ b/io/io/src/TEmulatedCollectionProxy.cxx @@ -183,7 +183,7 @@ TGenCollectionProxy *TEmulatedCollectionProxy::InitializeEx(Bool_t silent) if (0==TClass::GetClass(nam.c_str(), kTRUE, silent)) { // We need to emulate the pair - TVirtualStreamerInfo::Factory()->GenerateInfoForPair(inside[1],inside[2], silent); + TVirtualStreamerInfo::Factory()->GenerateInfoForPair(inside[1],inside[2], silent, 0, 0); } } fValue = new Value(nam,silent); diff --git a/io/io/src/TGenCollectionProxy.cxx b/io/io/src/TGenCollectionProxy.cxx index 3b4e02ba6a43d..bab4ddcf78e81 100644 --- a/io/io/src/TGenCollectionProxy.cxx +++ b/io/io/src/TGenCollectionProxy.cxx @@ -883,9 +883,29 @@ TGenCollectionProxy *TGenCollectionProxy::InitializeEx(Bool_t silent) { TInterpreter::SuspendAutoParsing autoParseRaii(gCling); - if (0==TClass::GetClass(nam.c_str())) { + if (0==TClass::GetClass(nam.c_str(), true, false, fValOffset, fValDiff)) { // We need to emulate the pair - TVirtualStreamerInfo::Factory()->GenerateInfoForPair(inside[1],inside[2], silent); + TVirtualStreamerInfo::Factory()->GenerateInfoForPair(inside[1], inside[2], silent, fValOffset, fValDiff); + } else { + TClass *paircl = TClass::GetClass(nam.c_str()); + if (paircl->GetClassSize() != fValDiff) { + if (paircl->GetState() >= TClass::kInterpreted) + Fatal("InitializeEx", + "The %s for %s reports a class size that is inconsistent with the one registered " + "through the CollectionProxy for %s: %d vs %d\n", + paircl->IsLoaded() ? "dictionary" : "interpreter information for", nam.c_str(), + cl->GetName(), (int)paircl->GetClassSize(), (int)fValDiff); + else { + gROOT->GetListOfClasses()->Remove(paircl); + TClass *newpaircl = TClass::GetClass(nam.c_str(), true, false, fValOffset, fValDiff); + if (newpaircl == paircl || newpaircl->GetClassSize() != fValDiff) + Fatal("InitializeEx", + "The TClass creation for %s did not get the right size: %d instead of%d\n", + nam.c_str(), (int)paircl->GetClassSize(), (int)fValDiff); + paircl->ReplaceWith(newpaircl); + delete paircl; + } + } } } newfValue = R__CreateValue(nam, silent); diff --git a/io/io/src/TStreamerInfo.cxx b/io/io/src/TStreamerInfo.cxx index 2648482db2161..961450dd9d13b 100644 --- a/io/io/src/TStreamerInfo.cxx +++ b/io/io/src/TStreamerInfo.cxx @@ -5650,7 +5650,7 @@ static TStreamerElement* R__CreateEmulatedElement(const char *dmName, const std: // provoke the creation of the corresponding TClass. This relies on the dictionary for // std::pair to already exist (or the interpreter information being available) // as it is used as a template. -TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &firstname, const std::string &secondname, bool silent) +TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &firstname, const std::string &secondname, bool silent, size_t hint_pair_offset, size_t hint_pair_size) { // Generate a TStreamerInfo for a std::pair // This TStreamerInfo is then used as if it was read from a file to generate @@ -5675,6 +5675,8 @@ TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &firs delete i; return 0; } + if (hint_pair_offset) + size = hint_pair_offset; TStreamerElement *second = R__CreateEmulatedElement("second", secondname, size, silent); if (second) { i->GetElements()->Add( second ); @@ -5688,10 +5690,12 @@ TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &firs i->BuildCheck(nullptr, kFALSE); // Skipping the loading part (it would leads to infinite recursion on this very routine) gErrorIgnoreLevel = oldlevel; i->BuildOld(); + if (hint_pair_size) + i->GetClass()->SetClassSize(hint_pair_size); return i; } -TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &pairclassname, bool silent) +TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &pairclassname, bool silent, size_t hint_pair_offset, size_t hint_pair_size) { const static int pairlen = strlen("pair<"); if (pairclassname.compare(0, pairlen, "pair<") != 0) { @@ -5709,5 +5713,5 @@ TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &pair return nullptr; } - return GenerateInfoForPair(inside[1], inside[2], silent); + return GenerateInfoForPair(inside[1], inside[2], silent, hint_pair_offset, hint_pair_size); } From eacc061050e014ab90b69e1612a819c48047f1b6 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 20 Nov 2020 18:38:25 -0600 Subject: [PATCH 2/9] Record that the TClass is from GenerateInfoForPair. The TClass generated by TStreamerInfo::GenerateInfoForPair is neither 'Interpreted' (cling likely does not, yet, have any information about that pair) nor loaded (the user did not request a dictionary for it) but need to have special treatment for those TClass. It is not clear whether this should be a new state. For now we introduce a new data member (`fIsSyntheticPair`) and don't increase the size of TClass instance by using a bit field. --- core/meta/inc/TClass.h | 10 ++++++++-- core/meta/src/TClass.cxx | 14 +++++++------- io/io/src/TStreamerInfo.cxx | 4 ++++ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/core/meta/inc/TClass.h b/core/meta/inc/TClass.h index 9622cec15a7c8..2009b630e5533 100644 --- a/core/meta/inc/TClass.h +++ b/core/meta/inc/TClass.h @@ -223,7 +223,13 @@ friend class TStreamerInfo; ClassConvStreamerFunc_t fConvStreamerFunc; //Wrapper around this class custom conversion Streamer member function. Int_t fSizeof; //Sizeof the class. - Int_t fCanSplit; //!Indicates whether this class can be split or not. + // Bit field + Int_t fCanSplit : 3; //!Indicates whether this class can be split or not. Values are -1, 0, 1, 2 + + //! Indicates whether this class represent a pair and was not created from a dictionary nor interpreter info but has + //! compiler compatible offset and size (and all the info is in the StreamerInfo per se) + Bool_t fIsSyntheticPair : 1; //! + mutable std::atomic fProperty; //!Property See TClass::Property() for details mutable Long_t fClassProperty; //!C++ Property of the class (is abstract, has virtual table, etc.) @@ -368,7 +374,7 @@ friend class TStreamerInfo; TVirtualStreamerInfo *FindConversionStreamerInfo( const char* onfile_classname, UInt_t checksum ) const; TVirtualStreamerInfo *GetConversionStreamerInfo( const TClass* onfile_cl, Int_t version ) const; TVirtualStreamerInfo *FindConversionStreamerInfo( const TClass* onfile_cl, UInt_t checksum ) const; - Bool_t HasDataMemberInfo() const { return fHasRootPcmInfo || HasInterpreterInfo(); } + Bool_t HasDataMemberInfo() const { return fIsSyntheticPair || fHasRootPcmInfo || HasInterpreterInfo(); } Bool_t HasDefaultConstructor(Bool_t testio = kFALSE) const; Bool_t HasInterpreterInfoInMemory() const { return 0 != fClassInfo; } Bool_t HasInterpreterInfo() const { return fCanLoadClassInfo || fClassInfo; } diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index fad93d2b96856..88806e83ec566 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -1053,7 +1053,7 @@ TClass::TClass() : fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(kNoInfo), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -1091,7 +1091,7 @@ TClass::TClass(const char *name, Bool_t silent) : fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(kNoInfo), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -1138,7 +1138,7 @@ TClass::TClass(const char *name, Version_t cversion, Bool_t silent) : fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(kNoInfo), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -1165,7 +1165,7 @@ TClass::TClass(const char *name, Version_t cversion, EState theState, Bool_t sil fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(theState), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -1209,7 +1209,7 @@ TClass::TClass(ClassInfo_t *classInfo, Version_t cversion, fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(kNoInfo), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -1259,7 +1259,7 @@ TClass::TClass(const char *name, Version_t cversion, fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(kNoInfo), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), @@ -1290,7 +1290,7 @@ TClass::TClass(const char *name, Version_t cversion, fStreamer(0), fIsA(0), fGlobalIsA(0), fIsAMethod(0), fMerge(0), fResetAfterMerge(0), fNew(0), fNewArray(0), fDelete(0), fDeleteArray(0), fDestructor(0), fDirAutoAdd(0), fStreamerFunc(0), fConvStreamerFunc(0), fSizeof(-1), - fCanSplit(-1), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), + fCanSplit(-1), fIsSyntheticPair(kFALSE), fProperty(0), fClassProperty(0), fHasRootPcmInfo(kFALSE), fCanLoadClassInfo(kFALSE), fIsOffsetStreamerSet(kFALSE), fVersionUsed(kFALSE), fRuntimeProperties(0), fOffsetStreamer(0), fStreamerType(TClass::kDefault), fState(kHasTClassInit), fCurrentInfo(0), fLastReadInfo(0), fRefProxy(0), diff --git a/io/io/src/TStreamerInfo.cxx b/io/io/src/TStreamerInfo.cxx index 961450dd9d13b..88abf6db21edf 100644 --- a/io/io/src/TStreamerInfo.cxx +++ b/io/io/src/TStreamerInfo.cxx @@ -5689,7 +5689,11 @@ TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &firs gErrorIgnoreLevel = kError; i->BuildCheck(nullptr, kFALSE); // Skipping the loading part (it would leads to infinite recursion on this very routine) gErrorIgnoreLevel = oldlevel; + + i->GetClass()->fIsSyntheticPair = kTRUE; + i->BuildOld(); + if (hint_pair_size) i->GetClass()->SetClassSize(hint_pair_size); return i; From 32cc344f568580221ee3e3b2e8c74c45899145f0 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 20 Nov 2020 18:44:04 -0600 Subject: [PATCH 3/9] TClass::GetClass now create a synthetic instance only if pair hints are provided. Since getting the right alignment and padding is hard (either use Cling/Clang with the associated memory cost and potential autoparsing or duplicating the platform dependent code that calculates it), we now only creates the synthetic TClass instance that represent and std::pair ***if and only*** the call is provided the actual offset of second and sizeof the pair. This information is known to compiled (and later interpreted) CollectionProxy, to TClass for class containing an std::pair (via their list of RealData which is recorded in the rootpcm) and to TClass::GetClass templated on the actual type (since the pair's data members are public) --- core/meta/src/TClass.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index 88806e83ec566..99a8ead368ec7 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -3091,12 +3091,11 @@ TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent, size_t hi // TClass if we have one. if (cl) return cl; - if (ispair) { + if (ispair && hint_pair_offset && hint_pair_size) { auto pairinfo = TVirtualStreamerInfo::Factory()->GenerateInfoForPair(normalizedName, silent, hint_pair_offset, hint_pair_size); //return pairinfo ? pairinfo->GetClass() : nullptr; if (pairinfo) return pairinfo->GetClass(); - } else if (TClassEdit::IsSTLCont( normalizedName.c_str() )) { return gInterpreter->GenerateTClass(normalizedName.c_str(), kTRUE, silent); From 807bc6f82488c5185f8308a5c45bfa2f52e3929a Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 20 Nov 2020 20:43:31 -0600 Subject: [PATCH 4/9] Add specialization of TClass::GetClass for pair. Extract the offset and size of the pair and pass it along to raw TClass::GetClass --- core/meta/inc/TClass.h | 20 ++++++++++++++++++-- core/meta/src/TClass.cxx | 15 +++++++++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/core/meta/inc/TClass.h b/core/meta/inc/TClass.h index 2009b630e5533..7b52327364558 100644 --- a/core/meta/inc/TClass.h +++ b/core/meta/inc/TClass.h @@ -543,7 +543,7 @@ friend class TStreamerInfo; static void RemoveClassDeclId(TDictionary::DeclId_t id); static TClass *GetClass(const char *name, Bool_t load = kTRUE, Bool_t silent = kFALSE); static TClass *GetClass(const char *name, Bool_t load, Bool_t silent, size_t hint_pair_offset, size_t hint_pair_size); - static TClass *GetClass(const std::type_info &typeinfo, Bool_t load = kTRUE, Bool_t silent = kFALSE); + static TClass *GetClass(const std::type_info &typeinfo, Bool_t load = kTRUE, Bool_t silent = kFALSE, size_t hint_pair_offset = 0, size_t hint_pair_size = 0); static TClass *GetClass(ClassInfo_t *info, Bool_t load = kTRUE, Bool_t silent = kFALSE); template static TClass *GetClass(Bool_t load = kTRUE, Bool_t silent = kFALSE); @@ -588,10 +588,26 @@ TClass *GetClassHelper(Bool_t, Bool_t, std::true_type) return T::Class(); } +template +struct TClassGetClassHelper { + static TClass *GetClass(Bool_t load, Bool_t silent) { + return TClass::GetClass(typeid(T), load, silent); + } +}; + +template +struct TClassGetClassHelper > { + static TClass *GetClass(Bool_t load, Bool_t silent) { + std::pair *p = nullptr; + size_t hint_offset = ((char*)&(p->second)) - (char*)p; + return TClass::GetClass(typeid(std::pair), load, silent, hint_offset, sizeof(std::pair)); + } +}; + template TClass *GetClassHelper(Bool_t load, Bool_t silent, std::false_type) { - return TClass::GetClass(typeid(T), load, silent); + return TClassGetClassHelper::GetClass(load, silent); } } // namespace Internal diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index 99a8ead368ec7..2becd41a6ac6d 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -3178,7 +3178,7 @@ TClass *TClass::GetClass(const char *name, Bool_t load, Bool_t silent, size_t hi //////////////////////////////////////////////////////////////////////////////// /// Return pointer to class with name. -TClass *TClass::GetClass(const std::type_info& typeinfo, Bool_t load, Bool_t /* silent */) +TClass *TClass::GetClass(const std::type_info& typeinfo, Bool_t load, Bool_t /* silent */, size_t hint_pair_offset, size_t hint_pair_size) { if (!gROOT->GetListOfClasses()) return 0; @@ -3243,12 +3243,23 @@ TClass *TClass::GetClass(const std::type_info& typeinfo, Bool_t load, Bool_t /* if (autoload_old && gInterpreter->AutoLoad(typeinfo,kTRUE)) { // Disable autoload to avoid potential infinite recursion TInterpreter::SuspendAutoLoadingRAII autoloadOff(gInterpreter); - cl = GetClass(typeinfo, load); + cl = GetClass(typeinfo, load, hint_pair_offset, hint_pair_size); if (cl) { return cl; } } + if (hint_pair_offset) { + int err = 0; + char* demangled_name = TClassEdit::DemangleTypeIdName(typeinfo, err); + if (!err) { + cl = TClass::GetClass(demangled_name, load, kTRUE, hint_pair_offset, hint_pair_size); + free(demangled_name); + if (cl) + return cl; + } + } + // last attempt. Look in the interpreter list of all (compiled+interpreted) // classes cl = gInterpreter->GetClass(typeinfo, load); From 78814cc3ae5230d8fb7dd6d1ec7d7cdbbe8ee013 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 20 Nov 2020 20:50:25 -0600 Subject: [PATCH 5/9] TProtoClass::FillTClass create synthetic pair TClass as needed. Use the data in fPRealData to calculate the offset and size of the pair --- core/meta/src/TProtoClass.cxx | 43 +++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/core/meta/src/TProtoClass.cxx b/core/meta/src/TProtoClass.cxx index fce40ed1e5ee8..5fb2dc8356760 100644 --- a/core/meta/src/TProtoClass.cxx +++ b/core/meta/src/TProtoClass.cxx @@ -312,7 +312,9 @@ Bool_t TProtoClass::FillTClass(TClass* cl) { int prevLevel = 0; bool first = true; if (fPRealData.size() > 0) { + size_t element_next_idx = 0; for (auto element: fPRealData) { + ++element_next_idx; //if (element->IsA() == TObjString::Class()) { if (element.IsAClass() ) { // We now check for the TClass entry, w/o loading. Indeed we did that above. @@ -322,16 +324,34 @@ Bool_t TProtoClass::FillTClass(TClass* cl) { // will be issued. TInterpreter::SuspendAutoParsing autoParseRaii(gInterpreter); + const char *classname = GetClassName(element.fClassIndex); + // Disable autoparsing which might be triggered by the use of ResolvedTypedef // and the fallback new TClass() below. - currentRDClass = TClass::GetClass(GetClassName(element.fClassIndex), false /* Load */ ); + currentRDClass = TClass::GetClass(classname, false /* Load */ ); //printf("element is a class - name %s - index %d %s \n ",currentRDClass->GetName(), element.fClassIndex, GetClassName(element.fClassIndex) ); if (!currentRDClass && !element.TestFlag(TProtoRealData::kIsTransient)) { - if (gDebug>1) - Info("FillTClass()", - "Cannot find TClass for %s; Creating an empty one in the kForwardDeclared state.", - GetClassName(element.fClassIndex)); - currentRDClass = new TClass(GetClassName(element.fClassIndex),1,TClass::kForwardDeclared, true /*silent*/); + + if (TClassEdit::IsStdPair(classname) && element.fDMIndex == 0 && fPRealData.size() > element_next_idx) { + size_t hint_offset = fPRealData[element_next_idx].fOffset - element.fOffset; + size_t hint_size = 0; + // Now find the size. + size_t end = element_next_idx + 1; + while (end < fPRealData.size() && fPRealData[end].fLevel > element.fLevel) + ++end; + if (end < fPRealData.size()) { + hint_size = fPRealData[end].fOffset - element.fOffset; + } else { + hint_size = fSizeof - element.fOffset; + } + currentRDClass = TClass::GetClass(classname, true, false, hint_offset, hint_size); + } + if (!currentRDClass) { + if (gDebug > 1) + Info("FillTClass()", + "Cannot find TClass for %s; Creating an empty one in the kForwardDeclared state.", classname); + currentRDClass = new TClass(classname, 1, TClass::kForwardDeclared, true /*silent*/); + } } } //else { @@ -432,10 +452,10 @@ TRealData* TProtoClass::TProtoRealData::CreateRealData(TClass* dmClass, //TDataMember* dm = (TDataMember*)dmClass->GetListOfDataMembers()->FindObject(fName); TDataMember* dm = TProtoClass::FindDataMember(dmClass, fDMIndex); - if (!dm && dmClass->GetState()!=TClass::kForwardDeclared) { + if (!dm && dmClass->GetState()!=TClass::kForwardDeclared && !dmClass->fIsSyntheticPair) { ::Error("CreateRealData", - "Cannot find data member # %d of class %s for parent %s!", fDMIndex, dmClass->GetName(), - parent->GetName()); + "Cannot find data member # %d of class %s for parent %s!", fDMIndex, dmClass->GetName(), + parent->GetName()); return nullptr; } @@ -444,6 +464,9 @@ TRealData* TProtoClass::TProtoRealData::CreateRealData(TClass* dmClass, TString realMemberName; // keep an empty name if data member is not found if (dm) realMemberName = dm->GetName(); + else if (dmClass->fIsSyntheticPair) { + realMemberName = (fDMIndex == 0) ? "first" : "second"; + } if (TestFlag(kIsPointer) ) realMemberName = TString("*")+realMemberName; else if (dm){ @@ -530,7 +553,7 @@ TDataMember * TProtoClass::FindDataMember(TClass * cl, Int_t index) return dm; i++; } - if (cl->GetState()!=TClass::kForwardDeclared) + if (cl->GetState()!=TClass::kForwardDeclared && !cl->fIsSyntheticPair) ::Error("TProtoClass::FindDataMember","data member with index %d is not found in class %s",index,cl->GetName()); return nullptr; } From 8c0d6132ced4af8554b9e8ba8984d812c2531661 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 20 Nov 2020 21:33:37 -0600 Subject: [PATCH 6/9] Remove deleted StreamerInfo from the global list Note: If a StreamerInfo is loaded from a file and is the same information as an existing one, it is assigned the same "unique id" and we need to double check before removing it from the global list. --- io/io/src/TFile.cxx | 1 - io/io/src/TStreamerInfo.cxx | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/io/io/src/TFile.cxx b/io/io/src/TFile.cxx index 6d41d5cdad26d..965f1ba573d1d 100644 --- a/io/io/src/TFile.cxx +++ b/io/io/src/TFile.cxx @@ -3675,7 +3675,6 @@ void TFile::WriteStreamerInfo() listOfRules.SetName("listOfRules"); std::set classSet; - while ((info = (TStreamerInfo*)next())) { Int_t uid = info->GetNumber(); if (fClassIndex->fArray[uid]) { diff --git a/io/io/src/TStreamerInfo.cxx b/io/io/src/TStreamerInfo.cxx index 88abf6db21edf..47e3d73bd8322 100644 --- a/io/io/src/TStreamerInfo.cxx +++ b/io/io/src/TStreamerInfo.cxx @@ -212,6 +212,12 @@ TStreamerInfo::TStreamerInfo(TClass *cl) TStreamerInfo::~TStreamerInfo() { + // Note: If a StreamerInfo is loaded from a file and is the same information + // as an existing one, it is assigned the same "unique id" and we need to double + // check before removing it from the global list. + if (fNumber >=0 && gROOT->GetListOfStreamerInfo()->At(fNumber) == this) + gROOT->GetListOfStreamerInfo()->RemoveAt(fNumber); + delete [] fComp; fComp = 0; delete [] fCompFull; fCompFull = 0; delete [] fCompOpt; fCompOpt = 0; From 88023912bd46d980c15766b3dd710d45e0b5a620 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 20 Nov 2020 21:36:24 -0600 Subject: [PATCH 7/9] Avoid spurrious warning about missing info in synthetic TClass for pair --- core/meta/inc/TClass.h | 1 + io/io/src/TFile.cxx | 2 +- io/io/src/TStreamerInfo.cxx | 10 ++++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/core/meta/inc/TClass.h b/core/meta/inc/TClass.h index 7b52327364558..222bbb6595752 100644 --- a/core/meta/inc/TClass.h +++ b/core/meta/inc/TClass.h @@ -486,6 +486,7 @@ friend class TStreamerInfo; Bool_t IsLoaded() const; Bool_t IsForeign() const; Bool_t IsStartingWithTObject() const; + Bool_t IsSyntheticPair() const { return fIsSyntheticPair; } Bool_t IsVersioned() const { return !( GetClassVersion()<=1 && IsForeign() ); } Bool_t IsTObject() const; static TClass *LoadClass(const char *requestedname, Bool_t silent); diff --git a/io/io/src/TFile.cxx b/io/io/src/TFile.cxx index 965f1ba573d1d..d15cd28be6e6c 100644 --- a/io/io/src/TFile.cxx +++ b/io/io/src/TFile.cxx @@ -3559,7 +3559,7 @@ void TFile::ReadStreamerInfo() Int_t asize = fClassIndex->GetSize(); if (uid >= asize && uid <100000) fClassIndex->Set(2*asize); if (uid >= 0 && uid < fClassIndex->GetSize()) fClassIndex->fArray[uid] = 1; - else if (!isstl) { + else if (!isstl && !info->GetClass()->IsSyntheticPair()) { printf("ReadStreamerInfo, class:%s, illegal uid=%d\n",info->GetName(),uid); } if (gDebug > 0) printf(" -class: %s version: %d info read at slot %d\n",info->GetName(), info->GetClassVersion(),uid); diff --git a/io/io/src/TStreamerInfo.cxx b/io/io/src/TStreamerInfo.cxx index 47e3d73bd8322..387def736ecba 100644 --- a/io/io/src/TStreamerInfo.cxx +++ b/io/io/src/TStreamerInfo.cxx @@ -572,8 +572,9 @@ void TStreamerInfo::Build(Bool_t isTransient) element = new TStreamerObjectPointer(dmName, dmTitle, offset, dmFull); } else { element = new TStreamerObjectAnyPointer(dmName, dmTitle, offset, dmFull); - if (!isTransient && !streamer && !clm->GetStreamer() && !clm->IsLoaded()) { - Error("Build", "%s: %s has no streamer or dictionary, data member %s will not be saved", GetName(), dmFull, dmName); + if (!isTransient && !streamer && !clm->GetStreamer() && !clm->IsLoaded() && !clm->fIsSyntheticPair) { + Error("Build", "%s: %s has no streamer or dictionary, data member %s will not be saved", + GetName(), dmFull, dmName); } } } @@ -583,8 +584,9 @@ void TStreamerInfo::Build(Bool_t isTransient) element = new TStreamerString(dmName, dmTitle, offset); } else { element = new TStreamerObjectAny(dmName, dmTitle, offset, dmFull); - if (!isTransient && !streamer && !clm->GetStreamer() && !clm->IsLoaded()) { - Warning("Build", "%s: %s has no streamer or dictionary, data member \"%s\" will not be saved", GetName(), dmFull, dmName); + if (!isTransient && !streamer && !clm->GetStreamer() && !clm->IsLoaded() && !clm->fIsSyntheticPair) { + Warning("Build", "%s: %s has no streamer or dictionary, data member \"%s\" will not be saved", + GetName(), dmFull, dmName); } } } From 6e0d90ba72b867f74669a75498304aad17d5fa71 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 20 Nov 2020 21:37:42 -0600 Subject: [PATCH 8/9] TStreamerInfo::Build: fix size calculation for synthetic TClass for pair. --- io/io/src/TStreamerInfo.cxx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/io/io/src/TStreamerInfo.cxx b/io/io/src/TStreamerInfo.cxx index 387def736ecba..f71a42bf9d50d 100644 --- a/io/io/src/TStreamerInfo.cxx +++ b/io/io/src/TStreamerInfo.cxx @@ -2421,7 +2421,7 @@ void TStreamerInfo::BuildOld() element->SetOffset(kMissing); } - if (offset != kMissing && fClass->GetState() <= TClass::kEmulated) { + if (offset != kMissing && fClass->GetState() <= TClass::kEmulated && !fClass->fIsSyntheticPair) { // Note the initialization in this case are // delayed until __after__ the schema evolution // section, just in case the info has changed. @@ -3085,6 +3085,13 @@ Bool_t TStreamerInfo::CompareContent(TClass *cl, TVirtualStreamerInfo *info, Boo void TStreamerInfo::ComputeSize() { + if (this == fClass->GetCurrentStreamerInfo()) { + if (fClass->GetState() >= TClass::kInterpreted || fClass->fIsSyntheticPair) { + fSize = fClass->GetClassSize(); + return; + } + } + TStreamerElement *element = (TStreamerElement*)fElements->Last(); //faster and more precise to use last element offset +size //on 64 bit machines, offset may be forced to be a multiple of 8 bytes @@ -5697,8 +5704,13 @@ TVirtualStreamerInfo *TStreamerInfo::GenerateInfoForPair(const std::string &firs gErrorIgnoreLevel = kError; i->BuildCheck(nullptr, kFALSE); // Skipping the loading part (it would leads to infinite recursion on this very routine) gErrorIgnoreLevel = oldlevel; - - i->GetClass()->fIsSyntheticPair = kTRUE; + // In the state emulated, BuildOld would recalculate the offset and undo the offset update. + // Note: we should consider adding a new state just for this (the hints indicates that we are mapping a compiled class but + // then we would have to investigate all use of the state with <= and >= condition to make sure they are still appropriate). + if (hint_pair_size) { + i->GetClass()->SetClassSize(hint_pair_size); + i->GetClass()->fIsSyntheticPair = kTRUE; + } i->BuildOld(); From dbeece7f9b10e38e4b16289d8a2a401a6e3f57ca Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Sat, 21 Nov 2020 13:16:18 -0600 Subject: [PATCH 9/9] Ignore onfile StreamerInfo for Synthetic TClass for pair --- io/io/src/TStreamerInfo.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/io/io/src/TStreamerInfo.cxx b/io/io/src/TStreamerInfo.cxx index f71a42bf9d50d..d664466d57374 100644 --- a/io/io/src/TStreamerInfo.cxx +++ b/io/io/src/TStreamerInfo.cxx @@ -776,6 +776,13 @@ void TStreamerInfo::BuildCheck(TFile *file /* = 0 */, Bool_t load /* = kTRUE */) return; } } + if (fClass->fIsSyntheticPair) { + // The format never change, no need to import the old StreamerInof + // (which anyway would have issue when being setup due to the lack + // of TDataMember in the TClass. + SetBit(kCanDelete); + return; + } if (0 == strcmp("string",fClass->GetName())) { // We know we do not need any offset check for a string