diff --git a/core/cont/inc/TVirtualCollectionProxy.h b/core/cont/inc/TVirtualCollectionProxy.h index d191ef94b429b..9e76ee64e04b2 100644 --- a/core/cont/inc/TVirtualCollectionProxy.h +++ b/core/cont/inc/TVirtualCollectionProxy.h @@ -68,11 +68,14 @@ class TVirtualCollectionProxy { TPushPop& operator=(const TPushPop&) = delete; }; - TVirtualCollectionProxy() : fClass(), fProperties(0) {}; - TVirtualCollectionProxy(TClass *cl) : fClass(cl), fProperties(0) {}; + TVirtualCollectionProxy() : fClass(), fProperties(0) {} + TVirtualCollectionProxy(TClass *cl) : fClass(cl), fProperties(0) {} virtual TVirtualCollectionProxy* Generate() const = 0; // Returns an object of the actual CollectionProxy class - virtual ~TVirtualCollectionProxy() {}; + virtual ~TVirtualCollectionProxy() {} + + // Reset the info gathered from StreamerInfos and value's TClass. + virtual Bool_t Reset() { return kTRUE; } virtual TClass *GetCollectionClass() const { return fClass; } // Return a pointer to the TClass representing the container diff --git a/core/meta/inc/TListOfEnums.h b/core/meta/inc/TListOfEnums.h index 63c688ce4d48d..17ebeba860448 100644 --- a/core/meta/inc/TListOfEnums.h +++ b/core/meta/inc/TListOfEnums.h @@ -71,6 +71,9 @@ class TListOfEnums : public THashList TEnum *Find(DeclId_t id) const; virtual TEnum *GetObject(const char*) const; + TObject *FindObject(const char*) const override; + using THashList::FindObject; + void Clear(Option_t *option) override; void Delete(Option_t *option="") override; diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index 9680f9947c1de..7db4e313ec3f1 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -5995,6 +5995,45 @@ void TClass::PostLoadCheck() } } } + if (fCollectionProxy) { + // Update the related pair's TClass if it has already been created. + size_t noffset = 0; + if (strncmp(GetName(), "map<", 4) == 0) + noffset = 3; + else if (strncmp(GetName(), "multimap<", 9) == 0) + noffset = 8; + else if (strncmp(GetName(), "unordered_map<", 14) == 0) + noffset = 13; + else if (strncmp(GetName(), "unordered_multimap<", 19) == 0) + noffset = 18; + if (noffset) { + std::string pairname("pair"); + pairname.append(GetName() + noffset); + auto pcl = TClass::GetClass(pairname.c_str(), false, false); + if ( pcl && !pcl->IsLoaded() && !pcl->IsSyntheticPair() ) + { + TInterpreter::SuspendAutoLoadingRAII autoloadOff(gInterpreter); + + fCollectionProxy->Reset(); + TIter nextClass(gROOT->GetListOfClasses()); + while (auto acl = (TClass*)nextClass()) { + if (acl == this) continue; + if (acl->fCollectionProxy && acl->fCollectionProxy->GetValueClass() == pcl) { + acl->fCollectionProxy->Reset(); + } + } + + TIter next(pcl->GetStreamerInfos()); + while (auto info = (TVirtualStreamerInfo*)next()) { + if (info->IsBuilt()) { + info->Clear("build"); + info->BuildOld(); + } + } + fCollectionProxy->GetValueClass(); + } + } + } } //////////////////////////////////////////////////////////////////////////////// @@ -7258,6 +7297,10 @@ void TClass::RemoveStreamerInfo(Int_t slot) R__LOCKGUARD(gInterpreterMutex); TVirtualStreamerInfo *info = (TVirtualStreamerInfo*)fStreamerInfo->At(slot); fStreamerInfo->RemoveAt(fClassVersion); + if (fLastReadInfo.load() == info) + fLastReadInfo = nullptr; + if (fCurrentInfo.load() == info) + fCurrentInfo = nullptr; delete info; if (fState == kEmulated && fStreamerInfo->GetEntries() == 0) { fState = kForwardDeclared; diff --git a/core/meta/src/TListOfEnums.cxx b/core/meta/src/TListOfEnums.cxx index d06ad74e28e05..8a35a135355a1 100644 --- a/core/meta/src/TListOfEnums.cxx +++ b/core/meta/src/TListOfEnums.cxx @@ -183,6 +183,21 @@ TEnum *TListOfEnums::Find(DeclId_t id) const return (TEnum *)fIds->GetValue((Long64_t)id); } +//////////////////////////////////////////////////////////////////////////////// +/// Specialize FindObject to do search for the +/// a enum just by name or create it if its not already in the list + +TObject *TListOfEnums::FindObject(const char *name) const +{ + TObject *result = THashList::FindObject(name); + if (!result) { + TInterpreter::DeclId_t decl; + decl = gInterpreter->GetEnum(GetClass(), name); + if (decl) result = const_cast(this)->Get(decl, name); + } + return result; +} + //////////////////////////////////////////////////////////////////////////////// /// Return (after creating it if necessary) the TEnum /// describing the enum corresponding to the Decl 'id'. diff --git a/core/meta/src/TListOfEnumsWithLock.cxx b/core/meta/src/TListOfEnumsWithLock.cxx index dadefa98c947b..761481fc73c80 100644 --- a/core/meta/src/TListOfEnumsWithLock.cxx +++ b/core/meta/src/TListOfEnumsWithLock.cxx @@ -156,16 +156,7 @@ void TListOfEnumsWithLock::Delete(Option_t *option /* ="" */) TObject *TListOfEnumsWithLock::FindObject(const char *name) const { R__LOCKGUARD(gInterpreterMutex); - TObject *result = TListOfEnums::FindObject(name); - if (!result) { - - - TInterpreter::DeclId_t decl; - if (GetClass()) decl = gInterpreter->GetEnum(GetClass(), name); - else decl = gInterpreter->GetEnum(0, name); - if (decl) result = const_cast(this)->Get(decl, name); - } - return result; + return TListOfEnums::FindObject(name); } diff --git a/core/meta/src/TProtoClass.cxx b/core/meta/src/TProtoClass.cxx index 5fb2dc8356760..f82665543bc2a 100644 --- a/core/meta/src/TProtoClass.cxx +++ b/core/meta/src/TProtoClass.cxx @@ -24,6 +24,7 @@ Persistent version of a TClass. #include "TList.h" #include "TListOfDataMembers.h" #include "TListOfEnums.h" +#include "TListOfEnumsWithLock.h" #include "TRealData.h" #include "TError.h" #include "TVirtualCollectionProxy.h" @@ -31,6 +32,22 @@ Persistent version of a TClass. #include #include +#ifdef WIN32 +#include +#include "Windows4Root.h" +#include +#define RTLD_DEFAULT ((void *)::GetModuleHandle(NULL)) +#define dlsym(library, function_name) ::GetProcAddress((HMODULE)library, function_name) +#else +#include +#endif + +static bool IsFromRootCling() { + // rootcling also uses TCling for generating the dictionary ROOT files. + const static bool foundSymbol = dlsym(RTLD_DEFAULT, "usedToIdentifyRootClingByDlSym"); + return foundSymbol; +} + //////////////////////////////////////////////////////////////////////////////// /// Initialize a TProtoClass from a TClass. @@ -262,7 +279,8 @@ Bool_t TProtoClass::FillTClass(TClass* cl) { // We need to fill enums one by one to initialise the internal map which is // transient { - auto temp = new TListOfEnums(); + auto temp = cl->fEnums.load() ? cl->fEnums.load() : + IsFromRootCling() ? new TListOfEnums() : new TListOfEnumsWithLock(); if (fEnums) { for (TObject* enumAsTObj : *fEnums){ temp->Add((TEnum*) enumAsTObj); diff --git a/core/metacling/src/TCling.cxx b/core/metacling/src/TCling.cxx index 79bce08995332..f75efddc3224d 100644 --- a/core/metacling/src/TCling.cxx +++ b/core/metacling/src/TCling.cxx @@ -1712,51 +1712,6 @@ void TCling::LoadPCMImpl(TFile &pcmFile) if (gDebug > 1) ::Info("TCling::LoadPCMImpl", "reading protoclasses for %s \n", pcmFile.GetName()); - pcmFile.GetObject("__ProtoClasses", protoClasses); - - if (protoClasses) { - for (auto obj : *protoClasses) { - TProtoClass *proto = (TProtoClass *)obj; - TClassTable::Add(proto); - } - // Now that all TClass-es know how to set them up we can update - // existing TClasses, which might cause the creation of e.g. TBaseClass - // objects which in turn requires the creation of TClasses, that could - // come from the PCH, but maybe later in the loop. Instead of resolving - // a dependency graph the addition to the TClassTable above allows us - // to create these dependent TClasses as needed below. - for (auto proto : *protoClasses) { - if (TClass *existingCl = (TClass *)gROOT->GetListOfClasses()->FindObject(proto->GetName())) { - // We have an existing TClass object. It might be emulated - // or interpreted; we now have more information available. - // Make that available. - if (existingCl->GetState() != TClass::kHasTClassInit) { - DictFuncPtr_t dict = gClassTable->GetDict(proto->GetName()); - if (!dict) { - ::Error("TCling::LoadPCM", "Inconsistent TClassTable for %s", proto->GetName()); - } else { - // This will replace the existing TClass. - TClass *ncl = (*dict)(); - if (ncl) - ncl->PostLoadCheck(); - } - } - } - } - - protoClasses->Clear(); // Ownership was transfered to TClassTable. - delete protoClasses; - } - - TObjArray *dataTypes; - pcmFile.GetObject("__Typedefs", dataTypes); - if (dataTypes) { - for (auto typedf : *dataTypes) - gROOT->GetListOfTypes()->Add(typedf); - dataTypes->Clear(); // Ownership was transfered to TListOfTypes. - delete dataTypes; - } - TObjArray *enums; pcmFile.GetObject("__Enums", enums); if (enums) { @@ -1806,6 +1761,51 @@ void TCling::LoadPCMImpl(TFile &pcmFile) enums->Clear(); delete enums; } + + pcmFile.GetObject("__ProtoClasses", protoClasses); + + if (protoClasses) { + for (auto obj : *protoClasses) { + TProtoClass *proto = (TProtoClass *)obj; + TClassTable::Add(proto); + } + // Now that all TClass-es know how to set them up we can update + // existing TClasses, which might cause the creation of e.g. TBaseClass + // objects which in turn requires the creation of TClasses, that could + // come from the PCH, but maybe later in the loop. Instead of resolving + // a dependency graph the addition to the TClassTable above allows us + // to create these dependent TClasses as needed below. + for (auto proto : *protoClasses) { + if (TClass *existingCl = (TClass *)gROOT->GetListOfClasses()->FindObject(proto->GetName())) { + // We have an existing TClass object. It might be emulated + // or interpreted; we now have more information available. + // Make that available. + if (existingCl->GetState() != TClass::kHasTClassInit) { + DictFuncPtr_t dict = gClassTable->GetDict(proto->GetName()); + if (!dict) { + ::Error("TCling::LoadPCM", "Inconsistent TClassTable for %s", proto->GetName()); + } else { + // This will replace the existing TClass. + TClass *ncl = (*dict)(); + if (ncl) + ncl->PostLoadCheck(); + } + } + } + } + + protoClasses->Clear(); // Ownership was transfered to TClassTable. + delete protoClasses; + } + + TObjArray *dataTypes; + pcmFile.GetObject("__Typedefs", dataTypes); + if (dataTypes) { + for (auto typedf : *dataTypes) + gROOT->GetListOfTypes()->Add(typedf); + dataTypes->Clear(); // Ownership was transfered to TListOfTypes. + delete dataTypes; + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/io/io/inc/TGenCollectionProxy.h b/io/io/inc/TGenCollectionProxy.h index 4c3f390f36beb..0cfe5ab5edaa6 100644 --- a/io/io/inc/TGenCollectionProxy.h +++ b/io/io/inc/TGenCollectionProxy.h @@ -70,7 +70,7 @@ class TGenCollectionProxy // Default copy constructor has the correct implementation. // Initializing constructor - Value(const std::string& info, Bool_t silent); + Value(const std::string& info, Bool_t silent, size_t hint_pair_offset = 0, size_t hint_pair_size = 0); // Delete individual item from STL container void DeleteItem(void* ptr); @@ -359,6 +359,9 @@ class TGenCollectionProxy // Standard destructor. virtual ~TGenCollectionProxy(); + // Reset the info gathered from StreamerInfos and value's TClass. + virtual Bool_t Reset(); + // Return a pointer to the TClass representing the container. virtual TClass *GetCollectionClass() const; diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index c5b759fa1aeee..979b514efb451 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -3516,6 +3516,8 @@ Int_t TBufferFile::WriteClassBuffer(const TClass *cl, void *pointer) //Have to be sure between the check and the taking of the lock if the current streamer has changed R__LOCKGUARD(gInterpreterMutex); sinfo = (TStreamerInfo*)const_cast(cl)->GetCurrentStreamerInfo(); + if (sinfo == nullptr) + sinfo = (TStreamerInfo*)const_cast(cl)->GetStreamerInfo(); if (sinfo == nullptr) { const_cast(cl)->BuildRealData(pointer); sinfo = new TStreamerInfo(const_cast(cl)); diff --git a/io/io/src/TGenCollectionProxy.cxx b/io/io/src/TGenCollectionProxy.cxx index 31e00a5cc626c..df36c7ff8095a 100644 --- a/io/io/src/TGenCollectionProxy.cxx +++ b/io/io/src/TGenCollectionProxy.cxx @@ -313,7 +313,7 @@ class TGenMapProxy : public TGenSetProxy { //////////////////////////////////////////////////////////////////////////////// /// Constructor. -TGenCollectionProxy::Value::Value(const std::string& inside_type, Bool_t silent) +TGenCollectionProxy::Value::Value(const std::string& inside_type, Bool_t silent, size_t hint_pair_offset, size_t hint_pair_size) { std::string inside = (inside_type.find("const ")==0) ? inside_type.substr(6) : inside_type; fCase = 0; @@ -364,7 +364,7 @@ TGenCollectionProxy::Value::Value(const std::string& inside_type, Bool_t silent) // might fail because CINT does not known the nesting // scope, so let's first look for an emulated class: - fType = TClass::GetClass(intype.c_str(),kTRUE,silent); + fType = TClass::GetClass(intype.c_str(),kTRUE,silent, hint_pair_offset, hint_pair_size); if (fType) { if (isPointer) { @@ -775,6 +775,19 @@ TGenCollectionProxy *TGenCollectionProxy::Initialize(Bool_t silent) const return p->InitializeEx(silent); } +//////////////////////////////////////////////////////////////////////////////// +/// Reset the info gathered from StreamerInfos and value's TClass. +Bool_t TGenCollectionProxy::Reset() +{ + if (fReadMemberWise) + fReadMemberWise->Clear(); + delete fWriteMemberWise; + fWriteMemberWise = nullptr; + if (fConversionReadMemberWise) + fConversionReadMemberWise->clear(); + return kTRUE; +} + //////////////////////////////////////////////////////////////////////////////// /// Check existence of function pointers @@ -815,9 +828,10 @@ void TGenCollectionProxy::CheckFunctions() const //////////////////////////////////////////////////////////////////////////////// /// Utility routine to issue a Fatal error is the Value object is not valid -static TGenCollectionProxy::Value *R__CreateValue(const std::string &name, Bool_t silent) +static TGenCollectionProxy::Value *R__CreateValue(const std::string &name, Bool_t silent, + size_t hint_pair_offset = 0, size_t hint_pair_size = 0) { - TGenCollectionProxy::Value *val = new TGenCollectionProxy::Value( name, silent ); + TGenCollectionProxy::Value *val = new TGenCollectionProxy::Value( name, silent, hint_pair_offset, hint_pair_size ); if ( !val->IsValid() ) { Fatal("TGenCollectionProxy","Could not find %s!",name.c_str()); } @@ -881,11 +895,16 @@ TGenCollectionProxy *TGenCollectionProxy::InitializeEx(Bool_t silent) { TInterpreter::SuspendAutoParsing autoParseRaii(gCling); - if (0==TClass::GetClass(nam.c_str(), true, false, fValOffset, fValDiff)) { + TClass *paircl = TClass::GetClass(nam.c_str(), true, false, fValOffset, fValDiff); + if (paircl == nullptr) { // We need to emulate the pair - TVirtualStreamerInfo::Factory()->GenerateInfoForPair(inside[1], inside[2], silent, fValOffset, fValDiff); + auto info = TVirtualStreamerInfo::Factory()->GenerateInfoForPair(inside[1], inside[2], silent, fValOffset, fValDiff); + if (!info) { + Fatal("InitializeEx", + "Could not load nor generate the dictionary for \"%s\", some element might be missing their dictionary (eg. enums)", + nam.c_str()); + } } else { - TClass *paircl = TClass::GetClass(nam.c_str()); if (paircl->GetClassSize() != fValDiff) { if (paircl->GetState() >= TClass::kInterpreted) Fatal("InitializeEx", @@ -896,7 +915,7 @@ TGenCollectionProxy *TGenCollectionProxy::InitializeEx(Bool_t silent) else { gROOT->GetListOfClasses()->Remove(paircl); TClass *newpaircl = TClass::GetClass(nam.c_str(), true, false, fValOffset, fValDiff); - if (newpaircl == paircl || newpaircl->GetClassSize() != fValDiff) + if (!newpaircl || 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); @@ -906,7 +925,7 @@ TGenCollectionProxy *TGenCollectionProxy::InitializeEx(Bool_t silent) } } } - newfValue = R__CreateValue(nam, silent); + newfValue = R__CreateValue(nam, silent, fValOffset, fValDiff); fPointers = (0 != (fKey->fCase&kIsPointer)); if (fPointers || (0 != (fKey->fProperties&kNeedDelete))) { diff --git a/io/io/src/TStreamerInfo.cxx b/io/io/src/TStreamerInfo.cxx index 4cbfbf61b0722..7d4782b624cb0 100644 --- a/io/io/src/TStreamerInfo.cxx +++ b/io/io/src/TStreamerInfo.cxx @@ -214,7 +214,8 @@ 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) + if (fNumber >=0 && gROOT->GetListOfStreamerInfo()->GetSize() > fNumber + && gROOT->GetListOfStreamerInfo()->At(fNumber) == this) gROOT->GetListOfStreamerInfo()->RemoveAt(fNumber); delete [] fComp; fComp = 0; @@ -2136,8 +2137,9 @@ void TStreamerInfo::BuildOld() if (pattern && pattern != this && pattern->IsBuilt()) { int pair_element_offset = kMissing; pattern->GetStreamerElement(element->GetName(), pair_element_offset); - if (offset != kMissing) - element->SetOffset(offset); + if (pair_element_offset != kMissing) { + element->SetOffset(pair_element_offset); + } } } } @@ -2608,13 +2610,20 @@ void TStreamerInfo::Clear(Option_t *option) delete [] fComp; fComp = 0; delete [] fCompFull; fCompFull= 0; delete [] fCompOpt; fCompOpt = 0; + fNdata = 0; fNfulldata = 0; fNslots= 0; fSize = 0; + ResetIsCompiled(); ResetBit(kBuildOldUsed); + TIter next(fElements); + while (auto element = (TStreamerElement*)next()) { + element->SetOffset(0); + } + if (fReadObjectWise) fReadObjectWise->fActions.clear(); if (fReadMemberWise) fReadMemberWise->fActions.clear(); if (fReadMemberWiseVecPtr) fReadMemberWiseVecPtr->fActions.clear(); diff --git a/io/rootpcm/src/rootclingIO.cxx b/io/rootpcm/src/rootclingIO.cxx index f9cf38a829c83..7d319ba6f84fe 100644 --- a/io/rootpcm/src/rootclingIO.cxx +++ b/io/rootpcm/src/rootclingIO.cxx @@ -169,6 +169,15 @@ bool CloseStreamerInfoROOTFile(bool writeEmptyRootPCM) auto dm = (TDataMember *) dmObj; if (!dm->IsPersistent() || cl->GetClassVersion()==0) continue; if (IsUnsupportedUniquePointer(normName.c_str(), dm)) return false; + if (dm->IsEnum()) { + const char *enumTypeName = dm->GetTypeName(); + auto enumType = TEnum::GetEnum(enumTypeName); + if (enumType && (!enumType->GetClass() || !enumType->GetClass()->IsLoaded()) && + ((strstr(enumTypeName, "(anonymous)") == nullptr) && + std::find(gEnumsToStore.begin(), gEnumsToStore.end(), enumTypeName) == gEnumsToStore.end())) + gEnumsToStore.emplace_back(enumTypeName); + } + } // Never store a proto class for a class which rootcling already has @@ -189,6 +198,27 @@ bool CloseStreamerInfoROOTFile(bool writeEmptyRootPCM) // continue; cl->Property(); // Force initialization of the bits and property fields. + if (auto pr = cl->GetCollectionProxy()) { + auto colltype = pr->GetCollectionType(); + if (colltype == ROOT::kSTLmap || colltype == ROOT::kSTLmultimap || + colltype == ROOT::kSTLunorderedmap || colltype == ROOT::kSTLunorderedmultimap) { + if (auto pcl = pr->GetValueClass()) { + if (auto pcl_dms = pcl->GetListOfDataMembers()) { + for (auto dmObj : *pcl_dms) { + auto dm = (TDataMember *) dmObj; + if (dm->IsEnum()) { + const char *enumTypeName = dm->GetTypeName(); + auto enumType = TEnum::GetEnum(enumTypeName); + if (enumType && (!enumType->GetClass() || !enumType->GetClass()->IsLoaded()) && + (std::find(gEnumsToStore.begin(), gEnumsToStore.end(), enumTypeName) == gEnumsToStore.end())) + gEnumsToStore.emplace_back(enumTypeName); + } + } + } + } + } + } + protoClasses.AddLast(new TProtoClass(cl)); } @@ -219,6 +249,8 @@ bool CloseStreamerInfoROOTFile(bool writeEmptyRootPCM) Error("CloseStreamerInfoROOTFile", "Cannot find TClass instance for namespace %s.", nsName.c_str()); return false; } + if (!(tclassInstance->Property() & kIsNamespace)) + continue; // Enum will be part of the TClass. auto enumListPtr = tclassInstance->GetListOfEnums(); if (!enumListPtr) { Error("CloseStreamerInfoROOTFile", "TClass instance for namespace %s does not have any enum associated. This is an inconsistency.", nsName.c_str()); @@ -242,10 +274,10 @@ bool CloseStreamerInfoROOTFile(bool writeEmptyRootPCM) if (dictFile.IsZombie()) return false; // Instead of plugins: - protoClasses.Write("__ProtoClasses", TObject::kSingleKey); - protoClasses.Delete(); typedefs.Write("__Typedefs", TObject::kSingleKey); enums.Write("__Enums", TObject::kSingleKey); + protoClasses.Write("__ProtoClasses", TObject::kSingleKey); + protoClasses.Delete(); return true; }