You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: proposals/0nnn-section-control.md
+71-1Lines changed: 71 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -55,7 +55,7 @@ This proposal recommends to use sections of the various object file formats as t
55
55
56
56
## Proposed Solution
57
57
58
-
The proposal is to add two new attributes `@section` and `@used` that will allow annotating global and static variables with directives to place the value into a custom section, and to require no-dead-stripping aka "attribute used". The`@section`attribute relies heavily on the facilities provided by [Swift Compile-Time Values](https://github.com/artemcm/swift-evolution/blob/const-values/proposals/0nnn-const-values.md), namely the ability to enforce constantness of an expressions. Using `@section` requires that the initializer expression is a constant expression:
58
+
The proposal is to add two new attributes `@section` and `@used` that will allow annotating global and static variables with directives to place the value into a custom section, and to require no-dead-stripping aka "attribute used". Using`@section`requires that the initializer expression is a constant expression (see Constant Expressions below for the definition of that):
59
59
60
60
```swift
61
61
// Place an entry into a section, mark as "do not dead strip".
@@ -100,6 +100,13 @@ var global = ...
100
100
101
101
For the ELF file format specifically, the compiler will also emit a “section index” into produced object files, containing an entry about each custom section used in the compilation. This is a solution to an ELF specific problem where the behavior of ELF linkers and loaders means that sections are not easily discoverable at runtime.
102
102
103
+
When placing variables into a custom section, it's also allowed to use the `lazy` keyword to opt out of the mandatory static initialization and mandatory constant expression behavior, while still achieving section placement of the backing store of the data:
> Note: The intention is that the `@section` and `@used` attributes are to be used rarely and only by specific use cases; high-level application code should not need to use them directly and instead should rely on libraries, macros and other abstractions over the low-level attributes.
104
111
105
112
> The scope of this proposal is limited to compile-time behavior and compile-time control. We expect that full user-facing solutions for features like linker sets, test discovery or plugins will also require runtime implementations to discover and iterate the contents of custom sections, possibly from multiple modules. This proposal makes sure to provide the right building blocks and artifacts in binaries for the runtime components, but doesn’t prescribe the shape of those. However, it is providing a significant step towards generalized and safe high-level mechanisms for those use cases. See the discussion in [Runtime discovery of data in custom sections](#runtime-discovery-of-data-in-custom-sections) and [Linker sets, plugins as high-level APIs](#linker-sets-plugins-as-high-level-apis) in Future Directions.
@@ -180,6 +187,54 @@ When allowed, the `@used` attribute on a variable declaration has the following
180
187
181
188
The effects described above are applied to the storage symbols and don’t generally affect optimizations and other transformations in the compiler. For example, the compiler is still allowed to propagate and copy a the constant value to code that uses the value, so there’s no guarantee that a value stored into a global with a custom section will not be propagated and “leak” outside of the section. The `@used` annotation, however, does inform the optimizer that such a variable cannot be removed, even when it doesn’t have any observed users or even if it’s inaccessible due to language rules (e.g. if it’s a private static member on an otherwise empty type).
182
189
190
+
### Constant expressions
191
+
192
+
Swift currently does not have a formal notion of a **constant expression**, i.e. an expression with a syntactic form that *guarantees the ability to know it's value at compile-time*. This proposal provides a definition of a "bare minimum" constant expression, with the understanding that this does not cover the language needs in generality, and the expectation that the Swift compiler and language will keep expanding the allowed forms of constant expressions. See [Generalized constant values and expressions](#generalized-constant-values-and-expressions) in Future Directions for further discussion on this.
193
+
194
+
This proposal defines a **constant expression** as being one of:
195
+
196
+
- an integer literal using any of built-in integer types (Int, UInt, Int8/16/32/64/128, UInt8/16/32/64/128)
197
+
- a floating-point literal of type Float or Double
198
+
- a boolean literal of type Bool
199
+
- a direct reference to a non-generic function using its name (the function itself is not generic, and also it must not be defined in a generic context)
200
+
- a direct reference to a non-generic metatype using the type name directly (the type itself is not generic, and also it must not be defined in a generic context), where the type is non-resilient
201
+
- a tuple composed of only other constant expressions
202
+
- an array literal of type InlineArray composed of only other constant expressions
203
+
204
+
Explicitly, this definition currently does **not allow** any operators, using any user-defined named types, any other built-in type (e.g. strings, dictionaries, sets), using closures, or referencing any variables by name. See below for examples of valid and invalid constant expressions:
205
+
206
+
```swift
207
+
@section("...") let a =42// ✅
208
+
@section("...") let b =3.14// ✅
209
+
@section("...") let c =1+1// ❌ operators not allowed
210
+
@section("...") let d =Int.max// ❌ not a literal
211
+
@section("...") let e: UInt8=42// ✅
212
+
@section("...") let f =UInt8(42) // ❌ not a literal
213
+
@section("...") let g: MyCustomExpressibleByIntegerLiteral =42// ❌ not a built-in type
@section("...") let func2 =foo() // ❌ not a function reference
224
+
@section("...") let func3 =Bool.random// ✅
225
+
@section("...") let func4 =Bool.self.random// ❌ not a direct reference
226
+
@section("...") let func5 = (Bool.selfasBool.Type).random// ❌ not a direct reference
227
+
@section("...") let func6 = [Int].randomElement// ❌ generic
228
+
@section("...") let func7 = { } // ❌ not using name
229
+
230
+
structS { }
231
+
@section("...") let metatype1 = S.self// ✅
232
+
@section("...") let metatype2 =Int.self// ✅
233
+
@section("...") let metatype3 =Int.self.self// ❌ not a direct reference
234
+
importFoundation
235
+
@section("...") let metatype4 = URL.self// ❌ resilient
236
+
```
237
+
183
238
### Guaranteed static initialization
184
239
185
240
Using attribute `@section` requires the initializer expression of the variable to be a **constant expression**. It's not required to separately annotate the expression for being a compile-time expression, instead this is implied from the `@section` attribute. On top of the constant-ness, `@section` on a global or static variable enforces **static initialization** on that variable.
@@ -221,6 +276,17 @@ let a = (42, foo) // "foo" is statically initialized into a
221
276
// linkable/relocatable pointer
222
277
```
223
278
279
+
### Lazy variables with section placement
280
+
281
+
On global and static variables that are annotated with `@section`, the compiler will now allow the `lazy` keyword (which is currently disallowed on all global and static variables). Using it will opt such variable out of the "mandatory static initialization" behavior and instead use the at-runtime lazy initialization that traditional global and static variables have. The initializer expression does not need to be a constant expression in this case. This is useful for the uncommon use caseof placing variables into a custom section purely forcolocation (e.g. to improve performance by increasing page/cacheline locality):
Traditional global and static variables are backed by two symbols: An init-once token and the actual storage for the variable's content. Both of these symbols are going to be placed into the custom section when using `@section` with `lazy`. This also means that any offline or in-process introspection mechanisms cannot assume a specific layout or state of such variables and their storage bytes in the sections, as the exact layout and content of the symbols oflazy variables is an implementation detail of the Swift language runtime.
289
+
224
290
### Cross-platform object file format support
225
291
226
292
The custom section name specified in the `@section` attribute is not validated by the compiler, instead it’s passed directly as a string to the linker. Different platforms supported by Swift are using different object and binary file formats (Linux uses ELF, Darwin uses Mach-O, Windows uses COFF), and that implies different restrictions and rules on what are valid section names. Because of that, a multi-platform library code is expected to use `#ifos(...)` to use different section names for different platforms. Because of that, it’s expected that the attributes are to be typically only used indirectly via macros that hide the low-level nature of sections and object file formats from higher-level code developers:
@@ -325,6 +391,10 @@ This will require some design decisions to be made around when should that be al
325
391
326
392
Static initialization of a global can be useful on its own, without placing data into a custom section, and a separate attribute for that could be added. This way, one can get the same effects as the `@section` attribute (static initialization, normal initalization behavior if top-level code) except the symbol would not be actually placed into any custom section.
327
393
394
+
### Generalized constant values and expressions
395
+
396
+
The notions of constant expressions and constant values is applicable to a much wider setof use cases that just section placement, and the setof allowed types and syntactical forms should be expanded in the future into a full-featured system for compile-time programming. A dedicated proposal, [Swift Compile-Time Values](https://github.com/artemcm/swift-evolution/blob/const-values/proposals/0nnn-const-values.md), is being pitched [on the forums](https://forums.swift.org/t/pitch-3-swift-compile-time-values/77434) and describes in detail the possible future of generalized constants, the relevant motivation and use cases.
397
+
328
398
### Allowing a reference to a constant string declaration as a section name
329
399
330
400
The requirement to only use string literals as the section names could be lifted in the future, and we might allow referring to a declaration of variable with a compile-time string. This would be useful to avoid repetition when placing multiple values into the same section without needing to use macros.
0 commit comments