> On Jul 28, 2017, at 7:07 PM, Jordan Rose <jordan_r...@apple.com> wrote:
>> On Jul 28, 2017, at 16:03, Joe Groff <jgr...@apple.com 
>> <mailto: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.

Yes, if we ended up with type metadata for an unexposed type, we'd need some 
way to know that it wasn't some other unexposed type.

I don't think is related to laziness at all; if another library has the ability 
to generate type metadata for it, it must be an exposed type.

>>> 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. :-)

I think we pretty clearly ought to be emitting some sort of protocol 
conformance descriptor.  It wouldn't need to be very large.

Of course, if we were relying on pointer equality for it, it would have to 
emitted eagerly.

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

Reply via email to