mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
wasm: simplify ElementSection
This commit is contained in:
parent
7958158d89
commit
4e7c1fe5e1
1 changed files with 15 additions and 109 deletions
|
@ -760,114 +760,33 @@ impl<'a> Serialize for ExportSection<'a> {
|
|||
*
|
||||
*******************************************************************/
|
||||
|
||||
/*
|
||||
https://webassembly.github.io/spec/core/binary/modules.html#binary-elemsec
|
||||
|
||||
Note: Wasm MVP only had variant 0x00, and tables only contained functions.
|
||||
|
||||
byte fields ⇒ syntax
|
||||
-------------------------------------------------------------------------------------------------------------------------------------
|
||||
0x00 e:expr y∗:vec(funcidx) ⇒ {type funcref, init ((ref.func y) end)∗, mode active {table 0, offset e}}
|
||||
0x01 et:elemkind y∗:vec(funcidx) ⇒ {type et, init ((ref.func y) end)∗, mode passive}
|
||||
0x02 x:tableidx e:expr et:elemkind y∗:vec(funcidx) ⇒ {type et, init ((ref.func y) end)∗, mode active {table x, offset e}}
|
||||
0x03 et:elemkind y∗:vec(funcidx) ⇒ {type et, init ((ref.func y) end)∗, mode declarative}
|
||||
|
||||
0x04 e:expr el∗:vec(expr) ⇒ {type funcref, init el∗, mode active {table 0, offset e}}
|
||||
0x05 et:reftype el∗:vec(expr) ⇒ {type et, init el∗, mode passive}
|
||||
0x06 x:tableidx e:expr et:reftype el∗:vec(expr) ⇒ {type et, init el∗, mode active {table x, offset e}}
|
||||
0x07 et:reftype el∗:vec(expr) ⇒ {type et, init el ∗ , mode declarative}
|
||||
|
||||
The initial byte can be interpreted as a bitfield
|
||||
Bit 0 indicates a passive or declarative segment
|
||||
Bit 1 indicates the presence of an explicit table index for an active segment and otherwise distinguishes passive from declarative segments
|
||||
Bit 2 indicates the use of element type and element expressions instead of element kind and element indices.
|
||||
|
||||
Active means "element is loaded into the table on module instantiation"
|
||||
Passive means it's loaded by explicit instructions in the code section
|
||||
Declarative is a declaration that a reference will be taken at runtime
|
||||
|
||||
Sigh. This is only the post-MVP version of Wasm! Some day it'll end up as convoluted as x86, wait and see.
|
||||
*/
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
enum ElementKind {
|
||||
FuncRef = 0,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[allow(dead_code)]
|
||||
enum ElementSegmentFormatId {
|
||||
/// Currently only supporting the original Wasm MVP format since it's the only one in wide use.
|
||||
/// There are newer formats for other table types, with complex encodings to preserve backward compatibility
|
||||
/// (Already going down the same path as x86!)
|
||||
ActiveImplicitTableIndex = 0x00,
|
||||
PassiveKindAndIndex = 0x01,
|
||||
ActiveExplicitTableKindAndIndex = 0x02,
|
||||
DeclarativeKindAndIndex = 0x03,
|
||||
ActiveImplicitTableTypeAndExpr = 0x04,
|
||||
PassiveTypeAndExpr = 0x05,
|
||||
ActiveExplicitTableTypeAndExpr = 0x06,
|
||||
DeclarativeTypeAndExpr = 0x07,
|
||||
}
|
||||
|
||||
// A representation based on the (convoluted) binary format.
|
||||
// NOTE: If we ever need a more intuitive format, we can base it on the syntax doc
|
||||
// https://webassembly.github.io/spec/core/syntax/modules.html#syntax-elem
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
enum ElementSegment<'a> {
|
||||
/// This is the only variant we currently use. It is from the original Wasm MVP.
|
||||
/// The rest are dead code but kept in case we need them later.
|
||||
ActiveImplicitTableIndex {
|
||||
offset: ConstExpr,
|
||||
fn_indices: Vec<'a, u32>,
|
||||
},
|
||||
PassiveKindAndIndex {
|
||||
kind: ElementKind,
|
||||
fn_indices: Vec<'a, u32>,
|
||||
},
|
||||
ActiveExplicitTableKindAndIndex {
|
||||
table_idx: u32,
|
||||
offset: ConstExpr,
|
||||
kind: ElementKind,
|
||||
fn_indices: Vec<'a, u32>,
|
||||
},
|
||||
DeclarativeKindAndIndex {
|
||||
kind: ElementKind,
|
||||
fn_indices: Vec<'a, u32>,
|
||||
},
|
||||
ActiveImplicitTableTypeAndExpr {
|
||||
offset: ConstExpr,
|
||||
init: Vec<'a, ConstExpr>,
|
||||
},
|
||||
PassiveTypeAndExpr {
|
||||
elem_type: RefType,
|
||||
init: Vec<'a, ConstExpr>,
|
||||
},
|
||||
ActiveExplicitTableTypeAndExpr {
|
||||
table_idx: u32,
|
||||
offset: ConstExpr,
|
||||
elem_type: RefType,
|
||||
init: Vec<'a, ConstExpr>,
|
||||
},
|
||||
DeclarativeTypeAndExpr {
|
||||
elem_type: RefType,
|
||||
init: Vec<'a, ConstExpr>,
|
||||
},
|
||||
struct ElementSegment<'a> {
|
||||
offset: ConstExpr,
|
||||
fn_indices: Vec<'a, u32>,
|
||||
}
|
||||
|
||||
impl<'a> ElementSegment<'a> {
|
||||
fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Self {
|
||||
// In practice we only need the original MVP format
|
||||
let format_id = bytes[*cursor];
|
||||
assert!(format_id == ElementSegmentFormatId::ActiveImplicitTableIndex as u8);
|
||||
debug_assert!(format_id == ElementSegmentFormatId::ActiveImplicitTableIndex as u8);
|
||||
*cursor += 1;
|
||||
|
||||
// The table index offset is encoded as a ConstExpr, but only I32 makes sense
|
||||
let const_expr_opcode = bytes[*cursor];
|
||||
assert!(const_expr_opcode == OpCode::I32CONST as u8);
|
||||
debug_assert!(const_expr_opcode == OpCode::I32CONST as u8);
|
||||
*cursor += 1;
|
||||
let offset = parse_u32_or_panic(bytes, cursor);
|
||||
assert!(bytes[*cursor] == OpCode::END as u8);
|
||||
debug_assert!(bytes[*cursor] == OpCode::END as u8);
|
||||
*cursor += 1;
|
||||
|
||||
let num_elems = parse_u32_or_panic(bytes, cursor);
|
||||
|
@ -878,7 +797,7 @@ impl<'a> ElementSegment<'a> {
|
|||
fn_indices.push(fn_idx);
|
||||
}
|
||||
|
||||
ElementSegment::ActiveImplicitTableIndex {
|
||||
ElementSegment {
|
||||
offset: ConstExpr::I32(offset as i32),
|
||||
fn_indices,
|
||||
}
|
||||
|
@ -889,25 +808,16 @@ impl<'a> ElementSegment<'a> {
|
|||
let constexpr_opcode = 1;
|
||||
let constexpr_value = MAX_SIZE_ENCODED_U32;
|
||||
let vec_len = MAX_SIZE_ENCODED_U32;
|
||||
let vec_contents = MAX_SIZE_ENCODED_U32
|
||||
* if let ElementSegment::ActiveImplicitTableIndex { fn_indices, .. } = &self {
|
||||
fn_indices.len()
|
||||
} else {
|
||||
internal_error!("Unsupported ElementSegment {:?}", self)
|
||||
};
|
||||
let vec_contents = MAX_SIZE_ENCODED_U32 * self.fn_indices.len();
|
||||
variant_id + constexpr_opcode + constexpr_value + vec_len + vec_contents
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Serialize for ElementSegment<'a> {
|
||||
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
|
||||
if let ElementSegment::ActiveImplicitTableIndex { offset, fn_indices } = &self {
|
||||
buffer.append_u8(ElementSegmentFormatId::ActiveImplicitTableIndex as u8);
|
||||
offset.serialize(buffer);
|
||||
fn_indices.serialize(buffer);
|
||||
} else {
|
||||
internal_error!("Unsupported ElementSegment {:?}", self)
|
||||
}
|
||||
buffer.append_u8(ElementSegmentFormatId::ActiveImplicitTableIndex as u8);
|
||||
self.offset.serialize(buffer);
|
||||
self.fn_indices.serialize(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -940,11 +850,7 @@ impl<'a> ElementSection<'a> {
|
|||
pub fn indirect_callees(&self, arena: &'a Bump) -> Vec<'a, u32> {
|
||||
let mut result = bumpalo::vec![in arena];
|
||||
for segment in self.segments.iter() {
|
||||
if let ElementSegment::ActiveImplicitTableIndex { fn_indices, .. } = segment {
|
||||
result.extend_from_slice(fn_indices);
|
||||
} else {
|
||||
internal_error!("Unsupported ElementSegment {:?}", self)
|
||||
}
|
||||
result.extend_from_slice(&segment.fn_indices);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue