88
99use crate :: backend:: Backend ;
1010use crate :: ir:: * ;
11+ use anyhow:: Result ;
1112
1213/// Emit preamble for generated Rust files.
1314pub fn rust_code_preamble ( ) -> String {
@@ -35,34 +36,58 @@ pub fn emit_const_globals<B: Backend>(_backend: &B, info: &ModuleInfo) -> String
3536
3637/// Generate element segment initialization code for a table.
3738///
38- /// `table_receiver` is the expression to access the table (e.g., "module.table" or "table").
39- pub fn emit_element_segments ( info : & ModuleInfo , table_receiver : & str ) -> String {
39+ /// Element segments are declared in the Wasm binary's `element` section. Each
40+ /// segment specifies a base offset into the table and a list of function
41+ /// references to write into consecutive slots starting at that offset. This
42+ /// function emits the Rust `table.set(...)` calls that perform those writes
43+ /// inside the generated module's `new()` constructor.
44+ pub fn emit_element_segments ( info : & ModuleInfo , table_receiver : & str ) -> Result < String > {
4045 let mut code = String :: new ( ) ;
46+
47+ // A Wasm module may declare multiple element segments, each covering a
48+ // contiguous slice of table slots at a different base offset.
4149 for seg in & info. element_segments {
50+ // `seg.offset` is the base table index for this segment.
51+ // `seg.func_indices` lists the local function indices to place into
52+ // consecutive slots: slot (offset+0), (offset+1), ...
53+ // All indices are already in the local index space (imports subtracted).
4254 for ( i, local_func_idx) in seg. func_indices . iter ( ) . enumerate ( ) {
55+ // Absolute table slot = segment base + position within segment.
4356 let table_idx = seg. offset + i;
57+
58+ // Each table entry records the function's canonical type index so
59+ // that `call_indirect` can validate the expected signature at the
60+ // call site before dispatching. We fetch it from the IR function.
4461 let type_idx = info
4562 . ir_function ( * local_func_idx)
4663 . map ( |f| f. type_idx . as_usize ( ) )
47- . unwrap_or ( 0 ) ;
64+ . ok_or ( anyhow:: anyhow!( "Invalid function index" ) ) ?;
65+
66+ // Emit one table initialisation statement per slot.
67+ //
68+ // TODO: `.unwrap()` panics if `table_idx` exceeds the table's
69+ // allocated size. The table is sized from the same Wasm module
70+ // so this should be unreachable, but it is not formally proven.
71+ // Generated code should use `?` and propagate a
72+ // `ConstructionError` to stay panic-free (required by no_std).
4873 code. push_str ( & format ! (
4974 " {}.set({}, Some(FuncRef {{ type_index: {}, func_index: {} }})).unwrap();\n " ,
50- table_receiver,
51- table_idx,
52- type_idx,
53- local_func_idx. as_usize( )
75+ table_receiver, // "module.table" or "table"
76+ table_idx, // absolute slot in the table
77+ type_idx, // for type-checking on call_indirect
78+ local_func_idx. as_usize( ) // which function to dispatch to
5479 ) ) ;
5580 }
5681 }
57- code
82+ Ok ( code)
5883}
5984
6085/// Generate the `pub fn new() -> WasmModule` or `pub fn new() -> WasmResult<WasmModule>` constructor.
6186pub fn generate_constructor < B : Backend > (
6287 _backend : & B ,
6388 info : & ModuleInfo ,
6489 has_mut_globals : bool ,
65- ) -> String {
90+ ) -> Result < String > {
6691 let mut code = String :: new ( ) ;
6792
6893 // Simple constructor for modules with no initialization
@@ -71,10 +96,10 @@ pub fn generate_constructor<B: Backend>(
7196 && info. data_segments . is_empty ( )
7297 && info. element_segments . is_empty ( )
7398 {
74- code. push_str ( "pub fn new() -> Result<WasmModule, herkos_runtime:: ConstructionError> {\n " ) ;
99+ code. push_str ( "pub fn new() -> Result<WasmModule, ConstructionError> {\n " ) ;
75100 code. push_str ( " Ok(WasmModule(LibraryModule::new((), Table::try_new(0)?)))\n " ) ;
76101 code. push_str ( "}\n " ) ;
77- return code;
102+ return Ok ( code) ;
78103 }
79104
80105 code. push_str ( "pub fn new() -> WasmResult<WasmModule> {\n " ) ;
@@ -130,13 +155,13 @@ pub fn generate_constructor<B: Backend>(
130155 }
131156
132157 // Element segment initialization
133- code. push_str ( & emit_element_segments ( info, "module.table" ) ) ;
158+ code. push_str ( & emit_element_segments ( info, "module.table" ) ? ) ;
134159
135160 code. push_str ( " Ok(WasmModule(module))\n " ) ;
136161 } else if !info. element_segments . is_empty ( ) {
137162 // Need mutable table for element initialization
138163 code. push_str ( & format ! ( " let mut table = {};\n " , table_init) ) ;
139- code. push_str ( & emit_element_segments ( info, "table" ) ) ;
164+ code. push_str ( & emit_element_segments ( info, "table" ) ? ) ;
140165 code. push_str ( & format ! (
141166 " Ok(WasmModule(LibraryModule::new({}, table)))\n " ,
142167 globals_init
@@ -149,5 +174,5 @@ pub fn generate_constructor<B: Backend>(
149174 }
150175
151176 code. push_str ( "}\n " ) ;
152- code
177+ Ok ( code)
153178}
0 commit comments