> On Jul 30, 2017, at 5:47 PM, John McCall <rjmcc...@apple.com> wrote: > >> On Jul 29, 2017, at 7:35 PM, Slava Pestov <spes...@apple.com >> <mailto:spes...@apple.com>> wrote: >>> On Jul 29, 2017, at 12:53 PM, John McCall via swift-dev >>> <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote: >>>> On Jul 29, 2017, at 12:48 AM, Andrew Trick <atr...@apple.com >>>> <mailto:atr...@apple.com>> wrote: >>>>> On Jul 28, 2017, at 8:13 PM, John McCall <rjmcc...@apple.com >>>>> <mailto: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. >>> >>> Oh, I missed that you were talking about both, sorry. If we wanted to emit >>> specialized type metadata, I think it would have to be an explicit goal >>> that they could be emitted without any sort of dynamic initialization, >>> which implies that they're non-unique. >> >> I was wondering about that. I’m still having trouble filling in the details, >> but it seems that if non-unique type metadata never ‘escapes’ from a >> function, we could stack-allocate ‘structural’ metadata, for example if you >> have >> >> func foo<T>(_: T) {} >> >> func bar<T>(x: T, y: Y) { >> foo((x, y)) >> } >> >> You would be able to compile bar() without any runtime calls at all, >> building the tuple type metadata ‘from scratch’ on the stack and passing it >> to foo(). Perhaps generic nominal types could also be constructed >> non-uniquely without a runtime call. > > Okay. What would be required to prove that type metadata never escapes from > a function?
Well, we could say that metadata is uniqued before being reified into a value (T.self) or when constructing an existential, etc. Other than that, I think the only thing we do with metadata is pass it to other functions? Slava > > John. > >> >>> Remember that we can only do this for types not expressed in terms of >>> archetypes to begin with, and we can already use caller-side caches to >>> optimize access such to those metadata anyway. >>> >>> John. >>> _______________________________________________ >>> swift-dev mailing list >>> swift-dev@swift.org <mailto:swift-dev@swift.org> >>> https://lists.swift.org/mailman/listinfo/swift-dev >>> <https://lists.swift.org/mailman/listinfo/swift-dev> >
_______________________________________________ swift-dev mailing list swift-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-dev