diff --git a/src/stack_height/mod.rs b/src/stack_height/mod.rs index 5ef075e..165e3b9 100644 --- a/src/stack_height/mod.rs +++ b/src/stack_height/mod.rs @@ -25,11 +25,12 @@ //! Because stack height is increased prior the call few problems arises: //! //! - Stack height isn't increased upon an entry to the first function, i.e. exported function. +//! - Start function is executed externally (similar to exported functions). //! - It is statically unknown what function will be invoked in an indirect call. //! //! The solution for this problems is to generate a intermediate functions, called 'thunks', which //! will increase before and decrease the stack height after the call to original function, and -//! then make exported function and table entries to point to a corresponding thunks. +//! then make exported function and table entries, start section to point to a corresponding thunks. //! //! # Stack cost //! diff --git a/src/stack_height/thunk.rs b/src/stack_height/thunk.rs index 747ef7d..f4c3b31 100644 --- a/src/stack_height/thunk.rs +++ b/src/stack_height/thunk.rs @@ -35,6 +35,8 @@ pub(crate) fn generate_thunks( .elements_section() .map(|es| es.entries()) .unwrap_or(&[]); + let start_func_idx = module + .start_section(); let exported_func_indicies = exports.iter().filter_map(|entry| match *entry.internal() { Internal::Function(ref function_idx) => Some(*function_idx), @@ -48,7 +50,7 @@ pub(crate) fn generate_thunks( // Replacement map is at least export section size. let mut replacement_map: Map = Map::new(); - for func_idx in exported_func_indicies.chain(table_func_indicies) { + for func_idx in exported_func_indicies.chain(table_func_indicies).chain(start_func_idx.into_iter()) { let callee_stack_cost = ctx.stack_cost(func_idx).ok_or_else(|| { Error(format!("function with idx {} isn't found", func_idx)) })?; @@ -154,6 +156,9 @@ pub(crate) fn generate_thunks( } } } + elements::Section::Start(ref mut start_idx) => { + fixup(start_idx) + } _ => {} } } diff --git a/tests/diff.rs b/tests/diff.rs index 4dc343a..4a6c4bd 100644 --- a/tests/diff.rs +++ b/tests/diff.rs @@ -88,6 +88,7 @@ macro_rules! def_stack_height_test { } def_stack_height_test!(simple); +def_stack_height_test!(start); def_stack_height_test!(table); def_stack_height_test!(global); def_stack_height_test!(imports); diff --git a/tests/expectations/stack-height/start.wat b/tests/expectations/stack-height/start.wat new file mode 100644 index 0000000..40587c3 --- /dev/null +++ b/tests/expectations/stack-height/start.wat @@ -0,0 +1,44 @@ +(module + (type (;0;) (func (param i32 i32))) + (type (;1;) (func)) + (import "env" "ext_return" (func (;0;) (type 0))) + (import "env" "memory" (memory (;0;) 1 1)) + (func (;1;) (type 1) + (local i32)) + (func (;2;) (type 1)) + (func (;3;) (type 1) + get_global 0 + i32.const 1 + i32.add + set_global 0 + get_global 0 + i32.const 1024 + i32.gt_u + if ;; label = @1 + unreachable + end + call 1 + get_global 0 + i32.const 1 + i32.sub + set_global 0) + (func (;4;) (type 1) + get_global 0 + i32.const 1 + i32.add + set_global 0 + get_global 0 + i32.const 1024 + i32.gt_u + if ;; label = @1 + unreachable + end + call 1 + get_global 0 + i32.const 1 + i32.sub + set_global 0) + (global (;0;) (mut i32) (i32.const 0)) + (export "exported_start" (func 4)) + (export "call" (func 2)) + (start 4)) diff --git a/tests/fixtures/stack-height/start.wat b/tests/fixtures/stack-height/start.wat new file mode 100644 index 0000000..595bdef --- /dev/null +++ b/tests/fixtures/stack-height/start.wat @@ -0,0 +1,11 @@ +(module + (import "env" "ext_return" (func $ext_return (param i32 i32))) + (import "env" "memory" (memory 1 1)) + + (start $start) + (func $start (export "exported_start") + (local i32) + ) + (func (export "call") + ) +)