Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize shadow stack instruction sequences #928

Open
wants to merge 51 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
534d556
add new stack pointer optimized instructions
Robbepop Feb 4, 2024
05a7f26
apply clippy suggestion
Robbepop Feb 4, 2024
874dd5f
implement execution of new instructions
Robbepop Feb 4, 2024
d697023
implement i32.add_imm + global.set fusion
Robbepop Feb 6, 2024
c0159af
only fuse for global.set with index 0
Robbepop Feb 6, 2024
d9321d1
improve comment
Robbepop Feb 6, 2024
2f84ac1
add TODO comment
Robbepop Feb 6, 2024
65c4882
apply rustfmt
Robbepop Feb 6, 2024
f8c0f57
fix intra doc link
Robbepop Feb 6, 2024
157ab4d
add global.get 0 + i32.add_imm fusion
Robbepop Feb 7, 2024
93bdbda
extract global.set with immutable input translation
Robbepop Feb 9, 2024
72c0028
improve i32_add_imm_into_global_0 constructor
Robbepop Feb 9, 2024
0bd8253
add new shadow stack opts tests
Robbepop Feb 9, 2024
d8b126b
make fuse_i32_eqz more robust
Robbepop Feb 9, 2024
bf4bf77
make cmp+branch fusion more robust
Robbepop Feb 9, 2024
672defb
remove unnecessary calls to reset_last_instr
Robbepop Feb 9, 2024
70bdd0d
improve i32_add_imm_from_global_0 constructor
Robbepop Feb 9, 2024
b889902
adjust tests
Robbepop Feb 9, 2024
38a7057
adjust tests
Robbepop Feb 9, 2024
f40b1a0
add bytecode constructor for I32AddImmInoutGlobal0
Robbepop Feb 9, 2024
cc96940
add op-code fusion for I32AddImmInoutGlobal0
Robbepop Feb 9, 2024
85b80a2
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Feb 9, 2024
d1307d1
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Feb 9, 2024
9c1d697
add test for I32AddImmIntoGlobal0 with I32Sub fusion
Robbepop Feb 11, 2024
72993e6
fix bug with shadow stack opt for i32::MIN values of i32.sub
Robbepop Feb 11, 2024
42f9936
improve shadow stack opt tests
Robbepop Feb 11, 2024
c98eeee
make shadow stack global.set opts work on large integers
Robbepop Feb 11, 2024
b46b533
always translate i{32,64}.sub as i{32,64}.add if rhs is const
Robbepop Feb 12, 2024
4f499bb
rename test
Robbepop Feb 12, 2024
d8a1fe8
adjust tests for shadow stack opts
Robbepop Feb 12, 2024
7f0690d
remove accidentally duplicated code
Robbepop Feb 12, 2024
f8cf6c9
apply clippy suggestions
Robbepop Feb 12, 2024
0a3b3a3
apply clippy suggestions (tests)
Robbepop Feb 12, 2024
d21ce29
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Feb 12, 2024
289de51
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Mar 13, 2024
f848742
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Mar 14, 2024
25c2847
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Mar 20, 2024
ab8126a
fix new tests after merge
Robbepop Mar 20, 2024
590e72f
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Mar 23, 2024
6cb3be7
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Mar 23, 2024
b0228fb
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Mar 23, 2024
2707fcf
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Mar 24, 2024
d61ba01
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Mar 25, 2024
8db0b3c
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Mar 28, 2024
15cd321
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Apr 22, 2024
c2b9c0b
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Jun 18, 2024
993728a
fix post-merge compile errors
Robbepop Jun 18, 2024
9b80c64
Merge branch 'master' into rf-shadow-stack-opt
Robbepop Jun 21, 2024
5034632
Merge branch 'main' into rf-shadow-stack-opt
Robbepop Jul 3, 2024
d021e82
fix internal doc link
Robbepop Jul 3, 2024
27264e3
Merge branch 'main' into rf-shadow-stack-opt
Robbepop Jul 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions crates/wasmi/src/engine/bytecode/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,30 @@ impl Instruction {
}
}

/// Creates a new [`Instruction::I32AddImmIntoGlobal0`].
pub fn i32_add_imm_into_global_0(lhs: Register, rhs: impl Into<Const32<i32>>) -> Self {
Self::I32AddImmIntoGlobal0 {
lhs,
rhs: rhs.into(),
}
}

