Skip to content

Commit 5b92b39

Browse files
authored
Merge pull request #3231 from aschwaighofer/fastpath_dynamiccast_anyobject
2 parents 37b7d3d + 8cae987 commit 5b92b39

File tree

1 file changed

+51
-11
lines changed

1 file changed

+51
-11
lines changed

stdlib/public/runtime/Casting.cpp

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -663,12 +663,27 @@ static void _maybeDeallocateOpaqueExistential(OpaqueValue *srcExistential,
663663
}
664664
}
665665

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+
666680
/// Given a possibly-existential value, find its dynamic type and the
667681
/// 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) {
672687
switch (type->getKind()) {
673688
case MetadataKind::Class:
674689
case MetadataKind::ObjCClassWrapper:
@@ -696,12 +711,23 @@ static void findDynamicValueAndType(OpaqueValue *value, const Metadata *type,
696711

697712
case ExistentialTypeRepresentation::Opaque:
698713
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+
}
699725
OpaqueValue *innerValue
700726
= existentialType->projectValue(value);
701-
const Metadata *innerType = existentialType->getDynamicType(value);
702727
inoutCanTake &= existentialType->mayTakeValue(value);
728+
703729
return findDynamicValueAndType(innerValue, innerType,
704-
outValue, outType, inoutCanTake);
730+
outValue, outType, inoutCanTake, false);
705731
}
706732
}
707733
}
@@ -736,7 +762,7 @@ swift::swift_getDynamicType(OpaqueValue *value, const Metadata *self) {
736762
OpaqueValue *outValue;
737763
const Metadata *outType;
738764
bool canTake = false;
739-
findDynamicValueAndType(value, self, outValue, outType, canTake);
765+
findDynamicValueAndType(value, self, outValue, outType, canTake, false);
740766
return outType;
741767
}
742768

@@ -876,8 +902,17 @@ static bool _dynamicCastToExistential(OpaqueValue *dest,
876902
OpaqueValue *srcDynamicValue;
877903
const Metadata *srcDynamicType;
878904
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.
879914
findDynamicValueAndType(src, srcType, srcDynamicValue, srcDynamicType,
880-
canTake);
915+
canTake, isTargetTypeAnyObject);
881916

882917
auto maybeDeallocateSourceAfterSuccess = [&] {
883918
if (shouldDeallocateSource(/*succeeded*/ true, flags)) {
@@ -897,10 +932,12 @@ static bool _dynamicCastToExistential(OpaqueValue *dest,
897932
case ExistentialTypeRepresentation::Class: {
898933
auto destExistential =
899934
reinterpret_cast<ClassExistentialContainer*>(dest);
935+
MetadataKind kind =
936+
srcDynamicType ? srcDynamicType->getKind() : MetadataKind::Class;
900937

901938
// If the source type is a value type, it cannot possibly conform
902939
// to a class-bounded protocol.
903-
switch (srcDynamicType->getKind()) {
940+
switch (kind) {
904941
case MetadataKind::ExistentialMetatype:
905942
case MetadataKind::Metatype: {
906943
#if SWIFT_OBJC_INTEROP
@@ -965,8 +1002,11 @@ static bool _dynamicCastToExistential(OpaqueValue *dest,
9651002
return _fail(src, srcType, targetType, flags);
9661003
}
9671004

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,
9701010
targetType->Protocols,
9711011
destExistential->getWitnessTables())) {
9721012
return _fail(src, srcType, targetType, flags, srcDynamicType);

0 commit comments

Comments
 (0)