Add heap_addr custom legalization.

The expansion of a heap_addr instruction depends on the type of heap and
its configuration, so this is handled by custom code.

Add a couple examples of heap access code to the language reference
manual.
This commit is contained in:
Jakob Stoklund Olesen
2017-08-24 14:04:35 -07:00
parent 3b71a27632
commit aae946128b
9 changed files with 250 additions and 10 deletions

View File

@@ -31,16 +31,13 @@ class CretonneLexer(RegexLexer):
bygroups(Comment.Single, Comment.Special, Comment.Single)),
# Plain comments.
(r';.*?$', Comment.Single),
# Strings are in double quotes, support \xx escapes only.
(r'"([^"\\]+|\\[0-9a-fA-F]{2})*"', String),
# A naked function name following 'function' is also a string.
(r'\b(function)([ \t]+)(\w+)\b',
bygroups(Keyword, Whitespace, String.Symbol)),
# Strings are prefixed by % or # with hex.
(r'%\w+|#[0-9a-fA-F]*', String),
# Numbers.
(r'[-+]?0[xX][0-9a-fA-F]+', Number.Hex),
(r'[-+]?0[xX][0-9a-fA-F]*\.[0-9a-fA-F]*([pP]\d+)?', Number.Hex),
(r'[-+]?(\d+\.\d+([eE]\d+)?|s?NaN|Inf)', Number.Float),
(r'[-+]?\d+', Number.Integer),
(r'[-+]?0[xX][0-9a-fA-F_]+', Number.Hex),
(r'[-+]?0[xX][0-9a-fA-F_]*\.[0-9a-fA-F_]*([pP]\d+)?', Number.Hex),
(r'[-+]?([0-9_]+\.[0-9_]+([eE]\d+)?|s?NaN|Inf)', Number.Float),
(r'[-+]?[0-9_]+', Number.Integer),
# Known attributes.
(keywords('uext', 'sext'), Name.Attribute),
# Well known value types.
@@ -48,7 +45,7 @@ class CretonneLexer(RegexLexer):
# v<nn> = value
# ss<nn> = stack slot
# jt<nn> = jump table
(r'(v|ss|jt)\d+', Name.Variable),
(r'(v|ss|gv|jt|fn|sig|heap)\d+', Name.Variable),
# ebb<nn> = extended basic block
(r'(ebb)\d+', Name.Label),
# Match instruction names in context.

View File

@@ -0,0 +1,15 @@
test verifier
function %add_members(i32) -> f32 spiderwasm {
gv0 = vmctx+64
gv1 = vmctx+72
heap0 = dynamic gv0, min 0x1000, bound gv1, guard 0
ebb0(v0: i32):
v1 = heap_addr.i64 heap0, v0, 20
v2 = load.f32 v1+16
v3 = heap_addr.i64 heap0, v0, 24
v4 = load.f32 v3+20
v5 = fadd v2, v4
return v5
}

View File

@@ -0,0 +1,14 @@
test verifier
function %add_members(i32) -> f32 spiderwasm {
gv0 = vmctx+64
heap0 = static gv0, min 0x1000, bound 0x10_0000, guard 0x1000
ebb0(v0: i32):
v1 = heap_addr.i32 heap0, v0, 1
v2 = load.f32 v1+16
v3 = load.f32 v1+20
v4 = fadd v2, v3
return v4
}

View File

@@ -0,0 +1,13 @@
test verifier
function %add_members(i32) -> f32 spiderwasm {
gv0 = vmctx+64
heap0 = static gv0, min 0x1000, bound 0x1_0000_0000, guard 0x8000_0000
ebb0(v0: i32):
v1 = heap_addr.i64 heap0, v0, 1
v2 = load.f32 v1+16
v3 = load.f32 v1+20
v4 = fadd v2, v3
return v4
}

View File

@@ -636,6 +636,37 @@ is resized. The bound of a dynamic heap is stored in a global variable.
:arg BoundGV: Global variable containing the current heap bound in bytes.
:arg GuardBytes: Size of the guard pages in bytes.
Heap examples
~~~~~~~~~~~~~
The SpiderMonkey VM prefers to use fixed heaps with a 4 GB bound and 2 GB of
guard pages when running WebAssembly code on 64-bit CPUs. The combination of a
4 GB fixed bound and 1-byte bounds checks means that no code needs to be
generated for bounds checks at all:
.. literalinclude:: heapex-sm64.cton
:language: cton
:lines: 2-
A static heap can also be used for 32-bit code when the WebAssembly module
declares a small upper bound on its memory. A 1 MB static bound with a single 4
KB guard page still has opportunities for sharing bounds checking code:
.. literalinclude:: heapex-sm32.cton
:language: cton
:lines: 2-
If the upper bound on the heap size is too large, a dynamic heap is required
instead.
Finally, a runtime environment that simply allocates a heap with
:c:func:`malloc()` may not have any guard pages at all. In that case, full
bounds checking is required for each access:
.. literalinclude:: heapex-dyn.cton
:language: cton
:lines: 2-
Operations
==========