mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +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)]
|
#[repr(u8)]
|
||||||
#[derive(Debug)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
enum ElementKind {
|
|
||||||
FuncRef = 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u8)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
enum ElementSegmentFormatId {
|
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,
|
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)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
struct ElementSegment<'a> {
|
||||||
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,
|
offset: ConstExpr,
|
||||||
fn_indices: Vec<'a, u32>,
|
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>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ElementSegment<'a> {
|
impl<'a> ElementSegment<'a> {
|
||||||
fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Self {
|
fn parse(arena: &'a Bump, bytes: &[u8], cursor: &mut usize) -> Self {
|
||||||
// In practice we only need the original MVP format
|
// In practice we only need the original MVP format
|
||||||
let format_id = bytes[*cursor];
|
let format_id = bytes[*cursor];
|
||||||
assert!(format_id == ElementSegmentFormatId::ActiveImplicitTableIndex as u8);
|
debug_assert!(format_id == ElementSegmentFormatId::ActiveImplicitTableIndex as u8);
|
||||||
*cursor += 1;
|
*cursor += 1;
|
||||||
|
|
||||||
// The table index offset is encoded as a ConstExpr, but only I32 makes sense
|
// The table index offset is encoded as a ConstExpr, but only I32 makes sense
|
||||||
let const_expr_opcode = bytes[*cursor];
|
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;
|
*cursor += 1;
|
||||||
let offset = parse_u32_or_panic(bytes, cursor);
|
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;
|
*cursor += 1;
|
||||||
|
|
||||||
let num_elems = parse_u32_or_panic(bytes, cursor);
|
let num_elems = parse_u32_or_panic(bytes, cursor);
|
||||||
|
@ -878,7 +797,7 @@ impl<'a> ElementSegment<'a> {
|
||||||
fn_indices.push(fn_idx);
|
fn_indices.push(fn_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementSegment::ActiveImplicitTableIndex {
|
ElementSegment {
|
||||||
offset: ConstExpr::I32(offset as i32),
|
offset: ConstExpr::I32(offset as i32),
|
||||||
fn_indices,
|
fn_indices,
|
||||||
}
|
}
|
||||||
|
@ -889,25 +808,16 @@ impl<'a> ElementSegment<'a> {
|
||||||
let constexpr_opcode = 1;
|
let constexpr_opcode = 1;
|
||||||
let constexpr_value = MAX_SIZE_ENCODED_U32;
|
let constexpr_value = MAX_SIZE_ENCODED_U32;
|
||||||
let vec_len = MAX_SIZE_ENCODED_U32;
|
let vec_len = MAX_SIZE_ENCODED_U32;
|
||||||
let vec_contents = MAX_SIZE_ENCODED_U32
|
let vec_contents = MAX_SIZE_ENCODED_U32 * self.fn_indices.len();
|
||||||
* if let ElementSegment::ActiveImplicitTableIndex { fn_indices, .. } = &self {
|
|
||||||
fn_indices.len()
|
|
||||||
} else {
|
|
||||||
internal_error!("Unsupported ElementSegment {:?}", self)
|
|
||||||
};
|
|
||||||
variant_id + constexpr_opcode + constexpr_value + vec_len + vec_contents
|
variant_id + constexpr_opcode + constexpr_value + vec_len + vec_contents
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Serialize for ElementSegment<'a> {
|
impl<'a> Serialize for ElementSegment<'a> {
|
||||||
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
|
fn serialize<T: SerialBuffer>(&self, buffer: &mut T) {
|
||||||
if let ElementSegment::ActiveImplicitTableIndex { offset, fn_indices } = &self {
|
|
||||||
buffer.append_u8(ElementSegmentFormatId::ActiveImplicitTableIndex as u8);
|
buffer.append_u8(ElementSegmentFormatId::ActiveImplicitTableIndex as u8);
|
||||||
offset.serialize(buffer);
|
self.offset.serialize(buffer);
|
||||||
fn_indices.serialize(buffer);
|
self.fn_indices.serialize(buffer);
|
||||||
} else {
|
|
||||||
internal_error!("Unsupported ElementSegment {:?}", self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -940,11 +850,7 @@ impl<'a> ElementSection<'a> {
|
||||||
pub fn indirect_callees(&self, arena: &'a Bump) -> Vec<'a, u32> {
|
pub fn indirect_callees(&self, arena: &'a Bump) -> Vec<'a, u32> {
|
||||||
let mut result = bumpalo::vec![in arena];
|
let mut result = bumpalo::vec![in arena];
|
||||||
for segment in self.segments.iter() {
|
for segment in self.segments.iter() {
|
||||||
if let ElementSegment::ActiveImplicitTableIndex { fn_indices, .. } = segment {
|
result.extend_from_slice(&segment.fn_indices);
|
||||||
result.extend_from_slice(fn_indices);
|
|
||||||
} else {
|
|
||||||
internal_error!("Unsupported ElementSegment {:?}", self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue