@@ -13,8 +13,8 @@ The stack allocations language extension allows the compiler to
13
13
stack-allocate some values, placing them on a stack rather than the
14
14
garbage collected heap. Instead of waiting for the next GC, the memory
15
15
used by stack-allocated values is reclaimed when their stack frame
16
- is reclaimed , and can be immediately reused. Whether the compiler
17
- stack-allocates certain values is controlled or inferred from new keywords
16
+ is popped , and can be immediately reused. Whether the compiler
17
+ stack-allocates certain values is inferred or controlled from new keywords
18
18
` stack_ ` and ` local_ ` , whose effects are explained below.
19
19
20
20
## Stack allocation
@@ -29,8 +29,8 @@ let abc = stack_ (42, 24) in
29
29
30
30
Here, the tuple cell will be stack-allocated. The ` stack_ ` keyword works shallowly: it
31
31
only forces the immediately following allocation to be on stack. In the following
32
- example, the outer tuple is guaranteed to be on stack, while the inner one is not (
33
- although likely to be due to optimization).
32
+ example, the outer tuple is guaranteed to be on stack, while the inner one is not
33
+ ( although likely to be due to optimization).
34
34
``` ocaml
35
35
let abc = stack_ (42, (24, 42)) in
36
36
...
@@ -61,17 +61,17 @@ including:
61
61
62
62
At runtime, stack allocations do not take place on the function call stack, but on a
63
63
separately-allocated stack that follows the same layout as the OCaml
64
- minor heap. In particular, this allows local-returning functions
65
- (see "Use ` exclave_ ` to return a local value" below)
66
- without the need to copy returned values .
64
+ minor heap. In particular, this enables local-returning functions
65
+ without the need to copy returned values. See "Use ` exclave_ ` to return a local value"
66
+ below for more details .
67
67
68
68
The runtime records the stack pointer when entering a new stack frame,
69
69
and leaving that stack frame resets the stack pointer to that value.
70
70
71
71
## Regions
72
72
73
73
Every stack allocation takes place inside a stack frame and is freed when the
74
- stack frame is freed . For this to be safe, stack-allocated values cannot be used
74
+ stack frame is reclaimed . For this to be safe, stack-allocated values cannot be used
75
75
after their stack frame is freed. This property is guaranteed at
76
76
compile-time by the type checker as follows.
77
77
@@ -103,7 +103,7 @@ let l = if n > 0 then stack_ (n :: x) else x in
103
103
```
104
104
105
105
Here, if ` n > 0 ` , then ` l ` will be a stack-allocated cons cell and thus local.
106
- However, if ` n <= 0 ` , then ` l ` will be ` x ` , which is global. The latter is
106
+ However, if ` n <= 0 ` , then ` l ` will be ` x ` , which is global. In that second case, ` x ` is
107
107
implicitly weakened to local (because both branches of an ` if ` must have the
108
108
same locality), making the whole
109
109
expression local.
@@ -168,7 +168,8 @@ including an entire file. This region never ends and is where global (heap-alloc
168
168
values live.
169
169
170
170
One subtlety is that we wish to treat ` local ` variables from the current region
171
- differently than ` local ` variables from an enclosing region. The latter is called * outer-local* .
171
+ differently than ` local ` variables from an enclosing region. Local from outside
172
+ the current region is called * outer-local* .
172
173
173
174
For instance:
174
175
@@ -183,16 +184,16 @@ let f () =
183
184
```
184
185
185
186
At the point marked ` ?? ` inside ` g ` , both ` outer ` and ` inner ` are local values,
186
- but they live in different regions: ` inner ` lives in ` g ` 's region, while ` outer `
187
- lives in the outer region and thus is outer-local.
187
+ but they live in different regions: ` inner ` lives in the ` g ` region, while ` outer `
188
+ lives in the ` f ` region and thus is outer-local.
188
189
189
190
So, if we replace ` ?? ` with ` inner ` , we see an error:
190
191
191
192
Error: This local value escapes its region
192
193
193
194
However, if we replace ` ?? ` with ` outer ` , the compiler will accept it: the
194
195
value ` outer ` , while being local, was definitely not local to the region of
195
- ` g ` , and there is therefore no problem allowing it to escape ` g ` 's region.
196
+ ` g ` , and there is therefore no problem allowing it to escape the ` g ` region.
196
197
197
198
(This is quite subtle, and there is an additional wrinkle: how does the
198
199
compiler know that it is safe to still refer to ` outer ` from within the closure
@@ -208,8 +209,8 @@ let f (local_ x) =
208
209
209
210
Both ` x ` and ` y ` are local and cannot, in general, escape a region. However, filling ` ?? `
210
211
in with ` x ` (but not ` y ` ) is allowed. This is because we know that ` x ` lives outside of
211
- ` f ` 's region and therefore will continue to exist after ` f ` ends. In contrast, ` y ` is a cons cell
212
- in ` f ` 's region, which will be destroyed after ` f ` ends.
212
+ the ` f ` region and therefore will continue to exist after ` f ` ends. In contrast, ` y ` is a cons cell
213
+ in the ` f ` region, which will be destroyed after ` f ` ends.
213
214
214
215
## Inference
215
216
@@ -317,8 +318,8 @@ which means it cannot be global. Therefore, it must be stack-allocated, and it
317
318
local value ` 42 :: x ` is not allowed to escape it.
318
319
319
320
It is possible to write functions like ` f3 ` that return stack-allocated
320
- values, but this requires an explicit annotation, as it would otherwise be easy to
321
- do by mistake . See "Use ` exclave_ ` to return a local value" below.
321
+ values, but this requires an explicit annotation, as it could otherwise be done
322
+ unintentionally . See "Use ` exclave_ ` to return a local value" below.
322
323
323
324
Like local variables, inference can determine whether function arguments are
324
325
local. However, note that for arguments of exported functions to be local, the
@@ -544,7 +545,7 @@ let make () = exclave_
544
545
```
545
546
546
547
The keyword ` exclave_ ` terminates the current region and executes the subsequent
547
- code in the outer region. Therefore, ` ref 0 ` is executed in ` f ` 's region, which
548
+ code in the outer region. Therefore, ` ref 0 ` is executed in the ` f ` region, which
548
549
allows its stack-allocation. The allocation will only be cleaned up when the
549
550
region of ` f ` ends.
550
551
@@ -577,7 +578,7 @@ In this example, the function `f` has a region where the allocation for the
577
578
complex computation occurs. This region is terminated by ` exclave_ ` , releasing
578
579
all temporary allocations. Both ` None ` and ` Some x ` are allocated in the
579
580
caller's stack frame and are allowed to be returned. In summary, the
580
- temporary allocations in the ` f ` 's region are promptly released, and the result
581
+ temporary allocations in the ` f ` region are promptly released, and the result
581
582
allocated in the caller's region is returned.
582
583
583
584
Here is another example in which the stack usage can be improved asymptotically
@@ -793,13 +794,13 @@ rejected:
793
794
let local_ f : int -> int -> int = fun a b -> a + b + !counter in
794
795
...
795
796
796
- let f : int -> int -> int = stack_ fun a b -> a + b + !counter in
797
+ let g : int -> int -> int = stack_ fun a b -> a + b + !counter in
797
798
...
798
799
```
799
800
800
801
Both define a closure which accepts two integers and returns an integer. The
801
802
closure must be local, since it refers to the local value ` counter ` . In the
802
- former definition, the type of the function appears under the ` local_ ` keyword,
803
+ definition of ` f ` , the type of the function appears under the ` local_ ` keyword,
803
804
and as described above is interpreted as:
804
805
805
806
``` ocaml
@@ -808,8 +809,8 @@ int -> local_ (int -> int)
808
809
809
810
This is the correct type for this function: if we partially apply it to
810
811
a single argument, the resulting closure will still be local, as it refers to
811
- the original function which refers to ` counter ` . By contrast, in the latter
812
- definition the type of the function is outside the ` stack_ ` keyword as is
812
+ the original function which refers to ` counter ` . By contrast, in the
813
+ definition of ` g ` , the type of the function is outside the ` stack_ ` keyword as is
813
814
interpreted as normal as:
814
815
815
816
``` ocaml
@@ -822,7 +823,7 @@ case here. For this reason, this version is rejected. It would be accepted if
822
823
written as follows:
823
824
824
825
``` ocaml
825
- let f : int -> local_ (int -> int) = stack_ fun a b -> a + b + !counter in
826
+ let g : int -> local_ (int -> int) = stack_ fun a b -> a + b + !counter in
826
827
...
827
828
```
828
829
0 commit comments