@@ -711,176 +711,32 @@ class ReflectionContext
711
711
}
712
712
}
713
713
714
+ // / Projects the value of an enum.
715
+ // /
716
+ // / Takes the address and typeref for an enum and determines the
717
+ // / index of the currently-selected case within the enum.
718
+ // / You can use this index with `swift_reflection_childOfTypeRef`
719
+ // / to get detailed information about the specific case.
720
+ // /
721
+ // / Returns true if the enum case could be successfully determined. In
722
+ // / particular, note that this code may return false for valid in-memory data
723
+ // / if the compiler used a strategy we do not yet understand.
714
724
bool projectEnumValue (RemoteAddress EnumAddress,
715
725
const TypeRef *EnumTR,
716
726
int *CaseIndex) {
717
- if (EnumTR == nullptr )
727
+ // Get the TypeInfo and sanity-check it
728
+ if (EnumTR == nullptr ) {
718
729
return false ;
719
- auto EnumTI = getTypeInfo (EnumTR);
720
- if (EnumTI == nullptr )
721
- return false ;
722
-
723
- auto EnumRecordTI = dyn_cast<const RecordTypeInfo>(EnumTI);
724
- if (EnumRecordTI == nullptr )
725
- return false ;
726
- auto EnumSize = EnumRecordTI->getSize ();
727
-
728
- auto Fields = EnumRecordTI->getFields ();
729
- auto FieldCount = Fields.size ();
730
- if (FieldCount == 0 ) {
731
- return false ; // No fields?
732
- }
733
- if (FieldCount == 1 ) {
734
- *CaseIndex = 0 ; // Only possible field
735
- return true ;
736
- }
737
-
738
- switch (EnumRecordTI->getRecordKind ()) {
739
-
740
- case RecordKind::NoPayloadEnum: {
741
- if (EnumSize == 0 ) {
742
- *CaseIndex = 0 ;
743
- return true ;
744
- }
745
- return getReader ().readInteger (EnumAddress, EnumSize, CaseIndex);
746
- }
747
-
748
- case RecordKind::SinglePayloadEnum: {
749
- FieldInfo PayloadCase = Fields[0 ];
750
- if (!PayloadCase.TR )
751
- return false ;
752
- unsigned long NonPayloadCaseCount = FieldCount - 1 ;
753
- unsigned long PayloadExtraInhabitants = PayloadCase.TI .getNumExtraInhabitants ();
754
- unsigned Discriminator = 0 ;
755
- auto PayloadSize = PayloadCase.TI .getSize ();
756
- if (NonPayloadCaseCount >= PayloadExtraInhabitants) {
757
- // There are more cases than inhabitants, we need a separate discriminator.
758
- auto TagInfo = getEnumTagCounts (PayloadSize, NonPayloadCaseCount, 1 );
759
- auto TagSize = TagInfo.numTagBytes ;
760
- auto TagAddress = RemoteAddress (EnumAddress.getAddressData () + PayloadSize);
761
- if (!getReader ().readInteger (TagAddress, TagSize, &Discriminator)) {
762
- printf (" >>>> readXI failed to read discriminator\n\n " );
763
- return false ;
764
- }
765
- }
766
-
767
- if (PayloadSize == 0 ) {
768
- // Payload carries no information, so discriminator fully determines the case
769
- *CaseIndex = Discriminator;
770
- return true ;
771
- } else if (Discriminator == 0 ) {
772
- // The payload area carries all the information...
773
- if (PayloadExtraInhabitants == 0 ) {
774
- *CaseIndex = 0 ;
775
- return true ;
776
- }
777
- int XITag = 0 ;
778
- if (!PayloadCase.TI .readExtraInhabitantIndex (getReader (), EnumAddress, &XITag)) {
779
- return false ;
780
- }
781
- if (XITag < 0 ) { // Valid (not extra) inhabitant
782
- *CaseIndex = 0 ; // Payload case is always #0
783
- return true ;
784
- } else if ((unsigned )XITag <= NonPayloadCaseCount) {
785
- *CaseIndex = XITag + 1 ;
786
- return true ;
787
- }
788
- return false ;
789
- } else {
790
- // No payload: Payload area is reused for more cases
791
- uint32_t PayloadTag = 0 ;
792
- auto PayloadTagSize = std::min (PayloadSize, decltype (PayloadSize)(sizeof (PayloadTag)));
793
- if (!getReader ().readInteger (EnumAddress, PayloadTagSize, &PayloadTag)) {
794
- return false ;
795
- }
796
- auto XICases = 1U + PayloadExtraInhabitants; // Cases coded with XIs when discriminator = 0
797
- auto PayloadCases = 1U << (PayloadTagSize * 8U );
798
- *CaseIndex = XICases + (Discriminator - 1 ) * PayloadCases + PayloadTag;
799
- return true ;
800
- }
801
730
}
802
-
803
- case RecordKind::MultiPayloadEnum: {
804
- // Collect basic statistics about the enum
805
- unsigned long PayloadCaseCount = 0 ;
806
- unsigned long NonPayloadCaseCount = 0 ;
807
- unsigned long PayloadSize = 0 ;
808
- for (auto Field : Fields) {
809
- if (Field.TR != 0 ) {
810
- PayloadCaseCount += 1 ;
811
- if (Field.TI .getSize () > PayloadSize) {
812
- PayloadSize = Field.TI .getSize ();
813
- }
814
- } else {
815
- NonPayloadCaseCount += 1 ;
816
- }
817
- }
818
- if (EnumSize > PayloadSize) {
819
- // If the compiler laid this out with a separate tag, use that.
820
- unsigned tag = 0 ;
821
- auto TagSize = EnumSize - PayloadSize;
822
- auto TagAddress = remote::RemoteAddress (EnumAddress.getAddressData () + PayloadSize);
823
- if (!getReader ().readInteger (TagAddress, TagSize, &tag)
824
- || tag >= Fields.size ()) {
825
- return false ;
826
- }
827
- if (tag < PayloadCaseCount) {
828
- *CaseIndex = tag;
829
- return true ;
830
- }
831
- auto PayloadTagSize = std::min (PayloadSize, 4UL );
832
- // Treat the tag as a page selector; payload carries the offset within the page
833
- auto Page = tag - PayloadCaseCount;
834
- // Zero for 32-bit because we'll never have more than one page
835
- auto PageSize = PayloadTagSize >= 4 ? 0 : 1 << (PayloadSize * 8U );
836
- auto PageStart = Page * PageSize;
837
- unsigned PayloadTag;
838
- if (!getReader ().readInteger (EnumAddress, PayloadTagSize, &PayloadTag)) {
839
- return false ;
840
- }
841
- *CaseIndex = PageStart + PayloadTag + PayloadCaseCount;
842
- return true ;
843
- } else {
844
- // XXX TODO: If the payloads have common spare bits (e.g., all pointers)
845
- // then use those to decode the case.
846
- return false ;
847
- }
848
- break ;
849
- }
850
-
851
- default :
852
- // Unknown record kind.
853
- break ;
854
- }
855
- return false ;
856
- }
857
-
858
- bool getEnumCaseTypeRef (const TypeRef *EnumTR,
859
- unsigned CaseIndex,
860
- std::string &Name,
861
- const TypeRef **OutPayloadTR) {
862
- *OutPayloadTR = nullptr ;
863
-
864
- if (EnumTR == nullptr )
865
- return false ;
866
-
867
- auto EnumTI = getTypeInfo (EnumTR);
868
- if (EnumTI == nullptr )
731
+ auto TI = getTypeInfo (EnumTR);
732
+ if (TI == nullptr ) {
869
733
return false ;
870
-
871
- auto EnumRecordTI = dyn_cast<const RecordTypeInfo>(EnumTI);
872
- if (EnumRecordTI == nullptr )
873
- return false ;
874
-
875
- auto NumCases = EnumRecordTI->getNumFields ();
876
- if (CaseIndex >= NumCases) {
734
+ }
735
+ auto EnumTI = dyn_cast<const EnumTypeInfo>(TI);
736
+ if (EnumTI == nullptr ){
877
737
return false ;
878
- } else {
879
- const auto Case = EnumRecordTI->getFields ()[CaseIndex];
880
- Name = Case.Name ;
881
- *OutPayloadTR = Case.TR ;
882
- return true ;
883
738
}
739
+ return EnumTI->projectEnumValue (getReader (), EnumAddress, CaseIndex);
884
740
}
885
741
886
742
// / Return a description of the layout of a value with the given type.
0 commit comments