Commits

Andrew Trick committed a174aa4dfe0
Add AST and SILGen support for Builtin.isUnique. Preparation to fix <rdar://problem/18151694> Add Builtin.checkUnique to avoid lost Array copies. This adds the following new builtins: isUnique : <T> (inout T[?]) -> Int1 isUniqueOrPinned : <T> (inout T[?]) -> Int1 These builtins take an inout object reference and return a boolean. Passing the reference inout forces the optimizer to preserve a retain distinct from what’s required to maintain lifetime for any of the reference's source-level copies, because the called function is allowed to replace the reference, thereby releasing the referent. Before this change, the API entry points for uniqueness checking already took an inout reference. However, after full inlining, it was possible for two source-level variables that reference the same object to appear to be the same variable from the optimizer's perspective because an address to the variable was longer taken at the point of checking uniqueness. Consequently the optimizer could remove "redundant" copies which were actually needed to implement copy-on-write semantics. With a builtin, the variable whose reference is being checked for uniqueness appears mutable at the level of an individual SIL instruction. The kind of reference count checking that Builtin.isUnique performs depends on the argument type: - Native object types are directly checked by reading the strong reference count: (Builtin.NativeObject, known native class reference) - Objective-C object types require an additional check that the dynamic object type uses native swift reference counting: (Builtin.UnknownObject, unknown class reference, class existential) - Bridged object types allow the dymanic object type check to be bypassed based on the pointer encoding: (Builtin.BridgeObject) Any of the above types may also be wrapped in an optional. If the static argument type is optional, then a null check is also performed. Thus, isUnique only returns true for non-null, native swift object references with a strong reference count of one. isUniqueOrPinned has the same semantics as isUnique except that it also returns true if the object is marked pinned regardless of the reference count. This allows for simultaneous non-structural modification of multiple subobjects. In some cases, the standard library can dynamically determine that it has a native reference even though the static type is a bridge or unknown object. Unsafe variants of the builtin are available to allow the additional pointer bit mask and dynamic class lookup to be bypassed in these cases: isUnique_native : <T> (inout T[?]) -> Int1 isUniqueOrPinned_native : <T> (inout T[?]) -> Int1 These builtins perform an implicit cast to NativeObject before checking uniqueness. There’s no way at SIL level to cast the address of a reference, so we need to encapsulate this operation as part of the builtin. Swift SVN r27887