/// Creates a new [`Instruction::I32AddImmFromGlobal0`].
pub fn i32_add_imm_from_global_0(result: Register, rhs: impl Into<Const32<i32>>) -> Self {
Self::I32AddImmFromGlobal0 {
result,
rhs: rhs.into(),
}
}

/// Creates a new [`Instruction::I32AddImmInoutGlobal0`].
pub fn i32_add_imm_inout_global_0(result: Register, rhs: impl Into<Const32<i32>>) -> Self {
Self::I32AddImmInoutGlobal0 {
result,
rhs: rhs.into(),
}
}

/// Creates a new [`Instruction::F32CopysignImm`] instruction.
pub fn f32_copysign_imm(result: Register, lhs: Register, rhs: Sign) -> Self {
Self::F32CopysignImm(BinInstrImm::new(result, lhs, rhs))
Expand Down
85 changes: 85 additions & 0 deletions crates/wasmi/src/engine/bytecode/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,91 @@ pub enum Instruction {
input: Const16<i64>,
},

/// Fused instruction to add a register and constant `i32` value to the `global` variable at index 0.
///
/// This instruction represents the following Wasm instruction sequence:
///
/// ```wat
/// local.get $v
/// i32.const $n
/// i32.add
/// global.set 0
/// ```
///
/// Where `$v` is a local variable index and `$n` is a `i32` literal.
///
/// # Note
///
/// - This is an instruction primarily intended to optimize Wasm instruction
/// sequences that emulate the shadow stack pointer arithmetic.
/// - We operate on the global variable at index 0 because that is the index
/// that LLVM tends to use for its shadow stack pointer. Other Wasm producers
/// have not been checked and might differ.
I32AddImmIntoGlobal0 {
/// The `lhs` register for the addition.
lhs: Register,
/// The `rhs` constant value for the addition.
rhs: Const32<i32>,
},
/// Fused instruction to add a constant `i32` value to the `global` variable at index 0.
///
/// This instruction represents the following Wasm instruction sequence:
///
/// ```wat
/// global.get 0
/// i32.const $n
/// i32.add
/// ```
///
/// Where `$n` is a `i32` literal.
///
/// # Note
///
/// - This is an instruction primarily intended to optimize Wasm instruction
/// sequences that emulate the shadow stack pointer arithmetic.
/// - We operate on the global variable at index 0 because that is the index
/// that LLVM tends to use for its shadow stack pointer. Other Wasm producers
/// have not been checked and might differ.
I32AddImmFromGlobal0 {
/// The register storing the result of the instruction.
result: Register,
/// The `rhs` constant value for the addition.
rhs: Const32<i32>,
},
/// Fused instruction to add a constant `i32` value to the `global` variable at index 0.
///
/// The result of this addition is stored both into
///
/// - the `result` register
/// - the `global` variable at index 0.
///
/// This instruction represents the following Wasm instruction sequence:
///
/// ```wat
/// global.get 0
/// i32.const $n
/// i32.add
/// local.tee $v
/// global.set 0
/// ```
///
/// Where `$v` is a local variable index and `$n` is a `i32` literal.
///
/// # Note
///
/// - This is a refinement variant of [`Instruction::I32AddImmFromGlobal0`].
/// - This is an instruction primarily intended to optimize Wasm instruction
/// sequences that emulate the shadow stack pointer arithmetic.
/// - We operate on the global variable at index 0 because that is the index
/// that LLVM tends to use for its shadow stack pointer. Other Wasm producers
/// have not been checked and might differ.
I32AddImmInoutGlobal0 {
/// The register storing the result of the instruction.
result: Register,
/// The `rhs` constant value for the addition.
rhs: Const32<i32>,
},

/// Wasm `i32.load` equivalent Wasmi instruction.
///
/// # Encoding
Expand Down
9 changes: 9 additions & 0 deletions crates/wasmi/src/engine/executor/instrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,15 @@
Instr::GlobalSetI64Imm16 { global, input } => {
self.execute_global_set_i64imm16(&mut store.inner, global, input)
}
Instr::I32AddImmIntoGlobal0 { lhs, rhs } => {
self.execute_i32_add_imm_into_global_0(lhs, rhs)

Check warning on line 377 in crates/wasmi/src/engine/executor/instrs.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs.rs#L376-L377

Added lines #L376 - L377 were not covered by tests
}
Instr::I32AddImmFromGlobal0 { result, rhs } => {
self.execute_i32_add_imm_from_global_0(result, rhs)

Check warning on line 380 in crates/wasmi/src/engine/executor/instrs.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs.rs#L379-L380

Added lines #L379 - L380 were not covered by tests
}
Instr::I32AddImmInoutGlobal0 { result, rhs } => {
self.execute_i32_add_imm_inout_global_0(result, rhs)
}
Instr::I32Load(instr) => self.execute_i32_load(instr)?,
Instr::I32LoadAt(instr) => self.execute_i32_load_at(instr)?,
Instr::I32LoadOffset16(instr) => self.execute_i32_load_offset16(instr)?,
Expand Down
36 changes: 35 additions & 1 deletion crates/wasmi/src/engine/executor/instrs/global.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::Executor;
use crate::{
core::{hint, UntypedVal},
engine::bytecode::{Const16, GlobalIdx, Register},
engine::bytecode::{Const16, Const32, GlobalIdx, Register},
store::StoreInner,
};

Expand Down Expand Up @@ -78,4 +78,38 @@
};
self.next_instr()
}

