@@ -663,12 +663,27 @@ static void _maybeDeallocateOpaqueExistential(OpaqueValue *srcExistential,
663
663
}
664
664
}
665
665
666
+ static bool
667
+ isAnyObjectExistentialType (const ExistentialTypeMetadata *targetType) {
668
+ unsigned numProtos = targetType->Protocols .NumProtocols ;
669
+ if (numProtos != 1 )
670
+ return false ;
671
+ const ProtocolDescriptor *protocol = targetType->Protocols [0 ];
672
+ bool isAnyObjectProtocol =
673
+ protocol->Flags .getSpecialProtocol () == SpecialProtocol::AnyObject;
674
+ // Assert that AnyObject does not need any witness tables. We rely on this.
675
+ assert (!isAnyObjectProtocol || !protocol->Flags .needsWitnessTable () &&
676
+ " AnyObject should not require witness tables" );
677
+ return isAnyObjectProtocol;
678
+ }
679
+
666
680
// / Given a possibly-existential value, find its dynamic type and the
667
681
// / address of its storage.
668
- static void findDynamicValueAndType (OpaqueValue *value, const Metadata *type,
669
- OpaqueValue *&outValue,
670
- const Metadata *&outType,
671
- bool &inoutCanTake) {
682
+ static void
683
+ findDynamicValueAndType (OpaqueValue *value, const Metadata *type,
684
+ OpaqueValue *&outValue, const Metadata *&outType,
685
+ bool &inoutCanTake,
686
+ bool isTargetTypeAnyObject) {
672
687
switch (type->getKind ()) {
673
688
case MetadataKind::Class:
674
689
case MetadataKind::ObjCClassWrapper:
@@ -696,12 +711,23 @@ static void findDynamicValueAndType(OpaqueValue *value, const Metadata *type,
696
711
697
712
case ExistentialTypeRepresentation::Opaque:
698
713
case ExistentialTypeRepresentation::ErrorProtocol: {
714
+ const Metadata *innerType = existentialType->getDynamicType (value);
715
+
716
+ // Short cut class in existential as AnyObject casts.
717
+ if (isTargetTypeAnyObject &&
718
+ innerType->getKind () == MetadataKind::Class) {
719
+ // inline value buffer storage.
720
+ outValue = value;
721
+ outType = 0 ;
722
+ inoutCanTake= true ;
723
+ return ;
724
+ }
699
725
OpaqueValue *innerValue
700
726
= existentialType->projectValue (value);
701
- const Metadata *innerType = existentialType->getDynamicType (value);
702
727
inoutCanTake &= existentialType->mayTakeValue (value);
728
+
703
729
return findDynamicValueAndType (innerValue, innerType,
704
- outValue, outType, inoutCanTake);
730
+ outValue, outType, inoutCanTake, false );
705
731
}
706
732
}
707
733
}
@@ -736,7 +762,7 @@ swift::swift_getDynamicType(OpaqueValue *value, const Metadata *self) {
736
762
OpaqueValue *outValue;
737
763
const Metadata *outType;
738
764
bool canTake = false ;
739
- findDynamicValueAndType (value, self, outValue, outType, canTake);
765
+ findDynamicValueAndType (value, self, outValue, outType, canTake, false );
740
766
return outType;
741
767
}
742
768
@@ -876,8 +902,17 @@ static bool _dynamicCastToExistential(OpaqueValue *dest,
876
902
OpaqueValue *srcDynamicValue;
877
903
const Metadata *srcDynamicType;
878
904
bool canTake = true ;
905
+
906
+ // Are we casting to AnyObject? In this case we can fast-path casts from
907
+ // classes.
908
+ bool isTargetTypeAnyObject =
909
+ targetType->getKind () == MetadataKind::Existential &&
910
+ isAnyObjectExistentialType (targetType);
911
+
912
+ // We don't care what the target type of a cast from class to AnyObject is.
913
+ // srcDynamicType will be set to a nullptr in this case to save a lookup.
879
914
findDynamicValueAndType (src, srcType, srcDynamicValue, srcDynamicType,
880
- canTake);
915
+ canTake, isTargetTypeAnyObject );
881
916
882
917
auto maybeDeallocateSourceAfterSuccess = [&] {
883
918
if (shouldDeallocateSource (/* succeeded*/ true , flags)) {
@@ -897,10 +932,12 @@ static bool _dynamicCastToExistential(OpaqueValue *dest,
897
932
case ExistentialTypeRepresentation::Class: {
898
933
auto destExistential =
899
934
reinterpret_cast <ClassExistentialContainer*>(dest);
935
+ MetadataKind kind =
936
+ srcDynamicType ? srcDynamicType->getKind () : MetadataKind::Class;
900
937
901
938
// If the source type is a value type, it cannot possibly conform
902
939
// to a class-bounded protocol.
903
- switch (srcDynamicType-> getKind () ) {
940
+ switch (kind ) {
904
941
case MetadataKind::ExistentialMetatype:
905
942
case MetadataKind::Metatype: {
906
943
#if SWIFT_OBJC_INTEROP
@@ -965,8 +1002,11 @@ static bool _dynamicCastToExistential(OpaqueValue *dest,
965
1002
return _fail (src, srcType, targetType, flags);
966
1003
}
967
1004
968
- // Check for protocol conformances and fill in the witness tables.
969
- if (!_conformsToProtocols (srcDynamicValue, srcDynamicType,
1005
+ // Check for protocol conformances and fill in the witness tables. If
1006
+ // srcDynamicType equals nullptr we have a cast from an existential
1007
+ // container with a class instance to AnyObject. In this case no check is
1008
+ // necessary.
1009
+ if (srcDynamicType && !_conformsToProtocols (srcDynamicValue, srcDynamicType,
970
1010
targetType->Protocols ,
971
1011
destExistential->getWitnessTables ())) {
972
1012
return _fail (src, srcType, targetType, flags, srcDynamicType);
0 commit comments