Compute delta_ip in side table for If/Else
Would like to get some feedback about this simplest case before computing delta_ip for the other branch types.
#46
There are a few issues:
side_table_last_entryis wrong, you need to supported nested blocks. You might need to put an index to the side table inLabelorLabelKind.- I don't think instruction index is the correct abstraction, I think we want instruction address. So you don't need
instr_idxat all and can useparser.save().as_ptr() as i32.Then in terms of design, I think we should keep
Contextconstant inExprand makeExpr::check_bodyreturn the side-table. We can then set it fromContext::check_modulewherecheck_bodyis called.
Thanks! The issues with parser.save().as_ptr() as i32 are
-
parser.save().as_ptr()overflows. -
The
DELTA_IP_MASKis too small to hold it.
Thanks! The issues with
parser.save().as_ptr() as i32are
parser.save().as_ptr()overflows.- The
DELTA_IP_MASKis too small to hold it.
Those are not issues because we only care about deltas between parser.save(). In the proposed design, I store directly the &'m [u8] delays converting to i32 until after we compute the delta.
I'm not sure it's worth iterating too much. It's simpler to just design correctly from the start, which means understanding the goal. Essentially, we want all occurrences of
skip_to_{else,end}()inexec.rsto be resolved from the side-table (to which we can addLoopto handle everything uniformly). This meansIf,Else,Br{,If}should each have an entry in the side-table andBrTableas much as its arguments. This defines when an entry is added. Then we need to fill their content, which is done onLoop,Else, andEnd(withLoopdone before the entry is added). This means that forLoopwe can store the parser position in theLabelKind(like done inexec.rs). ForElseandEnd, we need the side-table entries to register themselves in their labels. This means thatLabelshould contain anentries: Vec<(&'m [u8], usize)>recording for each side-table entry the parser position and the side-table length when it was added. Then inend_label()we can simply go over all entries compute the difference between the current parser position and the saved one to compute the delta IP, as well as the difference between the current side-table length and the index for the delta STP. We can then update the side-table entry.
Thanks! I implemented this design except Loop for the moment. I'll run some tests in the meanwhile.
I've merge main into dev/fast-interp. You might want to pull and merge your add-delta-ip branch into dev/fast-interp. This adds better support for unsupported operations, such that we can still run parts of a test instead of having to ignore it completely.
Could you clarify the hw-host error? I guess it results from the side table bit mask size issue.
I posted https://github.com/zhouwfang/wasefire/pull/2 to add val_cnt and pop_cnt on top of this PR. Could you also take a look at that? Thanks.
Could you clarify the hw-host error? I guess it results from the side table bit mask size issue.
Yes, this is indeed the side table masks being too short. So we'll probably have to use a u64 for the bit fields. You can also apply the following patch:
--- a/crates/interpreter/src/bit_field.rs
+++ b/crates/interpreter/src/bit_field.rs
@@ -29,6 +29,8 @@ fn offset(mask: u32) -> i32 {
pub fn into_field(mask: u32, value: u32) -> Result<u32, Error> {
let field = (value << mask.trailing_zeros()) & mask;
if from_field(mask, field) != value {
+ #[cfg(feature = "debug")]
+ eprintln!("Bit field value {value:08x} doesn't fit in mask {mask:08x}.");
return Err(unsupported(if_debug!(Unsupported::SideTable)));
}
Ok(field)
This is similar to what we do in the memory_too_small function.