From d3a71a08482259b2f2a9567fc11d90a34a877454 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 13 Feb 2025 17:11:44 -0600 Subject: [PATCH 1/4] [meta] Always delegate set fStreamerImpl to SetStreamerImpl --- core/meta/src/TClass.cxx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index 671f1ff6916bd..f69734fc397ca 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -6175,7 +6175,6 @@ Long_t TClass::Property() const TClass *kl = const_cast(this); kl->fStreamerType = TClass::kDefault; - kl->fStreamerImpl = &TClass::StreamerDefault; if (InheritsFrom(TObject::Class())) { kl->SetBit(kIsTObject); @@ -6185,7 +6184,6 @@ Long_t TClass::Property() const if (delta==0) kl->SetBit(kStartWithTObject); kl->fStreamerType = kTObject; - kl->fStreamerImpl = &TClass::StreamerTObject; } if (HasInterpreterInfo()) { @@ -6198,26 +6196,21 @@ Long_t TClass::Property() const kl->SetBit(kIsForeign); kl->fStreamerType = kForeign; - kl->fStreamerImpl = &TClass::StreamerStreamerInfo; } else if ( kl->fStreamerType == TClass::kDefault ) { if (kl->fConvStreamerFunc) { kl->fStreamerType = kInstrumented; - kl->fStreamerImpl = &TClass::ConvStreamerInstrumented; } else if (kl->fStreamerFunc) { kl->fStreamerType = kInstrumented; - kl->fStreamerImpl = &TClass::StreamerInstrumented; } else { // We have an automatic streamer using the StreamerInfo .. no need to go through the // Streamer method function itself. kl->fStreamerType = kInstrumented; - kl->fStreamerImpl = &TClass::StreamerStreamerInfo; } } if (fStreamer) { kl->fStreamerType = kExternal; - kl->fStreamerImpl = &TClass::StreamerExternal; } if (const_cast(this)->GetClassMethodWithPrototype("Hash", "", kTRUE)) { @@ -6238,11 +6231,12 @@ Long_t TClass::Property() const // and think all test bits have been properly set. kl->fProperty = gCling->ClassInfo_Property(fClassInfo); } + + kl->SetStreamerImpl(); } else { if (fStreamer) { kl->fStreamerType = kExternal; - kl->fStreamerImpl = &TClass::StreamerExternal; } kl->fStreamerType |= kEmulatedStreamer; From 64930153a64266b77d4b7f76e4df295db6115fce Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 13 Feb 2025 17:17:42 -0600 Subject: [PATCH 2/4] [meta] TClass::Property change fStreamerType only once. --- core/meta/inc/TClass.h | 2 +- core/meta/src/TClass.cxx | 28 +++++++++++++++------------- core/meta/src/TProtoClass.cxx | 3 +-- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/core/meta/inc/TClass.h b/core/meta/inc/TClass.h index ff250aae7ef5a..e8c1a16339d47 100644 --- a/core/meta/inc/TClass.h +++ b/core/meta/inc/TClass.h @@ -307,7 +307,7 @@ friend class TStreamerInfo; void SetClassSize(Int_t sizof) { fSizeof = sizof; } TVirtualStreamerInfo* DetermineCurrentStreamerInfo(); - void SetStreamerImpl(); + void SetStreamerImpl(Int_t streamerType); void SetRuntimeProperties(); diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index f69734fc397ca..dff666543ee0b 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -6174,7 +6174,7 @@ Long_t TClass::Property() const TClass *kl = const_cast(this); - kl->fStreamerType = TClass::kDefault; + Int_t streamerType = TClass::kDefault; if (InheritsFrom(TObject::Class())) { kl->SetBit(kIsTObject); @@ -6183,7 +6183,7 @@ Long_t TClass::Property() const Int_t delta = kl->GetBaseClassOffsetRecurse(TObject::Class()); if (delta==0) kl->SetBit(kStartWithTObject); - kl->fStreamerType = kTObject; + streamerType = kTObject; } if (HasInterpreterInfo()) { @@ -6195,22 +6195,22 @@ Long_t TClass::Property() const if (!const_cast(this)->GetClassMethodWithPrototype("Streamer","TBuffer&",kFALSE)) { kl->SetBit(kIsForeign); - kl->fStreamerType = kForeign; + streamerType = kForeign; - } else if ( kl->fStreamerType == TClass::kDefault ) { + } else if (streamerType == TClass::kDefault) { if (kl->fConvStreamerFunc) { - kl->fStreamerType = kInstrumented; + streamerType = kInstrumented; } else if (kl->fStreamerFunc) { - kl->fStreamerType = kInstrumented; + streamerType = kInstrumented; } else { // We have an automatic streamer using the StreamerInfo .. no need to go through the // Streamer method function itself. - kl->fStreamerType = kInstrumented; + streamerType = kInstrumented; } } if (fStreamer) { - kl->fStreamerType = kExternal; + streamerType = kExternal; } if (const_cast(this)->GetClassMethodWithPrototype("Hash", "", kTRUE)) { @@ -6232,15 +6232,16 @@ Long_t TClass::Property() const kl->fProperty = gCling->ClassInfo_Property(fClassInfo); } - kl->SetStreamerImpl(); + kl->SetStreamerImpl(streamerType); } else { if (fStreamer) { - kl->fStreamerType = kExternal; + streamerType = kExternal; } - kl->fStreamerType |= kEmulatedStreamer; - kl->SetStreamerImpl(); + streamerType |= kEmulatedStreamer; + + kl->SetStreamerImpl(streamerType); // fProperty was *not* set so that it can be forced to be recalculated // next time. return 0; @@ -6275,8 +6276,9 @@ void TClass::SetRuntimeProperties() /// Internal routine to set fStreamerImpl based on the value of /// fStreamerType. -void TClass::SetStreamerImpl() +void TClass::SetStreamerImpl(Int_t StreamerType) { + fStreamerType = StreamerType; switch (fStreamerType) { case kTObject: fStreamerImpl = &TClass::StreamerTObject; break; case kForeign: fStreamerImpl = &TClass::StreamerStreamerInfo; break; diff --git a/core/meta/src/TProtoClass.cxx b/core/meta/src/TProtoClass.cxx index 26674c1cedd79..1c53d2c73f256 100644 --- a/core/meta/src/TProtoClass.cxx +++ b/core/meta/src/TProtoClass.cxx @@ -304,7 +304,6 @@ Bool_t TProtoClass::FillTClass(TClass* cl) { cl->fCanSplit = fCanSplit; cl->fProperty = fProperty; cl->fClassProperty = fClassProperty; - cl->fStreamerType = fStreamerType; // Update pointers to TClass if (cl->fBase.load()) { @@ -405,7 +404,7 @@ Bool_t TProtoClass::FillTClass(TClass* cl) { cl->fRealData = new TList(); // FIXME: this should really become a THashList! } - cl->SetStreamerImpl(); + cl->SetStreamerImpl(fStreamerType); // set to zero in order not to delete when protoclass is deleted fBase = nullptr; From 47672c46e7c5813fe94cabe143745fbb90c5ff9a Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 13 Feb 2025 17:21:56 -0600 Subject: [PATCH 3/4] [meta] Set fStreamerImpl before fProperty. So that all other settings are set before the release (i.e. fProperty switching from -1 to another value) --- core/meta/src/TClass.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index dff666543ee0b..68ff33275b5c9 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -6217,6 +6217,8 @@ Long_t TClass::Property() const kl->SetBit(kHasLocalHashMember); } + kl->SetStreamerImpl(streamerType); + if (GetClassInfo()) { // In the case where the TClass for one of ROOT's core class // (eg TClonesArray for map) is requested @@ -6232,7 +6234,6 @@ Long_t TClass::Property() const kl->fProperty = gCling->ClassInfo_Property(fClassInfo); } - kl->SetStreamerImpl(streamerType); } else { if (fStreamer) { From e1ea995b6eb356f1ec5c00f1355972b093d457ba Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 13 Feb 2025 17:23:12 -0600 Subject: [PATCH 4/4] [meta] Don't redo Property if no new information. It is re-run if the first time we ran it, it did not have the full information (i.e. no dictionary nor any interpreter info; this happens for forward classes and STL collections). --- core/meta/src/TClass.cxx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index 68ff33275b5c9..817e6ce4d7a47 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -6168,6 +6168,14 @@ Long_t TClass::Property() const // Avoid asking about the class when it is still building if (TestBit(kLoading)) return fProperty; + if (fStreamerType != kDefault && !HasInterpreterInfo()) { + // We have no interpreter information but we already set the streamer type + // so we have already been here and have no new information, then let's + // give up. See the code at this end of this routine (else branch of the + // `if (HasInterpreterInfo()` for the path we took before. + return 0; + } + // When called via TMapFile (e.g. Update()) make sure that the dictionary // gets allocated on the heap and not in the mapped file. TMmallocDescTemp setreset;