Skip to content

Commit 2da6ac1

Browse files
committed
[SIL] Doc'd deinit barriers.
1 parent 2aa70af commit 2da6ac1

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

docs/SIL.rst

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2364,6 +2364,69 @@ The current list of interior pointer SIL instructions are:
23642364
(*) We still need to finish adding support for project_box, but all other
23652365
interior pointers are guarded already.
23662366

2367+
Variable Lifetimes
2368+
~~~~~~~~~~~~~~~~~~
2369+
2370+
In order for programmer intended lifetimes to be maintained under optimization,
2371+
the lifetimes of SIL values which correspond to named source-level values can
2372+
only be modified in limited ways. Generally, the behavior is that the lifetime
2373+
of a named source-level value cannot _observably_ end before the end of the
2374+
lexical scope in which that value is defined. Specifically, code motion may
2375+
not move the ends of these lifetimes across a **deinit barrier**.
2376+
2377+
A few sorts of SIL value have lifetimes that are constrained that way:
2378+
2379+
1: `begin_borrow [lexical]`
2380+
2: `move_value [lexical]`
2381+
3: @owned function arguments
2382+
4: `alloc_stack [lexical]`
2383+
2384+
That these three have constrained lifetimes is encoded in ValueBase::isLexical,
2385+
which should be checked before changing the lifetime of a value.
2386+
2387+
The reason that only @owned function arguments are constrained is that a
2388+
@guaranteed function argument is guaranteed by the function's caller to live for
2389+
the full duration of the function already. Optimization of the function alone
2390+
can't shorten it. When such a function is inlined into its caller, though, a
2391+
lexical borrow scope is added for each of its @guaranteed arguments, ensuring
2392+
that the lifetime of the corresponding source-level value is not shortened in a
2393+
way that doesn't respect deinit barriers.
2394+
2395+
Unlike the other sorts, `alloc_stack [lexical]` isn't a SILValue. Instead, it
2396+
constrains the lifetime of an addressable variable. Since the constraint is
2397+
applied to the in-memory representation, no additional lexical SILValue is
2398+
required.
2399+
2400+
Deinit Barriers
2401+
```````````````
2402+
2403+
Deinit barriers (see swift::isDeinitBarrier) are instructions which would be
2404+
affected by the side effects of deinitializers. To maintain the order of
2405+
effects that is visible to the programmer, destroys of lexical values cannot be
2406+
reordered with respect to them. There are three kinds:
2407+
2408+
1. synchronization points (locks, memory barriers, syscalls, etc.)
2409+
2. loads of weak or unowned values
2410+
3. accesses of pointers
2411+
2412+
Examples:
2413+
2414+
1. Given an instance of a class which owns a file handle and closes the file
2415+
handle on deinit, writing to the file handle and then deallocating the
2416+
instance would result in changes being written. If the destroy of the
2417+
instance were hoisted above the call to write to the file handle, an error
2418+
would be raised instead.
2419+
2. Given an instance `c` of a class `C` which weakly references an instance `d`
2420+
of a second class `D`, if `d` is referenced via a local variable `v`, then
2421+
loading that weak reference from `c` within the variable scope should return
2422+
a non-nil reference to `d`. Hoisting the destroy of `v` above the weak load
2423+
from `c`, however, would result in the destruction of `d` before that load
2424+
and a nil weak reference to `D`.
2425+
3. Given an instance of a class which owns a buffer and deallocates it on
2426+
deinitialization, accessing the pointer and then deallocating the instance
2427+
is defined behavior. Hoisting the destroy of the instance above the access
2428+
to the memory would result in accessing a freed pointer.
2429+
23672430
Memory Lifetime
23682431
~~~~~~~~~~~~~~~
23692432

0 commit comments

Comments
 (0)