diff --git a/src/validation/func.rs b/src/validation/func.rs index e8dfecc..15c78f8 100644 --- a/src/validation/func.rs +++ b/src/validation/func.rs @@ -168,16 +168,13 @@ impl Validator { } fn validate_instruction(context: &mut FunctionValidationContext, opcode: &Opcode) -> Result { - // TODO: use InstructionOutcome::*; - - println!("opcode={:?}", opcode); - use self::Opcode::*; match *opcode { // Nop instruction doesn't do anything. It is safe to just skip it. Nop => {}, Unreachable => { + context.sink.emit(isa::Instruction::Unreachable); return Ok(InstructionOutcome::Unreachable); }, @@ -324,6 +321,8 @@ impl Validator { Validator::validate_br_if(context, depth)?; }, BrTable(ref table, default) => { + Validator::validate_br_table(context, table, default)?; + let mut targets = Vec::new(); for depth in table.iter() { let target = context.require_target(*depth)?; @@ -332,8 +331,6 @@ impl Validator { let default_target = context.require_target(default)?; context.sink.emit_br_table(&targets, default_target); - Validator::validate_br_table(context, table, default)?; - return Ok(InstructionOutcome::Unreachable); }, Return => { @@ -1574,10 +1571,6 @@ impl<'a> FunctionValidationContext<'a> { let value_stack_height = self.value_stack.len() as u32; let drop = if frame.polymorphic_stack { 0 } else { - // TODO - println!("value_stack_height = {}", value_stack_height); - println!("frame.value_stack_len = {}", frame.value_stack_len); - println!("keep = {}", keep); (value_stack_height - frame.value_stack_len as u32) - keep as u32 }; diff --git a/src/validation/tests.rs b/src/validation/tests.rs index 83439b7..7683f28 100644 --- a/src/validation/tests.rs +++ b/src/validation/tests.rs @@ -701,7 +701,7 @@ fn if_else_branch_from_false_branch() { } #[test] -fn empty_loop() { +fn loop_() { let code = compile(r#" (module (func (export "call") @@ -733,9 +733,113 @@ fn empty_loop() { ) } -// TODO: Loop -// TODO: Empty loop? -// TODO: brtable +#[test] +fn loop_empty() { + let code = compile(r#" + (module + (func (export "call") + loop + end + ) + ) + "#); + assert_eq!( + code, + vec![ + isa::Instruction::Return { + drop: 0, + keep: 0, + }, + ] + ) +} + +#[test] +fn brtable() { + let code = compile(r#" + (module + (func (export "call") + block $1 + loop $2 + i32.const 0 + br_table $2 $1 + end + end + ) + ) + "#); + assert_eq!( + code, + vec![ + isa::Instruction::I32Const(0), + isa::Instruction::BrTable( + vec![ + isa::Target { + dst_pc: 0, + keep: 0, + drop: 0, + }, + isa::Target { + dst_pc: 2, + keep: 0, + drop: 0, + }, + ].into_boxed_slice() + ), + isa::Instruction::Return { + drop: 0, + keep: 0, + }, + ] + ) +} + +#[test] +fn brtable_returns_result() { + let code = compile(r#" + (module + (func (export "call") + block $1 (result i32) + block $2 (result i32) + i32.const 0 + i32.const 1 + br_table $2 $1 + end + unreachable + end + drop + ) + ) + "#); + assert_eq!( + code, + vec![ + isa::Instruction::I32Const(0), + isa::Instruction::I32Const(1), + isa::Instruction::BrTable( + vec![ + isa::Target { + dst_pc: 3, + keep: 1, + drop: 0, + }, + isa::Target { + dst_pc: 4, + keep: 1, + drop: 0, + }, + ].into_boxed_slice() + ), + isa::Instruction::Unreachable, + isa::Instruction::Drop, + isa::Instruction::Return { + drop: 0, + keep: 0, + }, + ] + ) +} + #[test] fn wabt_example() {