> On Jul 28, 2017, at 8:13 PM, John McCall <rjmcc...@apple.com> wrote:
> 
>> On Jul 28, 2017, at 11:11 PM, John McCall via swift-dev <swift-dev@swift.org 
>> <mailto:swift-dev@swift.org>> wrote:
>>> On Jul 28, 2017, at 10:38 PM, Andrew Trick <atr...@apple.com 
>>> <mailto:atr...@apple.com>> wrote:
>>>> On Jul 28, 2017, at 3:15 PM, John McCall <rjmcc...@apple.com 
>>>> <mailto:rjmcc...@apple.com>> wrote:
>>>>> On Jul 28, 2017, at 6:02 PM, Andrew Trick via swift-dev 
>>>>> <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:
>>>>> 
>>>>> 
>>>>>> On Jul 28, 2017, at 2:20 PM, Joe Groff via swift-dev 
>>>>>> <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:
>>>>>> 
>>>>>> The Swift runtime currently maintains globally unique pointer identities 
>>>>>> for type metadata and protocol conformances. This makes checking type 
>>>>>> equivalence a trivial pointer equality comparison, but most operations 
>>>>>> on generic values do not really care about exact type identity and only 
>>>>>> need to invoke value or protocol witness methods or consult other data 
>>>>>> in the type metadata structure. I think it's worth reevaluating whether 
>>>>>> having globally unique type metadata objects is the correct design 
>>>>>> choice. Maintaining global uniqueness of metadata instances carries a 
>>>>>> number of costs. Any code that wants type metadata for an instance of a 
>>>>>> generic type, even a fully concrete one, must make a potentially 
>>>>>> expensive runtime call to get the canonical metadata instance. This also 
>>>>>> greatly complicates our ability to emit specializations of type 
>>>>>> metadata, value witness tables, or protocol witness tables for concrete 
>>>>>> instances of generic types, since specializations would need to be 
>>>>>> registered with the runtime as canonical metadata objects, and it would 
>>>>>> be difficult to do this lazily and still reliably favor specializations 
>>>>>> over more generic witnesses. The lack of witness table specializations 
>>>>>> leaves an obnoxious performance cliff for instances of generic types 
>>>>>> that end up inside existential containers or cross into unspecialized 
>>>>>> code. The runtime also obligates binaries to provide the canonical 
>>>>>> metadata for all of their public types, along with all the dependent 
>>>>>> value witnesses, class methods, and protocol witness tables, meaning a 
>>>>>> type abstraction can never be completely "zero-cost" across modules.
>>>>>> 
>>>>>> On the other hand, if type metadata did not need to be unique, then the 
>>>>>> compiler would be free to emit specialized type metadata and protocol 
>>>>>> witness tables for fully concrete non-concrete value types without 
>>>>>> consulting the runtime. This would let us avoid runtime calls to fetch 
>>>>>> metadata in specialized code, and would make it much easier for us to 
>>>>>> implement witness specialization. It would also give us the ability to 
>>>>>> potentially extend the "inlinable" concept to public fragile types, 
>>>>>> making it a client's responsibility to emit metadata for the type when 
>>>>>> needed and keeping the type from affecting its home module's ABI. This 
>>>>>> could significantly reduce the size and ABI surface area of the standard 
>>>>>> library, since the standard library contains a lot of generic 
>>>>>> lightweight adapter types for collections and other abstractions that 
>>>>>> are intended to be optimized away in most use cases.
>>>>>> 
>>>>>> There are of course benefits to globally unique metadata objects that we 
>>>>>> would lose if we gave up uniqueness. Operations that do check type 
>>>>>> identity, such as comparison, hashing, and dynamic casting, would have 
>>>>>> to perform more expensive checks, and nonunique metadata objects would 
>>>>>> need to carry additional information to enable those checks. It is 
>>>>>> likely that class objects would have to remain globally unique, if for 
>>>>>> no other reason than that the Objective-C runtime requires it on Apple 
>>>>>> platforms. Having multiple equivalent copies of type metadata has the 
>>>>>> potential to increase the working set of an app in some situations, 
>>>>>> although it's likely that redundant compiler-emitted copies of value 
>>>>>> type metadata would at least be able to live in constant pages mapped 
>>>>>> from disk instead of getting dynamically instantiated by the runtime 
>>>>>> like everything is today. There could also be subtle source-breaking 
>>>>>> behavior for code that bitcasts metatype values to integers or pointers 
>>>>>> and expects bit-level equality to indicate type equality. It's unlikely 
>>>>>> to me that giving up uniqueness would buy us any simplification to the 
>>>>>> runtime, since the runtime would still need to be able to instantiate 
>>>>>> metadata for unspecialized code, and we would still want to unique 
>>>>>> runtime-instantiated metadata objects as an optimization.
>>>>>> 
>>>>>> Overall, my intuition is that the tradeoffs come out in favor for 
>>>>>> nonunique metadata objects, but what do you all think? Is there anything 
>>>>>> I'm missing?
>>>>>> 
>>>>>> -Joe
>>>>> 
>>>>> In a premature proposal two years ago, we agreed to ditch unique protocol 
>>>>> conformances but install the canonical address as the first entry in each 
>>>>> specialized table.
>>>> 
>>>> This would be a reference to (unique) global data about the conformance, 
>>>> not a reference to some canonical version of the protocol witness table.  
>>>> We do not rely on having a canonical protocol witness table.  The only 
>>>> reason we unique them (when we do need to instantiate) is because we don't 
>>>> want to track their lifetimes.
>>>> 
>>>>> That would mitigate the disadvantages that you pointed to. But, we would 
>>>>> also lose the ability to emit specialized metadata/conformances in 
>>>>> constant pages. How do you feel about that tradeoff?
>>>> 
>>>> Note that, per above, it's only specialized constant type metadata that we 
>>>> would lose.
>>>> 
>>>> I continue to feel that having to do structural equality tests on type 
>>>> metadata would be a huge loss.
>>>> 
>>>> John.
>>> 
>>> My question was really, are we going to runtime-initialize the specialized 
>>> metadata and specialized witness tables in order to install the unique 
>>> identifier, rather than requiring a runtime call whenever we need the 
>>> unique ID. I think the answer is “yes”, we want to install the ID at 
>>> initialization time for fast type comparison, hashing and casting.
>> 
>> Sorry, by "(unique) global data about the conformance" I meant that we would 
>> emit a global conformance descriptor in constant data for the conformance 
>> declaration.  There would be one of these, no matter how many it was 
>> instantiated; it would therefore uniquely identify a possible generic 
>> conformance the same way that a nominal type descriptor uniquely identifies 
>> a possibly generic type.  The reference to it would just be an ordinary 
>> symbol reference.
> 
> Naturally, eagerly emitting one of those has the same advantages and 
> disadvantages as eagerly emitting type metadata and everything else, and can 
> be solved in the same way.
> 
> John.

Sure, for witness tables each constant specialized conformance can refer to a 
unique constant nominal conformance, resolved at link-time.

Whereas we expect specialized type metadata to always need some runtime 
initialization because we want to unique some canonical entity for each 
instantiation and possibly compress VWTs.

-Andy
_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

Reply via email to