> On Jul 31, 2017, at 12:13 PM, Joe Groff <jgr...@apple.com> wrote: > > >> On Jul 30, 2017, at 7:55 PM, John McCall via swift-dev <swift-dev@swift.org >> <mailto:swift-dev@swift.org>> wrote: >> >>> On Jul 30, 2017, at 9:08 PM, Slava Pestov <spes...@apple.com >>> <mailto:spes...@apple.com>> wrote: >>>> On Jul 30, 2017, at 5:47 PM, John McCall <rjmcc...@apple.com >>>> <mailto: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? >> >> Hmm, yes, I guess we could make sure that everything that uses metadata in >> any way that might escape just uniques it at that point. >> >> Your tuple example is interesting because it would actually be quite >> elaborate to construct on the fly every time we needed it, since we'd have >> to perform type layout dynamically and form a complete value witness table. >> I hope you're not anticipating inlining that into every construction site? > > Being able to reclaim memory for dynamically-generated type metadata in at > least some situations feels compelling to me, since our current design always > "leaks" metadata memory and could probably be induced to pathologically waste > memory if an attacker put their mind to it.
Supposing that there is such an attack, it seems unlikely to me that it couldn't be made to involve a class or an existential or some other thing that forced heap-allocation. > It's conceivable that we could provide entry points for dynamically > generating temporary metadata into caller-provided stack space, or if LLVM > theoretically had alloca-into-caller, have runtime entry points that do the > stack allocation and temporary metadata instantiation. The analysis to > balance the tradeoff between regenerating a metadata record multiple times > vs. creating and caching it once is probably nontrivial for the compiler to > figure out ahead of time, though. Profile-guided, maybe? But I think I've made my point that this would be a huge research project that I can't imagine us finding the time for in the next year. Forward declarations are already going to represent a huge revision to the metadata system, and one that is substantially more urgent to solve for ABI stability. John.
_______________________________________________ swift-dev mailing list swift-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-dev