Add heap_load, heap_store, and heap_addr instructions.

These are used when lowering WebAssembly sandbox code.
This commit is contained in:
Jakob Stoklund Olesen
2017-04-10 15:03:10 -07:00
parent e78e4ea4ec
commit b474485c0d
9 changed files with 110 additions and 46 deletions

View File

@@ -8,7 +8,8 @@ in this module.
from __future__ import absolute_import
from cdsl.formats import InstructionFormat
from cdsl.operands import VALUE, VARIABLE_ARGS
from .immediates import imm64, uimm8, ieee32, ieee64, offset32, intcc, floatcc
from .immediates import imm64, uimm8, ieee32, ieee64, offset32, uoffset32
from .immediates import intcc, floatcc
from .entities import ebb, sig_ref, func_ref, jump_table, stack_slot
Nullary = InstructionFormat()
@@ -55,5 +56,10 @@ IndirectCall = InstructionFormat(
StackLoad = InstructionFormat(stack_slot, offset32)
StackStore = InstructionFormat(VALUE, stack_slot, offset32)
# Accessing a WebAssembly heap.
# TODO: Add a reference to a `heap` declared in the preamble.
HeapLoad = InstructionFormat(VALUE, uoffset32)
HeapStore = InstructionFormat(VALUE, VALUE, uoffset32)
# Finally extract the names of global variables in this module.
InstructionFormat.extract_names(globals())

View File

@@ -9,7 +9,7 @@ from cdsl.operands import Operand, VARIABLE_ARGS
from cdsl.typevar import TypeVar
from cdsl.instructions import Instruction, InstructionGroup
from base.types import i8, f32, f64, b1
from base.immediates import imm64, uimm8, ieee32, ieee64, offset32
from base.immediates import imm64, uimm8, ieee32, ieee64, offset32, uoffset32
from base.immediates import intcc, floatcc
from base import entities
import base.formats # noqa
@@ -209,6 +209,7 @@ SS = Operand('SS', entities.stack_slot)
Offset = Operand('Offset', offset32, 'In-bounds offset into stack slot')
x = Operand('x', Mem, doc='Value to be stored')
a = Operand('a', Mem, doc='Value loaded')
p = Operand('p', iAddr)
addr = Operand('addr', iAddr)
stack_load = Instruction(
@@ -247,6 +248,44 @@ stack_addr = Instruction(
""",
ins=(SS, Offset), outs=addr)
#
# WebAssembly bounds-checked heap accesses.
#
# TODO: Add a `heap` operand that selects between multiple heaps.
# TODO: Should the immediate offset be a `u32`?
# TODO: Distinguish between `iAddr` for a heap and for a target address? i.e.,
# 32-bit WebAssembly on a 64-bit target has two different types.
Offset = Operand('Offset', uoffset32, 'Unsigned offset to effective address')
heap_load = Instruction(
'heap_load', r"""
Load a value at the address :math:`p + Offset` in the heap H.
Trap if the heap access would be out of bounds.
""",
ins=(p, Offset), outs=a)
heap_store = Instruction(
'heap_store', r"""
Store a value at the address :math:`p + Offset` in the heap H.
Trap if the heap access would be out of bounds.
""",
ins=(x, p, Offset))
heap_addr = Instruction(
'heap_addr', r"""
Bounds check and compute absolute address of heap memory.
Verify that the address range ``p .. p + Size - 1`` is valid in the
heap H, and trap if not.
Convert the heap-relative address in ``p`` to a real absolute address
and return it.
""",
ins=(p, Offset), outs=addr)
#
# Materializing constants.
#

View File

@@ -6,7 +6,7 @@
use ir::types;
use ir::{InstructionData, DataFlowGraph, Cursor};
use ir::{Opcode, Type, Inst, Value, Ebb, JumpTable, SigRef, FuncRef, StackSlot, ValueList};
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, Offset32};
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, Offset32, Uoffset32};
use ir::condcodes::{IntCC, FloatCC};
/// Base trait for instruction builders.

View File

@@ -11,7 +11,7 @@ use std::str::FromStr;
use std::ops::{Deref, DerefMut};
use ir::{Value, Type, Ebb, JumpTable, SigRef, FuncRef, StackSlot};
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, Offset32};
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, Offset32, Uoffset32};
use ir::condcodes::*;
use ir::types;
use ir::DataFlowGraph;
@@ -240,6 +240,18 @@ pub enum InstructionData {
stack_slot: StackSlot,
offset: Offset32,
},
HeapLoad {
opcode: Opcode,
ty: Type,
arg: Value,
offset: Uoffset32,
},
HeapStore {
opcode: Opcode,
ty: Type,
args: [Value; 2],
offset: Uoffset32,
},
}
/// A variable list of `Value` operands used for function call arguments and passing arguments to

View File

@@ -269,7 +269,9 @@ impl<'a> Verifier<'a> {
&ExtractLane { .. } |
&IntCompare { .. } |
&IntCompareImm { .. } |
&FloatCompare { .. } => {}
&FloatCompare { .. } |
&HeapLoad { .. } |
&HeapStore { .. } => {}
}
Ok(())

View File

@@ -320,6 +320,8 @@ pub fn write_operands(w: &mut Write, dfg: &DataFlowGraph, inst: Inst) -> Result
offset,
..
} => write!(w, " {}, {}{}", arg, stack_slot, offset),
HeapLoad { arg, offset, .. } => write!(w, " {}{}", arg, offset),
HeapStore { args, offset, .. } => write!(w, " {}, {}{}", args[0], args[1], offset),
}
}

View File

@@ -227,15 +227,18 @@ impl<'a> Context<'a> {
InstructionData::IntCompareImm { ref mut arg, .. } |
InstructionData::Unary { ref mut arg, .. } |
InstructionData::UnarySplit { ref mut arg, .. } |
InstructionData::StackStore { ref mut arg, .. } => {
InstructionData::StackStore { ref mut arg, .. } |
InstructionData::HeapLoad { ref mut arg, .. } => {
self.map.rewrite_value(arg, loc)?;
}
// `args: Value[2]`
InstructionData::Binary { ref mut args, .. } |
InstructionData::BinaryOverflow { ref mut args, .. } |
InstructionData::InsertLane { ref mut args, .. } |
InstructionData::IntCompare { ref mut args, .. } |
InstructionData::FloatCompare { ref mut args, .. } => {
InstructionData::FloatCompare { ref mut args, .. } |
InstructionData::HeapStore { ref mut args, .. } => {
self.map.rewrite_values(args, loc)?;
}
@@ -1710,6 +1713,28 @@ impl<'a> Parser<'a> {
offset: offset,
}
}
InstructionFormat::HeapLoad => {
let addr = self.match_value("expected SSA value address")?;
let offset = self.optional_uoffset32()?;
InstructionData::HeapLoad {
opcode: opcode,
ty: VOID,
arg: addr,
offset: offset,
}
}
InstructionFormat::HeapStore => {
let arg = self.match_value("expected SSA value operand")?;
self.match_token(Token::Comma, "expected ',' between operands")?;
let addr = self.match_value("expected SSA value address")?;
let offset = self.optional_uoffset32()?;
InstructionData::HeapStore {
opcode: opcode,
ty: VOID,
args: [arg, addr],
offset: offset,
}
}
};
Ok(idata)
}