/// Executes an [`Instruction::I32AddImmIntoGlobal0`].
#[inline(always)]
pub fn execute_i32_add_imm_into_global_0(&mut self, lhs: Register, rhs: Const32<i32>) {
let lhs: i32 = self.get_register_as(lhs);
let rhs: i32 = i32::from(rhs);
let result = lhs.wrapping_add(rhs);

Check warning on line 87 in crates/wasmi/src/engine/executor/instrs/global.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs/global.rs#L84-L87

Added lines #L84 - L87 were not covered by tests
// Safety: TODO
unsafe { self.cache.global.set(result.into()) };
self.next_instr()

Check warning on line 90 in crates/wasmi/src/engine/executor/instrs/global.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs/global.rs#L89-L90

Added lines #L89 - L90 were not covered by tests
}

/// Executes an [`Instruction::I32AddImmFromGlobal0`].
#[inline(always)]
pub fn execute_i32_add_imm_from_global_0(&mut self, result: Register, rhs: Const32<i32>) {

Check warning on line 95 in crates/wasmi/src/engine/executor/instrs/global.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs/global.rs#L95

Added line #L95 was not covered by tests
// Safety: TODO
let lhs: i32 = unsafe { self.cache.global.get() }.into();
let rhs: i32 = rhs.into();
self.set_register(result, lhs.wrapping_add(rhs));
self.next_instr()

Check warning on line 100 in crates/wasmi/src/engine/executor/instrs/global.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs/global.rs#L97-L100

Added lines #L97 - L100 were not covered by tests
}

/// Executes an [`Instruction::I32AddImmInoutGlobal0`].
#[inline(always)]
pub fn execute_i32_add_imm_inout_global_0(&mut self, result: Register, rhs: Const32<i32>) {

Check warning on line 105 in crates/wasmi/src/engine/executor/instrs/global.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs/global.rs#L105

Added line #L105 was not covered by tests
// Safety: TODO
let lhs: i32 = unsafe { self.cache.global.get() }.into();
let rhs: i32 = rhs.into();
let sum = lhs.wrapping_add(rhs);
// Safety: TODO
unsafe { self.cache.global.set(sum.into()) };
self.set_register(result, sum);
self.next_instr()

Check warning on line 113 in crates/wasmi/src/engine/executor/instrs/global.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs/global.rs#L113

Added line #L113 was not covered by tests
}
}
116 changes: 116 additions & 0 deletions crates/wasmi/src/engine/translator/instr_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,122 @@
Ok(())
}

