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

Propertly implement blocktypes #311

Merged
merged 1 commit into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions wrausmt-format/src/binary/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,12 @@ impl<R: ParserReader> BinaryParser<R> {
syntax::Operands::None
}
Operands::Block => {
let bt = self.read_type_use()?;
let bt = self.read_blocktype()?;
let expr = self.read_expr(data_indices_ok)?;
syntax::Operands::Block(None, bt, expr, Continuation::End)
}
Operands::Loop => {
let bt = self.read_type_use()?;
let bt = self.read_blocktype()?;
let expr = self.read_expr(data_indices_ok)?;
syntax::Operands::Block(None, bt, expr, Continuation::Start)
}
Expand Down
22 changes: 12 additions & 10 deletions wrausmt-format/src/binary/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use {
},
wrausmt_runtime::syntax::{
types::{GlobalType, Limits, MemType, NumType, RefType, TableType, ValueType},
FParam, FResult, FunctionType, Index, Resolved, TypeField, TypeUse, Unvalidated,
BlockType, FParam, FResult, FunctionType, Index, Resolved, TypeField, TypeUse, Unvalidated,
},
};

Expand Down Expand Up @@ -92,18 +92,20 @@ impl<R: ParserReader> BinaryParser<R> {
})
}

pub(in crate::binary) fn read_blocktype(&mut self) -> Result<TypeUse<Resolved>> {
pub(in crate::binary) fn read_blocktype(&mut self) -> Result<BlockType<Resolved>> {
pctx!(self, "read block type");
let idx = self.read_i64_leb_128().result(self)?;
Ok(match idx {
-0x01 => TypeUse::single_result(NumType::I32.into()),
-0x02 => TypeUse::single_result(NumType::I64.into()),
-0x03 => TypeUse::single_result(NumType::F32.into()),
-0x04 => TypeUse::single_result(NumType::F64.into()),
-0x10 => TypeUse::single_result(RefType::Func.into()),
-0x11 => TypeUse::single_result(RefType::Func.into()),
-0x40 => TypeUse::default(),
x if x > 0 && x <= u32::MAX as i64 => TypeUse::ByIndex(Index::unnamed(x as u32)),
-0x01 => BlockType::SingleResult(NumType::I32.into()),
-0x02 => BlockType::SingleResult(NumType::I64.into()),
-0x03 => BlockType::SingleResult(NumType::F32.into()),
-0x04 => BlockType::SingleResult(NumType::F64.into()),
-0x10 => BlockType::SingleResult(RefType::Func.into()),
-0x11 => BlockType::SingleResult(RefType::Extern.into()),
-0x40 => BlockType::Void,
x if x > 0 && x <= u32::MAX as i64 => {
BlockType::TypeUse(TypeUse::ByIndex(Index::unnamed(x as u32)))
}
// TODO: This is not the right error.
_ => Err(self.err(BinaryParseErrorKind::InvalidBlockType(idx)))?,
})
Expand Down
6 changes: 5 additions & 1 deletion wrausmt-format/src/compiler/const_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ pub fn compile_const_expr(
}

(stack == [expect_type]).true_or(ValidationErrorKind::TypeMismatch {
actual: ValidationType::Value(*stack.first().unwrap_or(&ValueType::Void)),
actual: ValidationType::Value(
*stack
.first()
.ok_or(ValidationErrorKind::ValStackUnderflow)?,
),
expect: ValidationType::Value(expect_type),
})?;

Expand Down
51 changes: 41 additions & 10 deletions wrausmt-format/src/compiler/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ use {
validation::{ModuleContext, Result, Validation},
ToValidationError,
},
crate::ValidationErrorKind,
wrausmt_runtime::{
instructions::opcodes,
syntax::{
self,
location::Location,
types::{RefType, ValueType},
CompiledExpr, FuncField, Id, Instruction, Opcode, Operands, Resolved, TypeUse,
UncompiledExpr,
BlockType, CompiledExpr, FuncField, Id, Instruction, Opcode, Operands, Resolved,
TypeUse, UncompiledExpr,
},
},
};
Expand All @@ -26,19 +27,38 @@ pub trait Emitter {
fn splice32(&mut self, idx: usize, v: u32);
fn len(&self) -> usize;
fn emit_opcode(&mut self, opcode: Opcode);
fn func_arity(&self, typeuse: &TypeUse<Resolved>, location: &Location) -> Result<(u32, u32)>;

fn is_empty(&self) -> bool;

/// Emit the block type for the executor to read.
/// During execution we only need to know arity, so that's all that's
/// emitted.
fn emit_block_type(
&mut self,
blocktype: &syntax::BlockType<Resolved>,
location: &Location,
) -> Result<()> {
let (params, results) = match blocktype {
BlockType::Void => (0, 0),
BlockType::SingleResult(_) => (0, 1),
BlockType::TypeUse(tu) => self.func_arity(tu, location)?,
};
self.emit32(params);
self.emit32(results);
Ok(())
}

fn emit_block(
&mut self,
typeuse: &syntax::TypeUse<Resolved>,
blocktype: &syntax::BlockType<Resolved>,
expr: &syntax::UncompiledExpr<Resolved>,
cnt: &syntax::Continuation,
location: &Location,
) -> Result<()> {
let startcnt = self.len() as u32 - 1;

self.emit32(typeuse.index().value());
self.emit_block_type(blocktype, location)?;

let continuation_location = self.len();
// If the continuation is at the start, we write self the current length
Expand Down Expand Up @@ -78,12 +98,12 @@ pub trait Emitter {

fn emit_if(
&mut self,
typeuse: &TypeUse<Resolved>,
blocktype: &BlockType<Resolved>,
th: &UncompiledExpr<Resolved>,
el: &UncompiledExpr<Resolved>,
location: &Location,
) -> Result<()> {
self.emit32(typeuse.index().value());
self.emit_block_type(blocktype, location)?;

// Store the space for end continuation
let end_location = self.len();
Expand Down Expand Up @@ -125,8 +145,8 @@ pub trait Emitter {
// Emit operands
match &instr.operands {
syntax::Operands::None => (),
syntax::Operands::Block(_, typeuse, e, cnt) => {
self.emit_block(typeuse, e, cnt, &instr.location)?
syntax::Operands::Block(_, blocktype, e, cnt) => {
self.emit_block(blocktype, e, cnt, &instr.location)?
}
syntax::Operands::BrTable(indices, last) => self.emit_br_table(indices, last),
syntax::Operands::CallIndirect(idx, typeuse) => {
Expand All @@ -135,8 +155,8 @@ pub trait Emitter {
}
// SelectT operands are only used during validation.
syntax::Operands::SelectT(_) => (),
syntax::Operands::If(_, typeuse, th, el) => {
self.emit_if(typeuse, th, el, &instr.location)?
syntax::Operands::If(_, blocktype, th, el) => {
self.emit_if(blocktype, th, el, &instr.location)?
}
syntax::Operands::I32(n) => self.emit32(*n),
syntax::Operands::I64(n) => self.emit64(*n),
Expand Down Expand Up @@ -240,6 +260,17 @@ impl<'a> ValidatingEmitter<'a> {
}

impl<'a> Emitter for ValidatingEmitter<'a> {
fn func_arity(&self, tu: &TypeUse<Resolved>, location: &Location) -> Result<(u32, u32)> {
let ft = self
.validation
.module
.types
.get(tu.index().value() as usize)
.ok_or(ValidationErrorKind::UnknownFunc)
.validation_error(*location)?;
Ok((ft.params.len() as u32, ft.results.len() as u32))
}

fn validate_instr(&mut self, instr: &Instruction<Resolved>) -> Result<()> {
self.validation
.validate_instr(instr)
Expand Down
27 changes: 15 additions & 12 deletions wrausmt-format/src/compiler/validation/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use {
instructions::opcodes,
syntax::{
types::{NumType, RefType, ValueType},
Index, Instruction, LocalIndex, Operands, Resolved, TypeUse,
BlockType, Index, Instruction, LocalIndex, Operands, Resolved,
},
},
};
Expand Down Expand Up @@ -90,11 +90,14 @@ impl<'a> Validation<'a> {
Ok(())
}

fn function_type_for_typeuse(&self, typeuse: &TypeUse<Resolved>) -> FunctionType {
if typeuse.index().value() == 0x040 {
FunctionType::default()
} else {
self.module.types[typeuse.index().value() as usize].clone()
fn function_type_for_blocktype(&self, blocktype: &BlockType<Resolved>) -> FunctionType {
match blocktype {
BlockType::Void => FunctionType::default(),
BlockType::SingleResult(t) => FunctionType {
params: vec![],
results: vec![*t],
},
BlockType::TypeUse(tu) => self.module.types[tu.index().value() as usize].clone(),
}
}

Expand Down Expand Up @@ -126,22 +129,22 @@ impl<'a> Validation<'a> {
instr!(opcodes::UNREACHABLE) => self.stacks.unreachable(),
instr!(opcodes::NOP) => Ok(()),

instr!(opcodes::BLOCK => Operands::Block(_, typeuse, ..)) => {
let ft = self.function_type_for_typeuse(typeuse);
instr!(opcodes::BLOCK => Operands::Block(_, blocktype, ..)) => {
let ft = self.function_type_for_blocktype(blocktype);
self.stacks.pop_vals(&ft.params)?;
self.stacks.push_ctrl(opcodes::BLOCK, ft.params, ft.results);
Ok(())
}

instr!(opcodes::LOOP => Operands::Block(_, typeuse, ..)) => {
let ft = self.function_type_for_typeuse(typeuse);
instr!(opcodes::LOOP => Operands::Block(_, blocktype, ..)) => {
let ft = self.function_type_for_blocktype(blocktype);
self.stacks.pop_vals(&ft.params)?;
self.stacks.push_ctrl(opcodes::LOOP, ft.params, ft.results);
Ok(())
}

instr!(opcodes::IF => Operands::If(_, typeuse, ..)) => {
let ft = self.function_type_for_typeuse(typeuse);
instr!(opcodes::IF => Operands::If(_, blocktype, ..)) => {
let ft = self.function_type_for_blocktype(blocktype);
self.stacks.pop_val(I32)?;
self.stacks.pop_vals(&ft.params)?;
self.stacks.push_ctrl(opcodes::IF, ft.params, ft.results);
Expand Down
16 changes: 8 additions & 8 deletions wrausmt-format/src/text/parse/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,13 @@ impl<R: Read> Parser<R> {
fn parse_plain_block(&mut self, cnt: Continuation) -> Result<syntax::Operands<Unresolved>> {
pctx!(self, "parse plain block");
let label = self.try_id()?;
let typeuse = self.parse_type_use(super::module::FParamId::Forbidden)?;
let blocktype = self.parse_block_type()?;
let instr = self.parse_instructions()?;
self.expect_plain_end(&label)?;

Ok(syntax::Operands::Block(
label,
typeuse,
blocktype,
UncompiledExpr { instr },
cnt,
))
Expand All @@ -149,7 +149,7 @@ impl<R: Read> Parser<R> {
pctx!(self, "parse plain if operands");
let label = self.try_id()?;

let typeuse = self.parse_type_use(super::module::FParamId::Forbidden)?;
let blocktype = self.parse_block_type()?;

let thengroup = self.parse_instructions()?;

Expand All @@ -165,7 +165,7 @@ impl<R: Read> Parser<R> {

Ok(syntax::Operands::If(
label,
typeuse,
blocktype,
UncompiledExpr { instr: thengroup },
UncompiledExpr { instr: elsegroup },
))
Expand Down Expand Up @@ -228,10 +228,10 @@ impl<R: Read> Parser<R> {
pctx!(self, "parse folded block");
let location = self.location();
let label = self.try_id()?;
let typeuse = self.parse_type_use(super::module::FParamId::Forbidden)?;
let blocktype = self.parse_block_type()?;
let instr = self.parse_instructions()?;
self.expect_close()?;
let operands = syntax::Operands::Block(label, typeuse, UncompiledExpr { instr }, cnt);
let operands = syntax::Operands::Block(label, blocktype, UncompiledExpr { instr }, cnt);
Ok(Instruction {
name,
opcode,
Expand All @@ -244,7 +244,7 @@ impl<R: Read> Parser<R> {
pctx!(self, "parse folded if");
let location = self.location();
let label = self.try_id()?;
let typeuse = self.parse_type_use(super::module::FParamId::Forbidden)?;
let blocktype = self.parse_block_type()?;
let condition = self
.zero_or_more_groups(Self::try_folded_instruction)?
.result;
Expand All @@ -265,7 +265,7 @@ impl<R: Read> Parser<R> {
};

self.expect_close()?;
let operands = syntax::Operands::If(label, typeuse, thexpr, elexpr);
let operands = syntax::Operands::If(label, blocktype, thexpr, elexpr);

unfolded.push(Instruction {
name: Id::literal("if"),
Expand Down
25 changes: 22 additions & 3 deletions wrausmt-format/src/text/parse/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use {
std::io::Read,
wrausmt_runtime::syntax::{
types::{GlobalType, Limits, MemType, TableType},
DataField, DataInit, ElemField, ExportDesc, ExportField, FParam, FResult, FuncField,
FunctionType, GlobalField, Id, ImportDesc, ImportField, Index, IndexSpace, Local,
MemoryField, MemoryIndex, ModeEntry, Module, Resolved, ResolvedState, StartField,
BlockType, DataField, DataInit, ElemField, ExportDesc, ExportField, FParam, FResult,
FuncField, FunctionType, GlobalField, Id, ImportDesc, ImportField, Index, IndexSpace,
Local, MemoryField, MemoryIndex, ModeEntry, Module, Resolved, ResolvedState, StartField,
TableField, TypeField, TypeUse, UncompiledExpr, Unresolved, Unvalidated, ValidatedState,
},
};
Expand Down Expand Up @@ -621,6 +621,25 @@ impl<R: Read> Parser<R> {
}
}

pub fn parse_block_type(&mut self) -> Result<BlockType<Unresolved>> {
let typeuse = self.parse_type_use(FParamId::Forbidden)?;
Ok(match typeuse {
tu @ TypeUse::ByIndex(_) => BlockType::TypeUse(tu),
tu @ TypeUse::NamedInline { .. } => BlockType::TypeUse(tu),
TypeUse::AnonymousInline(ft) => {
if ft.params.is_empty() {
match ft.results.as_slice() {
[] => BlockType::Void,
[t] => BlockType::SingleResult(t.valuetype),
_ => BlockType::TypeUse(TypeUse::AnonymousInline(ft)),
}
} else {
BlockType::TypeUse(TypeUse::AnonymousInline(ft))
}
}
})
}

// Try to parse an inline export for a func, table, global, or memory.
// := (export <name>)
pub fn try_inline_export(&mut self) -> Result<Option<String>> {
Expand Down
Loading
Loading