@@ -774,6 +774,137 @@ HRESULT CLR_RT_HeapBlock::Reassign(const CLR_RT_HeapBlock &value)
774
774
NANOCLR_NOCLEANUP ();
775
775
}
776
776
777
+ HRESULT CLR_RT_HeapBlock::Reassign (CLR_RT_HeapBlock &rhs, const CLR_RT_TypeDef_Instance &expectedType)
778
+ {
779
+ NATIVE_PROFILE_CLR_CORE ();
780
+ NANOCLR_HEADER ();
781
+
782
+ // Build a TypeDescriptor for the *expected* type (the IL TypeSpec/TypeDef)
783
+ CLR_RT_TypeDescriptor descExpected;
784
+ NANOCLR_CHECK_HRESULT (descExpected.InitializeFromTypeDef (expectedType));
785
+
786
+ // Build a TypeDescriptor for the *actual* runtime object in rhs
787
+ CLR_RT_TypeDescriptor descActual;
788
+ NANOCLR_CHECK_HRESULT (descActual.InitializeFromObject (rhs));
789
+
790
+ // Compare them (including generics, arrays, value-types, etc.)
791
+ if (!TypeDescriptorsMatch (descExpected, descActual))
792
+ {
793
+ NANOCLR_SET_AND_LEAVE (CLR_E_WRONG_TYPE);
794
+ }
795
+
796
+ // They match: now do the actual copy
797
+ // - reference types & arrays: copy the object reference
798
+ // - value-types & primitives: copy the raw data
799
+ switch (descActual.GetDataType ())
800
+ {
801
+ case DATATYPE_CLASS:
802
+ case DATATYPE_SZARRAY:
803
+ {
804
+ // object reference or single-dim array
805
+ this ->Assign (rhs);
806
+ break ;
807
+ }
808
+
809
+ default :
810
+ {
811
+ // value-type, primitive, struct, etc.
812
+ // this->CopyFrom(rhs);
813
+ break ;
814
+ }
815
+ }
816
+
817
+ NANOCLR_NOCLEANUP ();
818
+ }
819
+
820
+ bool CLR_RT_HeapBlock::TypeDescriptorsMatch (
821
+ const CLR_RT_TypeDescriptor &expectedType,
822
+ const CLR_RT_TypeDescriptor &actualType)
823
+ {
824
+ // Figure out logical DataTypes, promoting ACTUAL CLASS ---> GENERICINST
825
+ NanoCLRDataType expectedDataType = expectedType.GetDataType ();
826
+ NanoCLRDataType actualDataType = actualType.GetDataType ();
827
+
828
+ // If the *actual* object is a closed-generic (even though boxed as CLASS),
829
+ // it will have m_handlerGenericType set. Promote it to GENERICINST.
830
+ if (actualDataType == DATATYPE_CLASS && actualType.m_handlerGenericType .data != CLR_EmptyToken)
831
+ {
832
+ actualDataType = DATATYPE_GENERICINST;
833
+ }
834
+
835
+ // If either side is GENERICINST, we do generic-inst matching
836
+ if (expectedDataType == DATATYPE_GENERICINST || actualDataType == DATATYPE_GENERICINST)
837
+ {
838
+ auto &eSpec = expectedType.m_handlerGenericType ;
839
+ auto &aSpec = actualType.m_handlerGenericType ;
840
+
841
+ return eSpec.Assembly () == aSpec.Assembly () && eSpec.typeDefIndex == aSpec.typeDefIndex ;
842
+ }
843
+
844
+ if (actualDataType <= DATATYPE_LAST_PRIMITIVE_TO_PRESERVE)
845
+ {
846
+ // If they declared a true valuetype, match directly:
847
+ if (expectedDataType == DATATYPE_VALUETYPE)
848
+ {
849
+ const auto &dtl = c_CLR_RT_DataTypeLookup[actualDataType];
850
+ if (dtl.m_cls && dtl.m_cls ->data == expectedType.m_handlerCls .data )
851
+ {
852
+ return true ;
853
+ }
854
+ }
855
+ // if they declared a boxed struct (CLASS whose TypeDef is a struct),
856
+ // need to match that too:
857
+ else if (expectedDataType == DATATYPE_CLASS && expectedType.m_handlerGenericType .data == 0 )
858
+ {
859
+ // Look up the TypeDef record flags to see if it's a VALUE-TYPE.
860
+ CLR_RT_TypeDef_Index clsIdx = expectedType.m_handlerCls ;
861
+
862
+ // fetch the owning assembly
863
+ CLR_RT_Assembly *ownerAsm = g_CLR_RT_TypeSystem.m_assemblies [clsIdx.Assembly () - 1 ];
864
+ const CLR_RECORD_TYPEDEF *rec = ownerAsm->GetTypeDef (clsIdx.Type ());
865
+
866
+ if (rec &&
867
+ ((rec->flags & CLR_RECORD_TYPEDEF::TD_Semantics_Mask) == CLR_RECORD_TYPEDEF::TD_Semantics_ValueType))
868
+ {
869
+ const auto &dtl = c_CLR_RT_DataTypeLookup[actualDataType];
870
+ if (dtl.m_cls && dtl.m_cls ->data == clsIdx.data )
871
+ {
872
+ return true ;
873
+ }
874
+ }
875
+ }
876
+ }
877
+
878
+ // For everything else, DataTypes must line up exactly
879
+ if (expectedDataType != actualDataType)
880
+ {
881
+ return false ;
882
+ }
883
+
884
+ // Dispatch on the remaining kinds
885
+ switch (expectedDataType)
886
+ {
887
+ case DATATYPE_CLASS:
888
+ case DATATYPE_VALUETYPE:
889
+ {
890
+ // compare TypeDef indices
891
+ auto &eCls = expectedType.m_handlerCls ;
892
+ auto &aCls = actualType.m_handlerCls ;
893
+ return eCls.data == aCls.data ;
894
+ }
895
+
896
+ case DATATYPE_SZARRAY:
897
+ {
898
+ // compare outer dims (always 1) then element types
899
+ return TypeDescriptorsMatch (expectedType, actualType);
900
+ }
901
+
902
+ // primitives and other leaf types match on the DataType alone
903
+ default :
904
+ return true ;
905
+ }
906
+ }
907
+
777
908
void CLR_RT_HeapBlock::AssignAndPinReferencedObject (const CLR_RT_HeapBlock &value)
778
909
{
779
910
// This is very special case that we have local variable with pinned attribute in metadata.
@@ -787,7 +918,7 @@ void CLR_RT_HeapBlock::AssignAndPinReferencedObject(const CLR_RT_HeapBlock &valu
787
918
m_data.objectReference .ptr ->Unpin ();
788
919
}
789
920
790
- // Move the data.
921
+ // Move the data
791
922
m_data = value.m_data ;
792
923
793
924
// Leave the same logic as in AssignAndPreserveType
0 commit comments