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