@@ -2142,6 +2142,7 @@ static void performBasicLayout(TypeLayout &layout,
21422142 size_t alignMask = layout.flags .getAlignmentMask ();
21432143 bool isPOD = layout.flags .isPOD ();
21442144 bool isBitwiseTakable = layout.flags .isBitwiseTakable ();
2145+ bool isBitwiseBorrowable = layout.flags .isBitwiseBorrowable ();
21452146 for (unsigned i = 0 ; i != numElements; ++i) {
21462147 auto &elt = elements[i];
21472148
@@ -2157,6 +2158,7 @@ static void performBasicLayout(TypeLayout &layout,
21572158 alignMask = std::max (alignMask, eltLayout->flags .getAlignmentMask ());
21582159 if (!eltLayout->flags .isPOD ()) isPOD = false ;
21592160 if (!eltLayout->flags .isBitwiseTakable ()) isBitwiseTakable = false ;
2161+ if (!eltLayout->flags .isBitwiseBorrowable ()) isBitwiseBorrowable = false ;
21602162 }
21612163 bool isInline =
21622164 ValueWitnessTable::isValueInline (isBitwiseTakable, size, alignMask + 1 );
@@ -2166,6 +2168,7 @@ static void performBasicLayout(TypeLayout &layout,
21662168 .withAlignmentMask (alignMask)
21672169 .withPOD (isPOD)
21682170 .withBitwiseTakable (isBitwiseTakable)
2171+ .withBitwiseBorrowable (isBitwiseBorrowable)
21692172 .withInlineStorage (isInline);
21702173 layout.extraInhabitantCount = 0 ;
21712174 layout.stride = std::max (size_t (1 ), roundUpToAlignMask (size, alignMask));
@@ -3050,7 +3053,9 @@ void swift::swift_initRawStructMetadata(StructMetadata *structType,
30503053 vwtable->stride = stride;
30513054 vwtable->flags = ValueWitnessFlags ()
30523055 .withAlignmentMask (alignMask)
3053- .withCopyable (false );
3056+ .withCopyable (false )
3057+ .withBitwiseTakable (true )
3058+ .withBitwiseBorrowable (false );
30543059 vwtable->extraInhabitantCount = extraInhabitantCount;
30553060}
30563061
@@ -3090,6 +3095,9 @@ void swift::swift_initRawStructMetadata2(StructMetadata *structType,
30903095 vwtable->flags = vwtable->flags
30913096 .withBitwiseTakable (likeTypeLayout->flags .isBitwiseTakable ());
30923097 }
3098+
3099+ vwtable->flags = vwtable->flags
3100+ .withBitwiseBorrowable (isRawLayoutBitwiseBorrowable (rawLayoutFlags));
30933101
30943102 // If the calculated size of this raw layout type is available to be put in
30953103 // value buffers, then set the inline storage bit if our like type is also
@@ -4454,27 +4462,44 @@ class ExistentialCacheEntry {
44544462
44554463class OpaqueExistentialValueWitnessTableCacheEntry {
44564464public:
4465+ struct Key {
4466+ unsigned numWitnessTables : 31 ;
4467+ unsigned copyable : 1 ;
4468+
4469+ bool operator ==(struct Key k) {
4470+ return k.numWitnessTables == numWitnessTables
4471+ && k.copyable == copyable;
4472+ }
4473+ };
4474+
44574475 ValueWitnessTable Data;
44584476
4459- OpaqueExistentialValueWitnessTableCacheEntry (unsigned numTables );
4477+ OpaqueExistentialValueWitnessTableCacheEntry (Key key );
44604478
44614479 unsigned getNumWitnessTables () const {
44624480 return (Data.size - sizeof (OpaqueExistentialContainer))
44634481 / sizeof (const WitnessTable *);
44644482 }
4483+
4484+ bool isCopyable () const {
4485+ return Data.flags .isCopyable ();
4486+ }
44654487
44664488 intptr_t getKeyIntValueForDump () {
44674489 return getNumWitnessTables ();
44684490 }
44694491
4470- bool matchesKey (unsigned key) const { return key == getNumWitnessTables (); }
4492+ bool matchesKey (Key key) const {
4493+ return key == Key{getNumWitnessTables (), isCopyable ()};
4494+ }
44714495
44724496 friend llvm::hash_code
44734497 hash_value (const OpaqueExistentialValueWitnessTableCacheEntry &value) {
4474- return llvm::hash_value (value.getNumWitnessTables ());
4498+ return llvm::hash_value (
4499+ std::make_pair (value.getNumWitnessTables (), value.isCopyable ()));
44754500 }
44764501
4477- static size_t getExtraAllocationSize (unsigned numTables ) {
4502+ static size_t getExtraAllocationSize (Key key ) {
44784503 return 0 ;
44794504 }
44804505 size_t getExtraAllocationSize () const {
@@ -4562,19 +4587,24 @@ OpaqueExistentialValueWitnessTables;
45624587// / Instantiate a value witness table for an opaque existential container with
45634588// / the given number of witness table pointers.
45644589static const ValueWitnessTable *
4565- getOpaqueExistentialValueWitnesses (unsigned numWitnessTables) {
4590+ getOpaqueExistentialValueWitnesses (unsigned numWitnessTables,
4591+ bool copyable) {
45664592 // We pre-allocate a couple of important cases.
4567- if (numWitnessTables == 0 )
4568- return &OpaqueExistentialValueWitnesses_0;
4569- if (numWitnessTables == 1 )
4570- return &OpaqueExistentialValueWitnesses_1;
4593+ if (copyable) {
4594+ if (numWitnessTables == 0 )
4595+ return &OpaqueExistentialValueWitnesses_0;
4596+ if (numWitnessTables == 1 )
4597+ return &OpaqueExistentialValueWitnesses_1;
4598+ }
45714599
4572- return &OpaqueExistentialValueWitnessTables.getOrInsert (numWitnessTables)
4573- .first ->Data ;
4600+ return &OpaqueExistentialValueWitnessTables
4601+ .getOrInsert (OpaqueExistentialValueWitnessTableCacheEntry::Key{
4602+ numWitnessTables, copyable})
4603+ .first ->Data ;
45744604}
45754605
45764606OpaqueExistentialValueWitnessTableCacheEntry::
4577- OpaqueExistentialValueWitnessTableCacheEntry (unsigned numWitnessTables ) {
4607+ OpaqueExistentialValueWitnessTableCacheEntry (Key key ) {
45784608 using Box = NonFixedOpaqueExistentialBox;
45794609 using Witnesses = NonFixedValueWitnesses<Box, /* known allocated*/ true >;
45804610
@@ -4584,16 +4614,24 @@ OpaqueExistentialValueWitnessTableCacheEntry(unsigned numWitnessTables) {
45844614#define DATA_VALUE_WITNESS (LOWER_ID, UPPER_ID, TYPE )
45854615#include " swift/ABI/ValueWitness.def"
45864616
4587- Data.size = Box::Container::getSize (numWitnessTables);
4617+ Data.size = Box::Container::getSize (key. numWitnessTables );
45884618 Data.flags = ValueWitnessFlags ()
4589- .withAlignment (Box::Container::getAlignment (numWitnessTables))
4619+ .withAlignment (Box::Container::getAlignment (key. numWitnessTables ))
45904620 .withPOD (false )
45914621 .withBitwiseTakable (true )
4592- .withInlineStorage (false );
4622+ .withInlineStorage (false )
4623+ .withCopyable (key.copyable )
4624+ // Non-bitwise-takable values are always stored out-of-line in existentials,
4625+ // so the existential representation itself is always bitwise-takable.
4626+ // Noncopyable values however can be bitwise-takable without being
4627+ // bitwise-borrowable, so noncopyable existentials are not bitwise-borrowable
4628+ // in the general case.
4629+ .withBitwiseBorrowable (key.copyable );
45934630 Data.extraInhabitantCount = Witnesses::numExtraInhabitants;
4594- Data.stride = Box::Container::getStride (numWitnessTables);
4631+ Data.stride = Box::Container::getStride (key. numWitnessTables );
45954632
4596- assert (getNumWitnessTables () == numWitnessTables);
4633+ assert (getNumWitnessTables () == key.numWitnessTables );
4634+ assert (isCopyable () == key.copyable );
45974635}
45984636
45994637static const ValueWitnessTable ClassExistentialValueWitnesses_1 =
@@ -4662,7 +4700,8 @@ static const ValueWitnessTable *
46624700getExistentialValueWitnesses (ProtocolClassConstraint classConstraint,
46634701 const Metadata *superclassConstraint,
46644702 unsigned numWitnessTables,
4665- SpecialProtocol special) {
4703+ SpecialProtocol special,
4704+ bool copyable) {
46664705 // Use special representation for special protocols.
46674706 switch (special) {
46684707 case SpecialProtocol::Error:
@@ -4685,7 +4724,7 @@ getExistentialValueWitnesses(ProtocolClassConstraint classConstraint,
46854724 numWitnessTables);
46864725 case ProtocolClassConstraint::Any:
46874726 assert (superclassConstraint == nullptr );
4688- return getOpaqueExistentialValueWitnesses (numWitnessTables);
4727+ return getOpaqueExistentialValueWitnesses (numWitnessTables, copyable );
46894728 }
46904729
46914730 swift_unreachable (" Unhandled ProtocolClassConstraint in switch." );
@@ -4928,7 +4967,8 @@ ExistentialCacheEntry::ExistentialCacheEntry(Key key) {
49284967 Data.ValueWitnesses = getExistentialValueWitnesses (key.ClassConstraint ,
49294968 key.SuperclassConstraint ,
49304969 numWitnessTables,
4931- special);
4970+ special,
4971+ /* copyable*/ true );
49324972 Data.Flags = ExistentialTypeFlags ()
49334973 .withNumWitnessTables (numWitnessTables)
49344974 .withClassConstraint (key.ClassConstraint )
@@ -5164,6 +5204,7 @@ class ExtendedExistentialTypeCacheEntry {
51645204const ValueWitnessTable *
51655205ExtendedExistentialTypeCacheEntry::getOrCreateVWT (Key key) {
51665206 auto shape = key.Shape ;
5207+ bool copyable = shape->isCopyable ();
51675208
51685209 if (auto witnesses = shape->getSuggestedValueWitnesses ())
51695210 return witnesses;
@@ -5202,7 +5243,8 @@ ExtendedExistentialTypeCacheEntry::getOrCreateVWT(Key key) {
52025243 return getExistentialValueWitnesses (ProtocolClassConstraint::Any,
52035244 /* superclass*/ nullptr ,
52045245 wtableStorageSizeInWords,
5205- SpecialProtocol::None);
5246+ SpecialProtocol::None,
5247+ copyable);
52065248
52075249 case SpecialKind::ExplicitLayout:
52085250 swift_unreachable (" shape with explicit layout but no suggested VWT" );
@@ -5214,7 +5256,8 @@ ExtendedExistentialTypeCacheEntry::getOrCreateVWT(Key key) {
52145256 return getExistentialValueWitnesses (ProtocolClassConstraint::Class,
52155257 /* superclass*/ nullptr ,
52165258 wtableStorageSizeInWords,
5217- SpecialProtocol::None);
5259+ SpecialProtocol::None,
5260+ /* copyable*/ true );
52185261
52195262 case SpecialKind::Metatype:
52205263 // Existential metatypes don't store type metadata.
0 commit comments