> On Jul 28, 2017, at 16:03, Joe Groff <jgr...@apple.com> wrote:
> 
> 
>> On Jul 28, 2017, at 3:59 PM, Jordan Rose <jordan_r...@apple.com 
>> <mailto:jordan_r...@apple.com>> wrote:
>> 
>> 
>> 
>>> On Jul 28, 2017, at 15:35, Joe Groff via swift-dev <swift-dev@swift.org 
>>> <mailto:swift-dev@swift.org>> wrote:
>>> 
>>>> 
>>>> On Jul 28, 2017, at 3:30 PM, John McCall <rjmcc...@apple.com 
>>>> <mailto:rjmcc...@apple.com>> wrote:
>>>> 
>>>>> On Jul 28, 2017, at 6:24 PM, Joe Groff <jgr...@apple.com 
>>>>> <mailto:jgr...@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.
>>>>> 
>>>>> I don't think it necessarily needs to be deep structural equality. If the 
>>>>> type metadata object or value witness table had a pointer to a mangled 
>>>>> type name string, we could strcmp those strings to compare equality, 
>>>>> which doesn't seem terribly onerous to me, though if it were we could 
>>>>> perhaps use the string to lazily resolve the canonical type metadata 
>>>>> pointer, sort of like we do with type metadata for imported C types today.
>>>> 
>>>> So generic code to instantiate type metadata would have to construct these 
>>>> mangled strings eagerly?
>>> 
>>> We already do exactly that for the ObjC runtime name of generic class 
>>> instantiations, for what it's worth, but it could conceivably be lazy as 
>>> well, at the cost of making the comparison yet more expensive. There aren't 
>>> that many runtime operations that need to do type comparison, though—the 
>>> ones I can think of are casting and the equality/hashing operations on 
>>> Any.Type—so how important is efficient type comparison?
>> 
>> I'm still strongly against any feature that relies on type names being 
>> present at runtime. I think we should be able to omit those for both code 
>> size and secrecy reasons when the type isn't an @objc class or protocol.
> 
> I think nonuniquing type metadata gives us a bit more leeway to discard 
> runtime info about types, at least public ones, since it's no longer the 
> owning binary's sole responsibility to provide canonical metadata.

My point is we can't use our usual mangling in the string, because that 
contains type names.


> 
>> For the actual feature, I'd be interested in how it interacts with 
>> conflicting protocol conformances in different frameworks, including both 
>> two different modules trying to do retroactive modeling and in a library 
>> adding a conformance in a later release that a client may have also added.
> 
> We could still have some way of uniquely identifying a conformance to prevent 
> these collisions.

To be clear, we don't have an answer for this today. Something we need to 
discuss along with library evolution. :-)

Jordan

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

Reply via email to