/// Fuses a `global.get 0` and an `i32.add_imm` if possible.
///
/// Returns `true` if `Instruction` fusion was successful, `false` otherwise.
pub fn fuse_global_get_i32_add_imm(
&mut self,
lhs: Register,
rhs: i32,
stack: &mut ValueStack,
) -> Result<bool, Error> {
let Some(last_instr) = self.last_instr else {
// Without a last instruction there is no way to fuse.
return Ok(false);
};
let &Instruction::GlobalGet { result, global } = self.instrs.get(last_instr) else {
// It is only possible to fuse an `GlobalGet` with a `I32AddImm` instruction.
return Ok(false);
};
if u32::from(global) != 0 {
// There only is an optimized instruction for a global index of 0.
// This is because most Wasm producers use the global at index 0 for their shadow stack.
return Ok(false);

Check warning on line 919 in crates/wasmi/src/engine/translator/instr_encoder.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/instr_encoder.rs#L919

Added line #L919 was not covered by tests
}
if !matches!(stack.get_register_space(result), RegisterSpace::Dynamic) {
// Due to observable state it is impossible to fuse `GlobalGet` that has a non-`dynamic` result.
return Ok(false);

Check warning on line 923 in crates/wasmi/src/engine/translator/instr_encoder.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/instr_encoder.rs#L923

Added line #L923 was not covered by tests
};
if result != lhs {
// The `input` to `I32AddImm` must be the same as the result of `GetGlobal`.
return Ok(false);

Check warning on line 927 in crates/wasmi/src/engine/translator/instr_encoder.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/instr_encoder.rs#L927

Added line #L927 was not covered by tests
}
let rhs = <Const32<i32>>::from(rhs);
let fused_instr = Instruction::i32_add_imm_from_global_0(result, rhs);
_ = mem::replace(self.instrs.get_mut(last_instr), fused_instr);
stack.push_register(result)?;
Ok(true)
}

/// Fuses the `global.set` instruction with its previous instruction if possible.
///
/// Returns `true` if `Instruction` fusion was successful, `false` otherwise.
pub fn fuse_global_set(
&mut self,
global_index: u32,
input: Register,
stack: &mut ValueStack,
) -> bool {
/// Returns `true` if the previous [`Instruction`] and
/// its `result` can be fused with the `global.set` and its `input`.
fn is_fusable(stack: &mut ValueStack, result: Register, input: Register) -> bool {
if !matches!(stack.get_register_space(result), RegisterSpace::Dynamic) {
// Due to observable state it is impossible to fuse an instruction that has a non-`dynamic` result.
return false;

Check warning on line 950 in crates/wasmi/src/engine/translator/instr_encoder.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/instr_encoder.rs#L950

Added line #L950 was not covered by tests
};
if result != input {
// It is only possible to fuse the instructions if the `input` of `global.set`
// matches the `result` of the previous to-be-fused instruction.
return false;
}
true
}

if global_index != 0 {
// There only is an optimized instruction for a global index of 0.
// This is because most Wasm producers use the global at index 0 for their shadow stack.
return false;
}
let Some(last_instr) = self.last_instr else {
// Without a last instruction there is no way to fuse.
return false;
};
let fused_instr = match self.instrs.get(last_instr) {
Instruction::I32Add(instr) => {
if !is_fusable(stack, instr.result, input) {
return false;

Check warning on line 972 in crates/wasmi/src/engine/translator/instr_encoder.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/instr_encoder.rs#L972

Added line #L972 was not covered by tests
}
let Some(value) = stack.resolve_func_local_const(instr.rhs).map(i32::from) else {
// It is only possiblet o fuse `I32Add` if its `rhs` is a function local constant.
return false;

Check warning on line 976 in crates/wasmi/src/engine/translator/instr_encoder.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/instr_encoder.rs#L976

Added line #L976 was not covered by tests
};
let lhs = instr.lhs;
let rhs = <Const32<i32>>::from(value);
Instruction::i32_add_imm_into_global_0(lhs, rhs)
}
Instruction::I32Sub(instr) => {
if !is_fusable(stack, instr.result, input) {
return false;

Check warning on line 984 in crates/wasmi/src/engine/translator/instr_encoder.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/instr_encoder.rs#L982-L984

Added lines #L982 - L984 were not covered by tests
}
let Some(value) = stack.resolve_func_local_const(instr.rhs).map(i32::from) else {

Check warning on line 986 in crates/wasmi/src/engine/translator/instr_encoder.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/instr_encoder.rs#L986

Added line #L986 was not covered by tests
// It is only possiblet o fuse `I32Add` if its `rhs` is a function local constant.
return false;

Check warning on line 988 in crates/wasmi/src/engine/translator/instr_encoder.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/instr_encoder.rs#L988

Added line #L988 was not covered by tests
};
let lhs = instr.lhs;
let rhs = <Const32<i32>>::from(-value);
Instruction::i32_add_imm_into_global_0(lhs, rhs)

Check warning on line 992 in crates/wasmi/src/engine/translator/instr_encoder.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/instr_encoder.rs#L990-L992

Added lines #L990 - L992 were not covered by tests
}
Instruction::I32AddImm16(instr) => {
if !is_fusable(stack, instr.result, input) {
return false;

Check warning on line 996 in crates/wasmi/src/engine/translator/instr_encoder.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/instr_encoder.rs#L996

Added line #L996 was not covered by tests
}
let lhs = instr.reg_in;
let rhs = <Const32<i32>>::from(i32::from(instr.imm_in));
Instruction::i32_add_imm_into_global_0(lhs, rhs)
}
&Instruction::I32AddImmFromGlobal0 { result, rhs } => {
if result != input {
// The `input` to `GlobalSet` must be the same as the result of `I32AddImmFromGlobal0`.
return false;

Check warning on line 1005 in crates/wasmi/src/engine/translator/instr_encoder.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/instr_encoder.rs#L1005

Added line #L1005 was not covered by tests
}
Instruction::i32_add_imm_inout_global_0(result, rhs)
}
_ => return false,
};
_ = mem::replace(self.instrs.get_mut(last_instr), fused_instr);
true
}

