@@ -2142,6 +2142,7 @@ static void performBasicLayout(TypeLayout &layout,
2142
2142
size_t alignMask = layout.flags .getAlignmentMask ();
2143
2143
bool isPOD = layout.flags .isPOD ();
2144
2144
bool isBitwiseTakable = layout.flags .isBitwiseTakable ();
2145
+ bool isBitwiseBorrowable = layout.flags .isBitwiseBorrowable ();
2145
2146
for (unsigned i = 0 ; i != numElements; ++i) {
2146
2147
auto &elt = elements[i];
2147
2148
@@ -2157,6 +2158,7 @@ static void performBasicLayout(TypeLayout &layout,
2157
2158
alignMask = std::max (alignMask, eltLayout->flags .getAlignmentMask ());
2158
2159
if (!eltLayout->flags .isPOD ()) isPOD = false ;
2159
2160
if (!eltLayout->flags .isBitwiseTakable ()) isBitwiseTakable = false ;
2161
+ if (!eltLayout->flags .isBitwiseBorrowable ()) isBitwiseBorrowable = false ;
2160
2162
}
2161
2163
bool isInline =
2162
2164
ValueWitnessTable::isValueInline (isBitwiseTakable, size, alignMask + 1 );
@@ -2166,6 +2168,7 @@ static void performBasicLayout(TypeLayout &layout,
2166
2168
.withAlignmentMask (alignMask)
2167
2169
.withPOD (isPOD)
2168
2170
.withBitwiseTakable (isBitwiseTakable)
2171
+ .withBitwiseBorrowable (isBitwiseBorrowable)
2169
2172
.withInlineStorage (isInline);
2170
2173
layout.extraInhabitantCount = 0 ;
2171
2174
layout.stride = std::max (size_t (1 ), roundUpToAlignMask (size, alignMask));
@@ -3050,7 +3053,9 @@ void swift::swift_initRawStructMetadata(StructMetadata *structType,
3050
3053
vwtable->stride = stride;
3051
3054
vwtable->flags = ValueWitnessFlags ()
3052
3055
.withAlignmentMask (alignMask)
3053
- .withCopyable (false );
3056
+ .withCopyable (false )
3057
+ .withBitwiseTakable (true )
3058
+ .withBitwiseBorrowable (false );
3054
3059
vwtable->extraInhabitantCount = extraInhabitantCount;
3055
3060
}
3056
3061
@@ -3090,6 +3095,9 @@ void swift::swift_initRawStructMetadata2(StructMetadata *structType,
3090
3095
vwtable->flags = vwtable->flags
3091
3096
.withBitwiseTakable (likeTypeLayout->flags .isBitwiseTakable ());
3092
3097
}
3098
+
3099
+ vwtable->flags = vwtable->flags
3100
+ .withBitwiseBorrowable (isRawLayoutBitwiseBorrowable (rawLayoutFlags));
3093
3101
3094
3102
// If the calculated size of this raw layout type is available to be put in
3095
3103
// value buffers, then set the inline storage bit if our like type is also
@@ -4454,27 +4462,44 @@ class ExistentialCacheEntry {
4454
4462
4455
4463
class OpaqueExistentialValueWitnessTableCacheEntry {
4456
4464
public:
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
+
4457
4475
ValueWitnessTable Data;
4458
4476
4459
- OpaqueExistentialValueWitnessTableCacheEntry (unsigned numTables );
4477
+ OpaqueExistentialValueWitnessTableCacheEntry (Key key );
4460
4478
4461
4479
unsigned getNumWitnessTables () const {
4462
4480
return (Data.size - sizeof (OpaqueExistentialContainer))
4463
4481
/ sizeof (const WitnessTable *);
4464
4482
}
4483
+
4484
+ bool isCopyable () const {
4485
+ return Data.flags .isCopyable ();
4486
+ }
4465
4487
4466
4488
intptr_t getKeyIntValueForDump () {
4467
4489
return getNumWitnessTables ();
4468
4490
}
4469
4491
4470
- bool matchesKey (unsigned key) const { return key == getNumWitnessTables (); }
4492
+ bool matchesKey (Key key) const {
4493
+ return key == Key{getNumWitnessTables (), isCopyable ()};
4494
+ }
4471
4495
4472
4496
friend llvm::hash_code
4473
4497
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 ()));
4475
4500
}
4476
4501
4477
- static size_t getExtraAllocationSize (unsigned numTables ) {
4502
+ static size_t getExtraAllocationSize (Key key ) {
4478
4503
return 0 ;
4479
4504
}
4480
4505
size_t getExtraAllocationSize () const {
@@ -4562,19 +4587,24 @@ OpaqueExistentialValueWitnessTables;
4562
4587
// / Instantiate a value witness table for an opaque existential container with
4563
4588
// / the given number of witness table pointers.
4564
4589
static const ValueWitnessTable *
4565
- getOpaqueExistentialValueWitnesses (unsigned numWitnessTables) {
4590
+ getOpaqueExistentialValueWitnesses (unsigned numWitnessTables,
4591
+ bool copyable) {
4566
4592
// 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
+ }
4571
4599
4572
- return &OpaqueExistentialValueWitnessTables.getOrInsert (numWitnessTables)
4573
- .first ->Data ;
4600
+ return &OpaqueExistentialValueWitnessTables
4601
+ .getOrInsert (OpaqueExistentialValueWitnessTableCacheEntry::Key{
4602
+ numWitnessTables, copyable})
4603
+ .first ->Data ;
4574
4604
}
4575
4605
4576
4606
OpaqueExistentialValueWitnessTableCacheEntry::
4577
- OpaqueExistentialValueWitnessTableCacheEntry (unsigned numWitnessTables ) {
4607
+ OpaqueExistentialValueWitnessTableCacheEntry (Key key ) {
4578
4608
using Box = NonFixedOpaqueExistentialBox;
4579
4609
using Witnesses = NonFixedValueWitnesses<Box, /* known allocated*/ true >;
4580
4610
@@ -4584,16 +4614,24 @@ OpaqueExistentialValueWitnessTableCacheEntry(unsigned numWitnessTables) {
4584
4614
#define DATA_VALUE_WITNESS (LOWER_ID, UPPER_ID, TYPE )
4585
4615
#include " swift/ABI/ValueWitness.def"
4586
4616
4587
- Data.size = Box::Container::getSize (numWitnessTables);
4617
+ Data.size = Box::Container::getSize (key. numWitnessTables );
4588
4618
Data.flags = ValueWitnessFlags ()
4589
- .withAlignment (Box::Container::getAlignment (numWitnessTables))
4619
+ .withAlignment (Box::Container::getAlignment (key. numWitnessTables ))
4590
4620
.withPOD (false )
4591
4621
.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 );
4593
4630
Data.extraInhabitantCount = Witnesses::numExtraInhabitants;
4594
- Data.stride = Box::Container::getStride (numWitnessTables);
4631
+ Data.stride = Box::Container::getStride (key. numWitnessTables );
4595
4632
4596
- assert (getNumWitnessTables () == numWitnessTables);
4633
+ assert (getNumWitnessTables () == key.numWitnessTables );
4634
+ assert (isCopyable () == key.copyable );
4597
4635
}
4598
4636
4599
4637
static const ValueWitnessTable ClassExistentialValueWitnesses_1 =
@@ -4662,7 +4700,8 @@ static const ValueWitnessTable *
4662
4700
getExistentialValueWitnesses (ProtocolClassConstraint classConstraint,
4663
4701
const Metadata *superclassConstraint,
4664
4702
unsigned numWitnessTables,
4665
- SpecialProtocol special) {
4703
+ SpecialProtocol special,
4704
+ bool copyable) {
4666
4705
// Use special representation for special protocols.
4667
4706
switch (special) {
4668
4707
case SpecialProtocol::Error:
@@ -4685,7 +4724,7 @@ getExistentialValueWitnesses(ProtocolClassConstraint classConstraint,
4685
4724
numWitnessTables);
4686
4725
case ProtocolClassConstraint::Any:
4687
4726
assert (superclassConstraint == nullptr );
4688
- return getOpaqueExistentialValueWitnesses (numWitnessTables);
4727
+ return getOpaqueExistentialValueWitnesses (numWitnessTables, copyable );
4689
4728
}
4690
4729
4691
4730
swift_unreachable (" Unhandled ProtocolClassConstraint in switch." );
@@ -4928,7 +4967,8 @@ ExistentialCacheEntry::ExistentialCacheEntry(Key key) {
4928
4967
Data.ValueWitnesses = getExistentialValueWitnesses (key.ClassConstraint ,
4929
4968
key.SuperclassConstraint ,
4930
4969
numWitnessTables,
4931
- special);
4970
+ special,
4971
+ /* copyable*/ true );
4932
4972
Data.Flags = ExistentialTypeFlags ()
4933
4973
.withNumWitnessTables (numWitnessTables)
4934
4974
.withClassConstraint (key.ClassConstraint )
@@ -5164,6 +5204,7 @@ class ExtendedExistentialTypeCacheEntry {
5164
5204
const ValueWitnessTable *
5165
5205
ExtendedExistentialTypeCacheEntry::getOrCreateVWT (Key key) {
5166
5206
auto shape = key.Shape ;
5207
+ bool copyable = shape->isCopyable ();
5167
5208
5168
5209
if (auto witnesses = shape->getSuggestedValueWitnesses ())
5169
5210
return witnesses;
@@ -5202,7 +5243,8 @@ ExtendedExistentialTypeCacheEntry::getOrCreateVWT(Key key) {
5202
5243
return getExistentialValueWitnesses (ProtocolClassConstraint::Any,
5203
5244
/* superclass*/ nullptr ,
5204
5245
wtableStorageSizeInWords,
5205
- SpecialProtocol::None);
5246
+ SpecialProtocol::None,
5247
+ copyable);
5206
5248
5207
5249
case SpecialKind::ExplicitLayout:
5208
5250
swift_unreachable (" shape with explicit layout but no suggested VWT" );
@@ -5214,7 +5256,8 @@ ExtendedExistentialTypeCacheEntry::getOrCreateVWT(Key key) {
5214
5256
return getExistentialValueWitnesses (ProtocolClassConstraint::Class,
5215
5257
/* superclass*/ nullptr ,
5216
5258
wtableStorageSizeInWords,
5217
- SpecialProtocol::None);
5259
+ SpecialProtocol::None,
5260
+ /* copyable*/ true );
5218
5261
5219
5262
case SpecialKind::Metatype:
5220
5263
// Existential metatypes don't store type metadata.
0 commit comments