Add heaps to the Cretonne IL.

Add preamble syntax for declaring static and dynamic heaps, and update
the langref section on heaps. Add IR support for heap references.

Remove the heap_load and heap_store as discussed in #144. We will use
heap_addr along with native load and store instructions in their place.

Add the heap_addr instruction and document its bounds checking
semantics.
This commit is contained in:
Jakob Stoklund Olesen
2017-08-18 12:51:54 -07:00
parent a9238eda7a
commit 3b71a27632
17 changed files with 405 additions and 83 deletions

View File

@@ -13,7 +13,7 @@ ebb1(v1: i32, v2: i32):
ebb2(v5: i32):
v6 = imul_imm v5, 4
v7 = iadd v1, v6
v8 = heap_load.f32 v7 ; array[i]
v8 = load.f32 v7 ; array[i]
v9 = fpromote.f64 v8
v10 = stack_load.f64 ss1
v11 = fadd v9, v10

View File

@@ -559,44 +559,82 @@ all process memory. Instead, it is given a small set of memory areas to work
in, and all accesses are bounds checked. Cretonne models this through the
concept of *heaps*.
A heap is declared in the function preamble and can be accessed with restricted
instructions that trap on out-of-bounds accesses. Heap addresses can be smaller
than the native pointer size, for example unsigned :type:`i32` offsets on a
64-bit architecture.
A heap is declared in the function preamble and can be accessed with the
:inst:`heap_addr` instruction that traps on out-of-bounds accesses or returns a
pointer that is guaranteed to trap. Heap addresses can be smaller than the
native pointer size, for example unsigned :type:`i32` offsets on a 64-bit
architecture.
.. inst:: H = heap Name
.. digraph:: static
:align: center
:caption: Heap address space layout
Declare a heap in the function preamble.
node [
shape=record,
fontsize=10,
fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans"
]
"static" [label="mapped\npages|unmapped\npages|guard\npages"]
This doesn't allocate memory, it just retrieves a handle to a sandbox from
the runtime environment.
A heap appears as three consecutive ranges of address space:
:arg Name: String identifying the heap in the runtime environment.
:result H: Heap identifier.
1. The *mapped pages* are the usable memory range in the heap. Loads and stores
to this range won't trap. A heap may have a minimum guaranteed size which
means that some mapped pages are always present.
2. The *unmapped pages* is a possibly empty range of address space that may be
mapped in the future when the heap is grown.
3. The *guard pages* is a range of address space that is guaranteed to cause a
trap when accessed. It is used to optimize bounds checking for heap accesses
with a shared base pointer.
.. autoinst:: heap_load
.. autoinst:: heap_store
When optimizing heap accesses, Cretonne may separate the heap bounds checking
and address computations from the memory accesses.
The *heap bound* is the total size of the mapped and unmapped pages. This is
the bound that :inst:`heap_addr` checks against. Memory accesses inside the
heap bounds can trap if they hit an unmapped page.
.. autoinst:: heap_addr
A small example using heaps::
Two styles of heaps are supported, *static* and *dynamic*. They behave
differently when resized.
function %vdup(i32, i32) {
h1 = heap "main"
Static heaps
~~~~~~~~~~~~
ebb1(v1: i32, v2: i32):
v3 = heap_load.i32x4 h1, v1, 0
v4 = heap_addr h1, v2, 32 ; Shared range check for two stores.
store v3, v4, 0
store v3, v4, 16
return
}
A *static heap* starts out with all the address space it will ever need, so it
never moves to a different address. At the base address is a number of mapped
pages corresponding to the heap's current size. Then follows a number of
unmapped pages where the heap can grow up to its maximum size. After the
unmapped pages follow the guard pages which are also guaranteed to generate a
trap when accessed.
The final expansion of the :inst:`heap_addr` range check and address conversion
depends on the runtime environment.
.. inst:: H = static Base, min MinBytes, bound BoundBytes, guard GuardBytes
Declare a static heap in the preamble.
:arg Base: Global variable holding the heap's base address or
``reserved_reg``.
:arg MinBytes: Guaranteed minimum heap size in bytes. Accesses below this
size will never trap.
:arg BoundBytes: Fixed heap bound in bytes. This defines the amount of
address space reserved for the heap, not including the guard pages.
:arg GuardBytes: Size of the guard pages in bytes.
Dynamic heaps
~~~~~~~~~~~~~
A *dynamic heap* can be relocated to a different base address when it is
resized, and its bound can move dynamically. The guard pages move when the heap
is resized. The bound of a dynamic heap is stored in a global variable.
.. inst:: H = dynamic Base, min MinBytes, bound BoundGV, guard GuardBytes
Declare a dynamic heap in the preamble.
:arg Base: Global variable holding the heap's base address or
``reserved_reg``.
:arg MinBytes: Guaranteed minimum heap size in bytes. Accesses below this
size will never trap.
:arg BoundGV: Global variable containing the current heap bound in bytes.
:arg GuardBytes: Size of the guard pages in bytes.
Operations