/// Translates a Wasm `i32.eqz` instruction.
///
/// Tries to fuse `i32.eqz` with a previous `i32.{and,or,xor}` instruction if possible.
Expand Down
40 changes: 39 additions & 1 deletion crates/wasmi/src/engine/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
core::{TrapCode, UntypedVal, ValType},
engine::{
bytecode::{
self,
AnyConst32,
Const16,
Const32,
Expand All @@ -57,7 +58,7 @@
BlockType,
CompiledFunc,
},
module::{FuncIdx, FuncTypeIdx, ModuleHeader},
module::{self, FuncIdx, FuncTypeIdx, ModuleHeader},
Engine,
Error,
FuncType,
Expand Down Expand Up @@ -2553,4 +2554,41 @@
fuel_info,
)
}

/// Translates a `global.set` with an immutable input.
fn translate_global_set_imm(
&mut self,
global: bytecode::GlobalIdx,
input: TypedVal,
) -> Result<(), Error> {
let global_index = u32::from(global);
let (global_type, _init_value) = self
.module
.get_global(module::GlobalIdx::from(global_index));
debug_assert_eq!(global_type.content(), input.ty());
match global_type.content() {
ValType::I32 => {
if let Ok(value) = Const16::try_from(i32::from(input)) {
self.push_fueled_instr(
Instruction::global_set_i32imm16(global, value),
FuelCosts::entity,
)?;

Check warning on line 2575 in crates/wasmi/src/engine/translator/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/mod.rs#L2575

Added line #L2575 was not covered by tests
return Ok(());
}
}
ValType::I64 => {
if let Ok(value) = Const16::try_from(i64::from(input)) {
self.push_fueled_instr(
Instruction::global_set_i64imm16(global, value),
FuelCosts::entity,
)?;

Check warning on line 2584 in crates/wasmi/src/engine/translator/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/mod.rs#L2584

Added line #L2584 was not covered by tests
return Ok(());
}
}
_ => {}
};
let cref = self.alloc.stack.alloc_const(input)?;
self.push_fueled_instr(Instruction::global_set(global, cref), FuelCosts::entity)?;
Ok(())
}
}
3 changes: 3 additions & 0 deletions crates/wasmi/src/engine/translator/relink_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@
I::GlobalSet { .. } | I::GlobalSetI32Imm16 { .. } | I::GlobalSetI64Imm16 { .. } => {
Ok(false)
}
I::I32AddImmIntoGlobal0 { .. } => Ok(false),

Check warning on line 236 in crates/wasmi/src/engine/translator/relink_result.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/relink_result.rs#L236

Added line #L236 was not covered by tests
I::I32AddImmFromGlobal0 { result, .. } => relink_simple(result, new_result, old_result),
I::I32AddImmInoutGlobal0 { result, .. } => relink_simple(result, new_result, old_result),

Check warning on line 238 in crates/wasmi/src/engine/translator/relink_result.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/translator/relink_result.rs#L238

Added line #L238 was not covered by tests
I::I32Load(instr) |
I::I64Load(instr) |
I::F32Load(instr) |
Expand Down
7 changes: 7 additions & 0 deletions crates/wasmi/src/engine/translator/stack/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,13 @@ impl ValueStack {
self.consts.alloc(value.into())
}

/// Returns the [`UntypedVal`] of the function local constant value referred to by `register` if any.
///
/// Returns `None` if the `register` does not refer to a function local constant.
pub fn resolve_func_local_const(&self, register: Register) -> Option<UntypedVal> {
self.consts.get(register)
}

/// Returns the allocated function local constant values in reversed allocation order.
///
/// # Note
Expand Down
Loading
Loading