@@ -217,14 +217,17 @@ Here by defining module type `S` with layout `any` and using `with` constraints,
217
217
reason about modules with similar shapes but that operate on different layouts. This removes code
218
218
duplication and can aid ppxs in supporting unboxed types.
219
219
220
+ <!-- This heading is referred to by name in a link to an HTML anchor below.
221
+ If you rename it, please also update that link.
222
+ -->
220
223
# ` [@layout_poly] ` attribute
221
224
222
225
The attribute enables support for ** limited layout polymorphism on external
223
226
` % ` -primitives** . This is possible because these primitives are always inlined at every
224
227
use site. We can thus specialize the function implementation based on the layout
225
228
information at each site.
226
229
227
- With a ` [@layout-poly ] ` external declaration like this:
230
+ With a ` [@layout_poly ] ` external declaration like this:
228
231
229
232
``` ocaml
230
233
external[@layout_poly] opaque_identity : ('a : any). 'a -> 'a = "%opaque"
@@ -270,7 +273,7 @@ let f2 : float# -> float# = magic;; (* ok *)
270
273
let f3 : float# -> int32# = magic;; (* error *)
271
274
```
272
275
273
- This feature is conceptually similar to ` [@local_opt] ` for modes and would be useful for
276
+ This feature is conceptually similar to ` [@local_opt] ` for modes and is useful for
274
277
array access primitives.
275
278
276
279
Here's the list of primitives that currently support ` [@layout_poly] ` :
@@ -285,17 +288,73 @@ Here's the list of primitives that currently support `[@layout_poly]`:
285
288
* ` %array_safe_set `
286
289
* ` %array_unsafe_get `
287
290
* ` %array_unsafe_set `
291
+ * ` %array_size `
292
+
293
+ # Arrays of unboxed elements
294
+
295
+ Arrays can store elements of any layout. You can think of ` array ` as having been declared as:
296
+
297
+ ``` ocaml
298
+ type ('a : any) array = (* ... *)
299
+ ```
300
+
301
+ Array elements are packed according to their width. For example, arrays of
302
+ elements whose layout is ` bits32 ` store two elements per word.
303
+
304
+ You can use normal array syntax for constructing such an array:
305
+
306
+ ``` ocaml
307
+ let array = [| #2l |]
308
+ ```
309
+
310
+ Array primitives must be declared with ` [@layout_poly] ` to be usable with arrays of unboxed elements.
311
+
312
+ ``` ocaml
313
+ module Array = struct
314
+ external[@layout_poly] get : ('a : any). 'a array -> int -> 'a = "%array_safe_get"
315
+ end
316
+
317
+ let first_elem () = array.(0)
318
+ ```
319
+
320
+ (The above relies on the fact that array projection syntax desugars to a call to whatever ` Array.get ` is in scope.)
321
+
322
+ A limited set of primitives may be bound as ` [@layout_poly] ` ;
323
+ [ see the earlier section] ( #layout_poly-attribute ) for more information.
324
+
325
+ ## Runtime representation
326
+
327
+ | Array | Tag | Layout of data |
328
+ | ----------------------------------| --------------------| -------------------------------------------------------------|
329
+ | ` float# array ` | ` Double_array_tag ` | 64 bits per element |
330
+ | ` int64# array ` | ` Custom_tag ` | reserved custom block word, followed by 64 bits per element |
331
+ | ` float32# array ` , ` int32# array ` | ` Custom_tag ` | reserved custom block word, followed by 32 bits per element |
332
+
333
+ The above table is written about concrete types like ` float# ` and ` int64# ` , but
334
+ actually holds for all types of the relevant layout.
335
+
336
+ The reserved custom block word is the standard custom block field that stores a
337
+ pointer to the record of custom operations, like polymorphic equality and
338
+ comparison. For unboxed 32-bit element types, like ` int32# ` and ` float32# ` , the
339
+ custom operations pointer is different for odd-length arrays and even-length
340
+ arrays.
341
+
342
+ Odd-length arrays of 32-bit element type have 32 bits of padding at the end.
343
+ The contents of this padding is unspecified, and it is not guaranteed that
344
+ the padding value will be preserved by the generated code or the runtime.
288
345
289
346
# Using unboxed types in structures
290
347
291
348
Unboxed types can usually be put in structures, though there are some restrictions.
292
349
293
350
These structures may contain unboxed types, but have some restrictions on field
294
351
orders:
352
+
295
353
* Records
296
354
* Constructors
297
355
298
356
Unboxed numbers can't be put in these structures:
357
+
299
358
* Constructors with inline record fields
300
359
* Exceptions
301
360
* Extensible variant constructors
0 commit comments