When we use type(of: x) on a class in an ObjC bridged context, the optimizer turns this into a SIL `value_metatype @objc` operation, which is supposed to get the dynamic type of the object as an ObjC class. This was previously lowered by IRGen into a `object_getClass` call, which extracts the isa pointer from the object, but is inconsistent with the `-class` method in ObjC or with the Swift-native behavior, which both look through artificial subclasses, proxies, and so on. This inconsistency led to observably different behavior between debug and release builds and between ObjC-bridged and native entry points, so provide an alternative runtime entry point that replicates the behavior of getting a native Swift class. Fixes SR-7258.
The current approach has several problems:
- Types that are not inout types but loadable may incorrectly get
marked as inout types.
- When inout arguments get inlined or otherwise optimized LLDB cannot
rely on the type to decide to dereference that value.
- One argument may get represented by different types in the same
function depending on what code is generated for it.
Fixes rdar://problem/rdar://problem/39023374
Most of the work of this patch is just propagating metadata states
throughout the system, especially local-type-data caching and
metadata-path resolution. It took a few design revisions to get both
DynamicMetadataRequest and MetadataResponse to a shape that felt
right and seemed to make everything easier.
The design is laid out pretty clearly (I hope) in the comments on
DynamicMetadataRequest and MetadataResponse, so I'm not going to
belabor it again here. Instead, I'll list out the work that's still
outstanding:
- I'm sure there are places we're asking for complete metadata where
we could be asking for something weaker.
- I need to actually test the runtime behavior to verify that it's
breaking the cycles it's supposed to, instead of just not regressing
anything else.
- I need to add something to the runtime to actually force all the
generic arguments of a generic type to be complete before reporting
completion. I think we can get away with this for now because all
existing types construct themselves completely on the first request,
but there might be a race condition there if another asks for the
type argument, gets an abstract metadata, and constructs a type with
it without ever needing it to be completed.
- Non-generic resilient types need to be switched over to an IRGen
pattern that supports initialization suspension.
- We should probably space out the MetadataStates so that there's some
space between Abstract and Complete.
- The runtime just calmly sits there, never making progress and
permanently blocking any waiting threads, if you actually form an
unresolvable metadata dependency cycle. It is possible to set up such
a thing in a way that Sema can't diagnose, and we should detect it at
runtime. I've set up some infrastructure so that it should be
straightforward to diagnose this, but I haven't actually implemented
the diagnostic yet.
- It's not clear to me that swift_checkMetadataState is really cheap
enough that it doesn't make sense to use a cache for type-fulfilled
metadata in associated type access functions. Fortunately this is not
ABI-affecting, so we can evaluate it anytime.
- Type layout really seems like a lot of code now that we sometimes
need to call swift_checkMetadataState for generic arguments. Maybe
we can have the runtime do this by marking low bits or something, so
that a TypeLayoutRef is actually either (1) a TypeLayout, (2) a known
layout-complete metadata, or (3) a metadata of unknown state. We could
do that later with a flag, but we'll need to at least future-proof by
allowing the runtime functions to return a MetadataDependency.
At -Onone, we may opt to extend the liverange of a value by inserting
fake uses of the value in blocks which postdominate its def. This keeps
values available throughout the entirety of a function when stepping
through it in a debugger.
This patch makes it so that we also insert a fake use at the start of a
value's lifetime. This forces early materialization of the value, i.e it
becomes available for inspection in a debugger as soon as it's defined.
This is useful when a value has no uses except fake uses. In such cases,
ISel may (correctly!) decide to materialize the value at the end of its
scope. This is really unintuitive and unhelpful for users, because you
need to be done stepping through the value's scope before you can
inspect it.
For the same reasons, forcing early materialization is also useful when
a value *does* have uses. Consider:
let d = ...
print("Here is the value of d: \(d)")
Without early materialization, if you set a breakpoint on the line
containing the print, you would not be able to inspect "d". That's
because "d" would be materialized right before string interpolation
happens, which is *after* the breakpoint PC.
rdar://38465084
Abstract type/heap metadata access goes into MetadataRequest.
Metadata access starting from a heap object goes into GenHeap.
Accessing various components of class metadata goes into GenClass
or MetadataLayout.
SIL functions might be associated with decls from other source files whose symbols we can't necessarily locally link to. The module should be associated with the SourceFile that was compiled.
This makes it more likely we'll do optimizations that are currently scoped to same-SourceFile references, such as direct relative references or symbolic references in mangling, in codegen that gets triggered on behalf of a SILFunction. Should be NFC, aside from some tiny code size improvement.
Will be used to verify that withoutActuallyEscaping's block does not
escape the closure.
``%escaping = is_escaping_closure %closure`` tests the reference count. If the
closure is not uniquely referenced it prints out and error message and
returns true. Otherwise, it returns false. The returned result can be
used with a ``cond_fail %escaping`` instruction to abort the program.
rdar://35525730
This patch both makes debug variable information it optional on
alloc_stack and alloc_box instructions, and forced variable
information on debug_value and debug_value_addr instructions. The
change of the interface uncovered a plethora of bugs in SILGen,
SILTransform, and IRGen's LoadableByAddress pass.
Most importantly this fixes the previously commented part of the
DebugInfo/local-vars.swift.gyb testcase.
rdar://problem/37720555
Factor out and reuse logic in the lowering of CondFailInst to emit
non-mergeable traps, everywhere we emit traps. This should address a
debugging quality issue with ambiguous ud2 instructions.
rdar://32772768
Whan an alloca is dynamic, all FastISel can do is describe the
register in which the address of of the dynamic alloca is kept, and if
the value isn't used it will get kicked out by regalloc.
rdar://problem/36663932
- make @noescape function types trivial
- think_to_thick_function with @noescape result type
- Fix for getSwiftFunctionPointerCallee
Part of:
SR-5441
rdar://36116691
@noescape function types will eventually be trivial. A
convert_escape_to_noescape instruction does not take ownership of its
operand. It is a projection to the trivial value carried by the closure
-- both context and implementation function viewed as a trivial value.
A safe SIL program must ensure that the object that the project value is based
on is live beyond the last use of the trivial value. This will be
achieve by means of making the lifetimes dependent.
For example:
%e = partial_apply [callee_guaranteed] %f(%z) : $@convention(thin) (Builtin.Int64) -> ()
%n = convert_escape_to_noescape %e : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
%n2 = mark_dependence %n : $@noescape @callee_guaranteed () -> () on %e : $@callee_guaranteed () -> ()
%f2 = function_ref @use : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
apply %f2(%n2) : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
release_value %e : $@callee_guaranteed () -> ()
Note: This is not yet actually used.
Part of:
SR-5441
rdar://36116691
This code was ad-hoc trying to reconstruct the layout. Ask TypeInfo
instead, as it knows what's the right thing to do.
This allows to print field of classes nested inside classes correctly
in lldb (SR-6791).
<rdar://problem/36518505>
We want to be able to re-order existing protocol requirements
and add new protocol requirements with default implementations.
Enable this by wrapping the witness table lookup inside a
thunk and calling the thunk, instead of open-coding the
witness table lookup directly in client code.
* Reduce array abstraction on apple platforms dealing with literals
Part of the ongoing quest to reduce swift array literal abstraction
penalties: make the SIL optimizer able to eliminate bridging overhead
when dealing with array literals.
Introduce a new classify_bridge_object SIL instruction to handle the
logic of extracting platform specific bits from a Builtin.BridgeObject
value that indicate whether it contains a ObjC tagged pointer object,
or a normal ObjC object. This allows the SIL optimizer to eliminate
these, which allows constant folding a ton of code. On the example
added to test/SILOptimizer/static_arrays.swift, this results in 4x
less SIL code, and also leads to a lot more commonality between linux
and apple platform codegen when passing an array literal.
This also introduces a couple of SIL combines for patterns that occur
in the array literal passing case.
This un-breaks the LLDB testsuite.
To make it unambiguous whether a `var` binding has been initialized,
zero-initialize the first pointer-sized field. LLDB uses this to
recognize to detect uninitizialized variables. This can be removed once
swiftc switches to @llvm.dbg.addr() intrinsics. This dead store will get
optimized away when optimizations are enabled.
<rdar://problem/36156857>
And unbreak the LLDB testsuite.
This patch fixes three problems with the original implementation:
- Use SILBuilderWithScope instead of SILBuilder to avoid holes in the
lexical scopes.
- Use an artificial location for stores to the alloca to avoid the debugger
stopping before the variable is initialized.
- Recognize debug_value_addr instructions referring to an alloc_stack
instruction to avoid introducing an extra indirection in the debug info.
rdar://problem/31975108
The debug location is now unconditionally being set for each
instruction, so resetting the location at the beginning of each basic
block is redundant.
<rdar://problem/25772716>
Switch statements generate at least one anonymous match variable per
case, which consumes both a lot of stack space and an explosion of
range extension depencies due to the way case statements are scoped.
rdar://problem/34326355