Introduce Keep and DropKeep structs in isa

This commit is contained in:
Sergey Pepyakin 2018-06-18 19:30:11 +03:00
parent 0f6da829de
commit 29002153ec
5 changed files with 181 additions and 172 deletions

View File

@ -40,11 +40,23 @@
//! - Reserved immediates are ignored for `call_indirect`, `current_memory`, `grow_memory`. //! - Reserved immediates are ignored for `call_indirect`, `current_memory`, `grow_memory`.
//! //!
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Keep {
None,
Single,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct DropKeep {
pub drop: u32,
pub keep: Keep,
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Target { pub struct Target {
pub dst_pc: u32, pub dst_pc: u32,
pub drop: u32, pub drop_keep: DropKeep,
pub keep: u8,
} }
#[allow(unused)] // TODO: Remove #[allow(unused)] // TODO: Remove
@ -71,10 +83,7 @@ pub enum Instruction {
BrTable(Box<[Target]>), BrTable(Box<[Target]>),
Unreachable, Unreachable,
Return { Return(DropKeep),
drop: u32,
keep: u8,
},
Call(u32), Call(u32),
CallIndirect(u32), CallIndirect(u32),

View File

@ -33,7 +33,7 @@ pub enum InstructionOutcome {
/// Execute function call. /// Execute function call.
ExecuteCall(FuncRef), ExecuteCall(FuncRef),
/// Return from current function block. /// Return from current function block.
Return(u32, u8), Return(isa::DropKeep),
} }
/// Function run result. /// Function run result.
@ -157,14 +157,14 @@ impl<'a, E: Externals> Interpreter<'a, E> {
InstructionOutcome::RunNextInstruction => function_context.position += 1, InstructionOutcome::RunNextInstruction => function_context.position += 1,
InstructionOutcome::Branch(target) => { InstructionOutcome::Branch(target) => {
function_context.position = target.dst_pc as usize; function_context.position = target.dst_pc as usize;
self.value_stack.drop_keep(target.drop, target.keep); self.value_stack.drop_keep(target.drop_keep);
}, },
InstructionOutcome::ExecuteCall(func_ref) => { InstructionOutcome::ExecuteCall(func_ref) => {
function_context.position += 1; function_context.position += 1;
return Ok(RunResult::NestedCall(func_ref)); return Ok(RunResult::NestedCall(func_ref));
}, },
InstructionOutcome::Return(drop, keep) => { InstructionOutcome::Return(drop_keep) => {
self.value_stack.drop_keep(drop, keep); self.value_stack.drop_keep(drop_keep);
break; break;
}, },
} }
@ -182,7 +182,7 @@ impl<'a, E: Externals> Interpreter<'a, E> {
&isa::Instruction::BrIfEqz(ref target) => self.run_br_eqz(target.clone()), &isa::Instruction::BrIfEqz(ref target) => self.run_br_eqz(target.clone()),
&isa::Instruction::BrIfNez(ref target) => self.run_br_nez(target.clone()), &isa::Instruction::BrIfNez(ref target) => self.run_br_nez(target.clone()),
&isa::Instruction::BrTable(ref targets) => self.run_br_table(targets), &isa::Instruction::BrTable(ref targets) => self.run_br_table(targets),
&isa::Instruction::Return { drop, keep } => self.run_return(drop, keep), &isa::Instruction::Return(drop_keep) => self.run_return(drop_keep),
&isa::Instruction::Call(index) => self.run_call(context, index), &isa::Instruction::Call(index) => self.run_call(context, index),
&isa::Instruction::CallIndirect(index) => self.run_call_indirect(context, index), &isa::Instruction::CallIndirect(index) => self.run_call_indirect(context, index),
@ -405,8 +405,8 @@ impl<'a, E: Externals> Interpreter<'a, E> {
Ok(InstructionOutcome::Branch(dst)) Ok(InstructionOutcome::Branch(dst))
} }
fn run_return(&mut self, drop: u32, keep: u8) -> Result<InstructionOutcome, TrapKind> { fn run_return(&mut self, drop_keep: isa::DropKeep) -> Result<InstructionOutcome, TrapKind> {
Ok(InstructionOutcome::Return(drop, keep)) Ok(InstructionOutcome::Return(drop_keep))
} }
fn run_call( fn run_call(
@ -1127,16 +1127,14 @@ impl ValueStack {
} }
#[inline] #[inline]
fn drop_keep(&mut self, drop: u32, keep: u8) { fn drop_keep(&mut self, drop_keep: isa::DropKeep) {
assert!(keep <= 1); if drop_keep.keep == isa::Keep::Single {
if keep == 1 {
let top = *self.top(); let top = *self.top();
*self.pick_mut(drop as usize + 1) = top; *self.pick_mut(drop_keep.drop as usize + 1) = top;
} }
let cur_stack_len = self.len(); let cur_stack_len = self.len();
self.sp = cur_stack_len - drop as usize; self.sp = cur_stack_len - drop_keep.drop as usize;
} }
#[inline] #[inline]

View File

@ -283,7 +283,7 @@ impl Validator {
context.sink.emit_br_eqz(Target { context.sink.emit_br_eqz(Target {
label: if_not, label: if_not,
drop_keep: DropKeep { drop: 0, keep: 0 }, drop_keep: isa::DropKeep { drop: 0, keep: isa::Keep::None, },
}); });
} }
Else => { Else => {
@ -303,7 +303,7 @@ impl Validator {
// to the "end_label" (it will be resolved at End). // to the "end_label" (it will be resolved at End).
context.sink.emit_br(Target { context.sink.emit_br(Target {
label: end_label, label: end_label,
drop_keep: DropKeep { drop: 0, keep: 0 }, drop_keep: isa::DropKeep { drop: 0, keep: isa::Keep::None, },
}); });
// Resolve `if_not` to here so when if condition is unsatisfied control flow // Resolve `if_not` to here so when if condition is unsatisfied control flow
@ -375,15 +375,12 @@ impl Validator {
)?; )?;
} }
let DropKeep { drop, keep } = drop_keep_return( let drop_keep = drop_keep_return(
&context.locals, &context.locals,
&context.value_stack, &context.value_stack,
&context.frame_stack, &context.frame_stack,
); );
context.sink.emit(isa::Instruction::Return { context.sink.emit(isa::Instruction::Return(drop_keep));
drop,
keep,
});
} }
pop_label(&mut context.value_stack, &mut context.frame_stack)?; pop_label(&mut context.value_stack, &mut context.frame_stack)?;
@ -441,15 +438,12 @@ impl Validator {
tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?; tee_value(&mut context.value_stack, &context.frame_stack, value_type.into())?;
} }
let DropKeep { drop, keep } = drop_keep_return( let drop_keep = drop_keep_return(
&context.locals, &context.locals,
&context.value_stack, &context.value_stack,
&context.frame_stack &context.frame_stack
); );
context.sink.emit(isa::Instruction::Return { context.sink.emit(isa::Instruction::Return(drop_keep));
drop,
keep,
});
return Ok(InstructionOutcome::Unreachable); return Ok(InstructionOutcome::Unreachable);
} }
@ -1549,13 +1543,13 @@ fn require_target(
require_label(depth, frame_stack).expect("require_target called with a bogus depth"); require_label(depth, frame_stack).expect("require_target called with a bogus depth");
// Find out how many values we need to keep (copy to the new stack location after the drop). // Find out how many values we need to keep (copy to the new stack location after the drop).
let keep: u8 = match (frame.frame_type, frame.block_type) { let keep: isa::Keep = match (frame.frame_type, frame.block_type) {
// A loop doesn't take a value upon a branch. It can return value // A loop doesn't take a value upon a branch. It can return value
// only via reaching it's closing `End` operator. // only via reaching it's closing `End` operator.
(BlockFrameType::Loop { .. }, _) => 0, (BlockFrameType::Loop { .. }, _) => isa::Keep::None,
(_, BlockType::Value(_)) => 1, (_, BlockType::Value(_)) => isa::Keep::Single,
(_, BlockType::NoResult) => 0, (_, BlockType::NoResult) => isa::Keep::None,
}; };
// Find out how many values we need to discard. // Find out how many values we need to discard.
@ -1573,7 +1567,7 @@ fn require_target(
); );
assert!( assert!(
(value_stack_height as u32 - frame.value_stack_len as u32) >= keep as u32, (value_stack_height as u32 - frame.value_stack_len as u32) >= keep as u32,
"Stack underflow detected: asked to keep {} values, but there are only {}", "Stack underflow detected: asked to keep {:?} values, but there are only {}",
keep, keep,
value_stack_height as u32 - frame.value_stack_len as u32, value_stack_height as u32 - frame.value_stack_len as u32,
); );
@ -1582,7 +1576,7 @@ fn require_target(
Target { Target {
label: frame.frame_type.br_destination(), label: frame.frame_type.br_destination(),
drop_keep: DropKeep { drop, keep }, drop_keep: isa::DropKeep { drop, keep },
} }
} }
@ -1590,7 +1584,7 @@ fn drop_keep_return(
locals: &Locals, locals: &Locals,
value_stack: &StackWithLimit<StackValueType>, value_stack: &StackWithLimit<StackValueType>,
frame_stack: &StackWithLimit<BlockFrame>, frame_stack: &StackWithLimit<BlockFrame>,
) -> DropKeep { ) -> isa::DropKeep {
assert!( assert!(
!frame_stack.is_empty(), !frame_stack.is_empty(),
"drop_keep_return can't be called with the frame stack empty" "drop_keep_return can't be called with the frame stack empty"
@ -1627,16 +1621,10 @@ fn relative_local_depth(
Ok(depth) Ok(depth)
} }
#[derive(Clone)]
struct DropKeep {
drop: u32,
keep: u8,
}
#[derive(Clone)] #[derive(Clone)]
struct Target { struct Target {
label: LabelId, label: LabelId,
drop_keep: DropKeep, drop_keep: isa::DropKeep,
} }
#[derive(Debug)] #[derive(Debug)]
@ -1694,51 +1682,39 @@ impl Sink {
fn emit_br(&mut self, target: Target) { fn emit_br(&mut self, target: Target) {
let Target { let Target {
label, label,
drop_keep: DropKeep { drop_keep,
drop,
keep,
},
} = target; } = target;
let pc = self.cur_pc(); let pc = self.cur_pc();
let dst_pc = self.pc_or_placeholder(label, || Reloc::Br { pc }); let dst_pc = self.pc_or_placeholder(label, || Reloc::Br { pc });
self.ins.push(isa::Instruction::Br(isa::Target { self.ins.push(isa::Instruction::Br(isa::Target {
dst_pc, dst_pc,
drop, drop_keep: drop_keep.into(),
keep,
})); }));
} }
fn emit_br_eqz(&mut self, target: Target) { fn emit_br_eqz(&mut self, target: Target) {
let Target { let Target {
label, label,
drop_keep: DropKeep { drop_keep,
drop,
keep,
},
} = target; } = target;
let pc = self.cur_pc(); let pc = self.cur_pc();
let dst_pc = self.pc_or_placeholder(label, || Reloc::Br { pc }); let dst_pc = self.pc_or_placeholder(label, || Reloc::Br { pc });
self.ins.push(isa::Instruction::BrIfEqz(isa::Target { self.ins.push(isa::Instruction::BrIfEqz(isa::Target {
dst_pc, dst_pc,
drop, drop_keep: drop_keep.into(),
keep,
})); }));
} }
fn emit_br_nez(&mut self, target: Target) { fn emit_br_nez(&mut self, target: Target) {
let Target { let Target {
label, label,
drop_keep: DropKeep { drop_keep,
drop,
keep,
},
} = target; } = target;
let pc = self.cur_pc(); let pc = self.cur_pc();
let dst_pc = self.pc_or_placeholder(label, || Reloc::Br { pc }); let dst_pc = self.pc_or_placeholder(label, || Reloc::Br { pc });
self.ins.push(isa::Instruction::BrIfNez(isa::Target { self.ins.push(isa::Instruction::BrIfNez(isa::Target {
dst_pc, dst_pc,
drop, drop_keep: drop_keep.into(),
keep,
})); }));
} }
@ -1747,16 +1723,12 @@ impl Sink {
let pc = self.cur_pc(); let pc = self.cur_pc();
let mut isa_targets = Vec::new(); let mut isa_targets = Vec::new();
for (idx, &Target { label, drop_keep: DropKeep { for (idx, &Target { label, drop_keep }) in targets.iter().chain(iter::once(&default)).enumerate() {
drop,
keep,
}}) in targets.iter().chain(iter::once(&default)).enumerate() {
let dst_pc = self.pc_or_placeholder(label, || Reloc::BrTable { pc, idx }); let dst_pc = self.pc_or_placeholder(label, || Reloc::BrTable { pc, idx });
isa_targets.push( isa_targets.push(
isa::Target { isa::Target {
dst_pc, dst_pc,
keep, drop_keep: drop_keep.into(),
drop,
}, },
); );
} }

View File

@ -327,10 +327,10 @@ fn implicit_return_no_value() {
assert_eq!( assert_eq!(
code, code,
vec![ vec![
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 0, drop: 0,
keep: 0, keep: isa::Keep::None,
} })
] ]
) )
} }
@ -348,10 +348,10 @@ fn implicit_return_with_value() {
code, code,
vec![ vec![
isa::Instruction::I32Const(0), isa::Instruction::I32Const(0),
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 0, drop: 0,
keep: 1, keep: isa::Keep::Single,
} }),
] ]
) )
} }
@ -367,10 +367,10 @@ fn implicit_return_param() {
assert_eq!( assert_eq!(
code, code,
vec![ vec![
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 1, drop: 1,
keep: 0, keep: isa::Keep::None,
} }),
] ]
) )
} }
@ -388,10 +388,10 @@ fn get_local() {
code, code,
vec![ vec![
isa::Instruction::GetLocal(1), isa::Instruction::GetLocal(1),
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 1, drop: 1,
keep: 1, keep: isa::Keep::Single,
} }),
] ]
) )
} }
@ -410,14 +410,14 @@ fn explicit_return() {
code, code,
vec![ vec![
isa::Instruction::GetLocal(1), isa::Instruction::GetLocal(1),
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 1, drop: 1,
keep: 1, keep: isa::Keep::Single,
}, }),
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 1, drop: 1,
keep: 1, keep: isa::Keep::Single,
} }),
] ]
) )
} }
@ -444,10 +444,10 @@ fn add_params() {
isa::Instruction::GetLocal(2), isa::Instruction::GetLocal(2),
isa::Instruction::GetLocal(2), isa::Instruction::GetLocal(2),
isa::Instruction::I32Add, isa::Instruction::I32Add,
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 2, drop: 2,
keep: 1, keep: isa::Keep::Single,
} }),
] ]
) )
} }
@ -468,10 +468,10 @@ fn drop_locals() {
vec![ vec![
isa::Instruction::GetLocal(2), isa::Instruction::GetLocal(2),
isa::Instruction::SetLocal(1), isa::Instruction::SetLocal(1),
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 2, drop: 2,
keep: 0, keep: isa::Keep::None,
} }),
] ]
) )
} }
@ -496,19 +496,21 @@ fn if_without_else() {
isa::Instruction::I32Const(1), isa::Instruction::I32Const(1),
isa::Instruction::BrIfEqz(isa::Target { isa::Instruction::BrIfEqz(isa::Target {
dst_pc: 4, dst_pc: 4,
drop: 0, drop_keep: isa::DropKeep {
keep: 0, drop: 0,
keep: isa::Keep::None,
},
}), }),
isa::Instruction::I32Const(2), isa::Instruction::I32Const(2),
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 1, // 1 param drop: 1, // 1 param
keep: 1, // 1 result keep: isa::Keep::Single, // 1 result
}, }),
isa::Instruction::I32Const(3), isa::Instruction::I32Const(3),
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 1, drop: 1,
keep: 1, keep: isa::Keep::Single,
}, }),
] ]
) )
} }
@ -536,22 +538,26 @@ fn if_else() {
isa::Instruction::I32Const(1), isa::Instruction::I32Const(1),
isa::Instruction::BrIfEqz(isa::Target { isa::Instruction::BrIfEqz(isa::Target {
dst_pc: 5, dst_pc: 5,
drop: 0, drop_keep: isa::DropKeep {
keep: 0, drop: 0,
keep: isa::Keep::None,
},
}), }),
isa::Instruction::I32Const(2), isa::Instruction::I32Const(2),
isa::Instruction::SetLocal(1), isa::Instruction::SetLocal(1),
isa::Instruction::Br(isa::Target { isa::Instruction::Br(isa::Target {
dst_pc: 7, dst_pc: 7,
drop: 0, drop_keep: isa::DropKeep {
keep: 0, drop: 0,
keep: isa::Keep::None,
},
}), }),
isa::Instruction::I32Const(3), isa::Instruction::I32Const(3),
isa::Instruction::SetLocal(1), isa::Instruction::SetLocal(1),
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 1, drop: 1,
keep: 0, keep: isa::Keep::None,
}, }),
] ]
) )
} }
@ -577,21 +583,25 @@ fn if_else_returns_result() {
isa::Instruction::I32Const(1), isa::Instruction::I32Const(1),
isa::Instruction::BrIfEqz(isa::Target { isa::Instruction::BrIfEqz(isa::Target {
dst_pc: 4, dst_pc: 4,
drop: 0, drop_keep: isa::DropKeep {
keep: 0, drop: 0,
keep: isa::Keep::None,
},
}), }),
isa::Instruction::I32Const(2), isa::Instruction::I32Const(2),
isa::Instruction::Br(isa::Target { isa::Instruction::Br(isa::Target {
dst_pc: 5, dst_pc: 5,
drop: 0, drop_keep: isa::DropKeep {
keep: 0, drop: 0,
keep: isa::Keep::None,
},
}), }),
isa::Instruction::I32Const(3), isa::Instruction::I32Const(3),
isa::Instruction::Drop, isa::Instruction::Drop,
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 0, drop: 0,
keep: 0, keep: isa::Keep::None,
}, }),
] ]
) )
} }
@ -621,29 +631,35 @@ fn if_else_branch_from_true_branch() {
isa::Instruction::I32Const(1), isa::Instruction::I32Const(1),
isa::Instruction::BrIfEqz(isa::Target { isa::Instruction::BrIfEqz(isa::Target {
dst_pc: 8, dst_pc: 8,
drop: 0, drop_keep: isa::DropKeep {
keep: 0, drop: 0,
keep: isa::Keep::None,
},
}), }),
isa::Instruction::I32Const(1), isa::Instruction::I32Const(1),
isa::Instruction::I32Const(1), isa::Instruction::I32Const(1),
isa::Instruction::BrIfNez(isa::Target { isa::Instruction::BrIfNez(isa::Target {
dst_pc: 9, dst_pc: 9,
drop: 0, drop_keep: isa::DropKeep {
keep: 1, drop: 0,
keep: isa::Keep::Single,
},
}), }),
isa::Instruction::Drop, isa::Instruction::Drop,
isa::Instruction::I32Const(2), isa::Instruction::I32Const(2),
isa::Instruction::Br(isa::Target { isa::Instruction::Br(isa::Target {
dst_pc: 9, dst_pc: 9,
drop: 0, drop_keep: isa::DropKeep {
keep: 0, drop: 0,
keep: isa::Keep::None,
},
}), }),
isa::Instruction::I32Const(3), isa::Instruction::I32Const(3),
isa::Instruction::Drop, isa::Instruction::Drop,
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 0, drop: 0,
keep: 0, keep: isa::Keep::None,
}, }),
] ]
) )
} }
@ -673,29 +689,35 @@ fn if_else_branch_from_false_branch() {
isa::Instruction::I32Const(1), isa::Instruction::I32Const(1),
isa::Instruction::BrIfEqz(isa::Target { isa::Instruction::BrIfEqz(isa::Target {
dst_pc: 4, dst_pc: 4,
drop: 0, drop_keep: isa::DropKeep {
keep: 0, drop: 0,
keep: isa::Keep::None,
},
}), }),
isa::Instruction::I32Const(1), isa::Instruction::I32Const(1),
isa::Instruction::Br(isa::Target { isa::Instruction::Br(isa::Target {
dst_pc: 9, dst_pc: 9,
drop: 0, drop_keep: isa::DropKeep {
keep: 0, drop: 0,
keep: isa::Keep::None,
},
}), }),
isa::Instruction::I32Const(2), isa::Instruction::I32Const(2),
isa::Instruction::I32Const(1), isa::Instruction::I32Const(1),
isa::Instruction::BrIfNez(isa::Target { isa::Instruction::BrIfNez(isa::Target {
dst_pc: 9, dst_pc: 9,
drop: 0, drop_keep: isa::DropKeep {
keep: 1, drop: 0,
keep: isa::Keep::Single,
},
}), }),
isa::Instruction::Drop, isa::Instruction::Drop,
isa::Instruction::I32Const(3), isa::Instruction::I32Const(3),
isa::Instruction::Drop, isa::Instruction::Drop,
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 0, drop: 0,
keep: 0, keep: isa::Keep::None,
}, }),
] ]
) )
} }
@ -720,15 +742,17 @@ fn loop_() {
isa::Instruction::I32Const(1), isa::Instruction::I32Const(1),
isa::Instruction::BrIfNez(isa::Target { isa::Instruction::BrIfNez(isa::Target {
dst_pc: 0, dst_pc: 0,
drop: 0, drop_keep: isa::DropKeep {
keep: 0, drop: 0,
keep: isa::Keep::None,
},
}), }),
isa::Instruction::I32Const(2), isa::Instruction::I32Const(2),
isa::Instruction::Drop, isa::Instruction::Drop,
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 0, drop: 0,
keep: 0, keep: isa::Keep::None,
}, }),
] ]
) )
} }
@ -746,10 +770,10 @@ fn loop_empty() {
assert_eq!( assert_eq!(
code, code,
vec![ vec![
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 0, drop: 0,
keep: 0, keep: isa::Keep::None,
}, }),
] ]
) )
} }
@ -776,20 +800,24 @@ fn brtable() {
vec![ vec![
isa::Target { isa::Target {
dst_pc: 0, dst_pc: 0,
keep: 0, drop_keep: isa::DropKeep {
drop: 0, drop: 0,
keep: isa::Keep::None,
},
}, },
isa::Target { isa::Target {
dst_pc: 2, dst_pc: 2,
keep: 0, drop_keep: isa::DropKeep {
drop: 0, drop: 0,
keep: isa::Keep::None,
},
}, },
].into_boxed_slice() ].into_boxed_slice()
), ),
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 0, drop: 0,
keep: 0, keep: isa::Keep::None,
}, }),
] ]
) )
} }
@ -820,22 +848,26 @@ fn brtable_returns_result() {
vec![ vec![
isa::Target { isa::Target {
dst_pc: 3, dst_pc: 3,
keep: 1, drop_keep: isa::DropKeep {
drop: 0, drop: 0,
keep: isa::Keep::Single,
},
}, },
isa::Target { isa::Target {
dst_pc: 4, dst_pc: 4,
keep: 1, drop_keep: isa::DropKeep {
drop: 0, keep: isa::Keep::Single,
drop: 0,
},
}, },
].into_boxed_slice() ].into_boxed_slice()
), ),
isa::Instruction::Unreachable, isa::Instruction::Unreachable,
isa::Instruction::Drop, isa::Instruction::Drop,
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 0, drop: 0,
keep: 0, keep: isa::Keep::None,
}, }),
] ]
) )
} }
@ -862,24 +894,25 @@ fn wabt_example() {
isa::Instruction::GetLocal(1), isa::Instruction::GetLocal(1),
isa::Instruction::BrIfNez(isa::Target { isa::Instruction::BrIfNez(isa::Target {
dst_pc: 4, dst_pc: 4,
keep: 0, drop_keep: isa::DropKeep {
drop: 0, drop: 0,
keep: isa::Keep::None,
},
}), }),
isa::Instruction::I32Const(1), isa::Instruction::I32Const(1),
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 1, // 1 parameter drop: 1, // 1 parameter
keep: 1, // return value keep: isa::Keep::Single,
}, }),
isa::Instruction::I32Const(2), isa::Instruction::I32Const(2),
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 1, drop: 1,
keep: 1, keep: isa::Keep::Single,
}, }),
isa::Instruction::Return { isa::Instruction::Return(isa::DropKeep {
drop: 1, drop: 1,
keep: 1, keep: isa::Keep::Single,
}, }),
] ]
) )
} }

View File

@ -123,12 +123,9 @@ mod tests {
Local::new(u32::max_value(), ValueType::I32), Local::new(u32::max_value(), ValueType::I32),
Local::new(1, ValueType::I64), Local::new(1, ValueType::I64),
]; ];
let locals = Locals::new(&[], &local_groups).unwrap();
assert_matches!( assert_matches!(
locals.type_of_local(u32::max_value() - 1), Locals::new(&[], &local_groups),
Ok(ValueType::I32) Err(_)
); );
assert_matches!(locals.type_of_local(u32::max_value()), Err(_));
} }
} }