mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-24 06:01:33 +00:00
Get control flow working (fingers crossed)
This commit is contained in:
@ -2,21 +2,22 @@ use inkwell::{
|
|||||||
builder::Builder,
|
builder::Builder,
|
||||||
context::Context,
|
context::Context,
|
||||||
module::Module,
|
module::Module,
|
||||||
|
passes::PassManager,
|
||||||
types::{BasicType, BasicTypeEnum, FunctionType},
|
types::{BasicType, BasicTypeEnum, FunctionType},
|
||||||
values::{BasicValue, FunctionValue},
|
values::{BasicValue, FunctionValue, PhiValue},
|
||||||
FloatPredicate, IntPredicate,
|
FloatPredicate, IntPredicate,
|
||||||
};
|
};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use wasmer_runtime_core::{
|
use wasmer_runtime_core::{
|
||||||
module::ModuleInfo,
|
module::ModuleInfo,
|
||||||
structures::{Map, SliceMap, TypedIndex},
|
structures::{Map, SliceMap, TypedIndex},
|
||||||
types::{FuncIndex, FuncSig, LocalFuncIndex, LocalOrImport, SigIndex, Type},
|
types::{FuncIndex, MemoryIndex, FuncSig, LocalFuncIndex, LocalOrImport, SigIndex, Type, MemoryType},
|
||||||
};
|
};
|
||||||
use wasmparser::{BinaryReaderError, CodeSectionReader, LocalsReader, Operator, OperatorsReader};
|
use wasmparser::{BinaryReaderError, CodeSectionReader, LocalsReader, Operator, OperatorsReader};
|
||||||
|
|
||||||
use crate::intrinsics::Intrinsics;
|
use crate::intrinsics::Intrinsics;
|
||||||
use crate::read_info::type_to_type;
|
use crate::read_info::type_to_type;
|
||||||
use crate::state::State;
|
use crate::state::{ControlFrame, IfElseState, State};
|
||||||
|
|
||||||
fn func_sig_to_llvm(context: &Context, intrinsics: &Intrinsics, sig: &FuncSig) -> FunctionType {
|
fn func_sig_to_llvm(context: &Context, intrinsics: &Intrinsics, sig: &FuncSig) -> FunctionType {
|
||||||
let user_param_types = sig.params().iter().map(|&ty| type_to_llvm(intrinsics, ty));
|
let user_param_types = sig.params().iter().map(|&ty| type_to_llvm(intrinsics, ty));
|
||||||
@ -116,10 +117,37 @@ fn parse_function(
|
|||||||
let llvm_sig = &signatures[sig_index];
|
let llvm_sig = &signatures[sig_index];
|
||||||
|
|
||||||
let function = functions[func_index];
|
let function = functions[func_index];
|
||||||
let entry_block = context.append_basic_block(&function, "entry");
|
|
||||||
builder.position_at_end(&entry_block);
|
|
||||||
|
|
||||||
let mut state = State::new();
|
let mut state = State::new();
|
||||||
|
let entry_block = context.append_basic_block(&function, "entry");
|
||||||
|
|
||||||
|
let return_block = context.append_basic_block(&function, "return");
|
||||||
|
builder.position_at_end(&return_block);
|
||||||
|
|
||||||
|
let phis: SmallVec<[PhiValue; 1]> = func_sig
|
||||||
|
.returns()
|
||||||
|
.iter()
|
||||||
|
.map(|&wasmer_ty| type_to_llvm(intrinsics, wasmer_ty))
|
||||||
|
.map(|ty| builder.build_phi(ty, &state.var_name()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
match phis.as_slice() {
|
||||||
|
// No returns.
|
||||||
|
&[] => {
|
||||||
|
builder.build_return(None);
|
||||||
|
}
|
||||||
|
&[one_value] => {
|
||||||
|
let value = one_value.as_basic_value();
|
||||||
|
builder.build_return(Some(&value));
|
||||||
|
}
|
||||||
|
returns @ _ => {
|
||||||
|
// let struct_ty = llvm_sig.get_return_type().as_struct_type();
|
||||||
|
// let ret_struct = struct_ty.const_zero();
|
||||||
|
unimplemented!("multi-value returns not yet implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.push_block(return_block, phis);
|
||||||
|
builder.position_at_end(&entry_block);
|
||||||
|
|
||||||
let mut locals = Vec::with_capacity(locals_reader.get_count() as usize);
|
let mut locals = Vec::with_capacity(locals_reader.get_count() as usize);
|
||||||
locals.extend(function.get_param_iter().enumerate().map(|(index, param)| {
|
locals.extend(function.get_param_iter().enumerate().map(|(index, param)| {
|
||||||
@ -163,7 +191,7 @@ fn parse_function(
|
|||||||
offset: -1isize as usize,
|
offset: -1isize as usize,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let end_block = context.append_basic_block(&function, &state.block_name());
|
let end_block = context.append_basic_block(&function, "end");
|
||||||
builder.position_at_end(&end_block);
|
builder.position_at_end(&end_block);
|
||||||
|
|
||||||
let phis = if let Ok(wasmer_ty) = type_to_type(ty) {
|
let phis = if let Ok(wasmer_ty) = type_to_type(ty) {
|
||||||
@ -180,12 +208,24 @@ fn parse_function(
|
|||||||
builder.position_at_end(¤t_block);
|
builder.position_at_end(¤t_block);
|
||||||
}
|
}
|
||||||
Operator::Loop { ty } => {
|
Operator::Loop { ty } => {
|
||||||
|
let loop_body = context.append_basic_block(&function, "loop_body");
|
||||||
|
let loop_next = context.append_basic_block(&function, "loop_outer");
|
||||||
|
|
||||||
// let loop_body = context.append_basic_block(&function, &state.block_name());
|
builder.build_unconditional_branch(&loop_body);
|
||||||
// let next = context.append_basic_block(&function, &state.block_name());
|
|
||||||
// builder.build_unconditional_branch(&body);
|
builder.position_at_end(&loop_next);
|
||||||
// let num_return_values = if ty == wasmparser::Type::EmptyBlockType { 0 } else { 1 };
|
let phis = if let Ok(wasmer_ty) = type_to_type(ty) {
|
||||||
// state.push_loop(loop_body, next, num_return_values);
|
let llvm_ty = type_to_llvm(intrinsics, wasmer_ty);
|
||||||
|
[llvm_ty]
|
||||||
|
.iter()
|
||||||
|
.map(|&ty| builder.build_phi(ty, &state.var_name()))
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
SmallVec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
builder.position_at_end(&loop_body);
|
||||||
|
state.push_loop(loop_body, loop_next, phis);
|
||||||
}
|
}
|
||||||
Operator::Br { relative_depth } => {
|
Operator::Br { relative_depth } => {
|
||||||
let frame = state.frame_at_depth(relative_depth)?;
|
let frame = state.frame_at_depth(relative_depth)?;
|
||||||
@ -195,7 +235,13 @@ fn parse_function(
|
|||||||
offset: -1isize as usize,
|
offset: -1isize as usize,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let values = state.peekn(frame.phis().len())?;
|
let value_len = if frame.is_loop() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
frame.phis().len()
|
||||||
|
};
|
||||||
|
|
||||||
|
let values = state.peekn(value_len)?;
|
||||||
|
|
||||||
// For each result of the block we're branching to,
|
// For each result of the block we're branching to,
|
||||||
// pop a value off the value stack and load it into
|
// pop a value off the value stack and load it into
|
||||||
@ -204,11 +250,10 @@ fn parse_function(
|
|||||||
phi.add_incoming(&[(value, ¤t_block)]);
|
phi.add_incoming(&[(value, ¤t_block)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.build_unconditional_branch(frame.dest());
|
builder.build_unconditional_branch(frame.br_dest());
|
||||||
|
|
||||||
state.popn(frame.phis().len())?;
|
state.popn(value_len)?;
|
||||||
|
state.reachable = false;
|
||||||
builder.build_unreachable();
|
|
||||||
}
|
}
|
||||||
Operator::BrIf { relative_depth } => {
|
Operator::BrIf { relative_depth } => {
|
||||||
let cond = state.pop1()?;
|
let cond = state.pop1()?;
|
||||||
@ -219,13 +264,19 @@ fn parse_function(
|
|||||||
offset: -1isize as usize,
|
offset: -1isize as usize,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let param_stack = state.peekn(frame.phis().len())?;
|
let value_len = if frame.is_loop() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
frame.phis().len()
|
||||||
|
};
|
||||||
|
|
||||||
|
let param_stack = state.peekn(value_len)?;
|
||||||
|
|
||||||
for (phi, value) in frame.phis().iter().zip(param_stack.iter()) {
|
for (phi, value) in frame.phis().iter().zip(param_stack.iter()) {
|
||||||
phi.add_incoming(&[(value, ¤t_block)]);
|
phi.add_incoming(&[(value, ¤t_block)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let false_block = context.append_basic_block(&function, &state.block_name());
|
let else_block = context.append_basic_block(&function, "else");
|
||||||
|
|
||||||
let cond_value = builder.build_int_compare(
|
let cond_value = builder.build_int_compare(
|
||||||
IntPredicate::NE,
|
IntPredicate::NE,
|
||||||
@ -233,8 +284,8 @@ fn parse_function(
|
|||||||
intrinsics.i32_zero,
|
intrinsics.i32_zero,
|
||||||
&state.var_name(),
|
&state.var_name(),
|
||||||
);
|
);
|
||||||
builder.build_conditional_branch(cond_value, frame.dest(), &false_block);
|
builder.build_conditional_branch(cond_value, frame.br_dest(), &else_block);
|
||||||
builder.position_at_end(&false_block);
|
builder.position_at_end(&else_block);
|
||||||
}
|
}
|
||||||
Operator::BrTable { ref table } => {
|
Operator::BrTable { ref table } => {
|
||||||
let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
|
let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
|
||||||
@ -268,25 +319,131 @@ fn parse_function(
|
|||||||
phi.add_incoming(&[(value, ¤t_block)]);
|
phi.add_incoming(&[(value, ¤t_block)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((case_index_literal, frame.dest()))
|
Ok((case_index_literal, frame.br_dest()))
|
||||||
})
|
})
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
builder.build_switch(index.into_int_value(), default_frame.dest(), &cases[..]);
|
builder.build_switch(index.into_int_value(), default_frame.br_dest(), &cases[..]);
|
||||||
|
|
||||||
state.popn(res_len)?;
|
state.popn(res_len)?;
|
||||||
builder.build_unreachable();
|
builder.build_unreachable();
|
||||||
}
|
}
|
||||||
|
Operator::If { ty } => {
|
||||||
|
let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
|
||||||
|
message: "not currently in a block",
|
||||||
|
offset: -1isize as usize,
|
||||||
|
})?;
|
||||||
|
let if_then_block = context.append_basic_block(&function, "if_then");
|
||||||
|
let if_else_block = context.append_basic_block(&function, "if_else");
|
||||||
|
let end_block = context.append_basic_block(&function, "if_end");
|
||||||
|
|
||||||
|
let end_phis = {
|
||||||
|
builder.position_at_end(&end_block);
|
||||||
|
|
||||||
|
let phis = if let Ok(wasmer_ty) = type_to_type(ty) {
|
||||||
|
let llvm_ty = type_to_llvm(intrinsics, wasmer_ty);
|
||||||
|
[llvm_ty]
|
||||||
|
.iter()
|
||||||
|
.map(|&ty| builder.build_phi(ty, &state.var_name()))
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
SmallVec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
builder.position_at_end(¤t_block);
|
||||||
|
phis
|
||||||
|
};
|
||||||
|
|
||||||
|
let cond = state.pop1()?;
|
||||||
|
|
||||||
|
let cond_value = builder.build_int_compare(
|
||||||
|
IntPredicate::NE,
|
||||||
|
cond.into_int_value(),
|
||||||
|
intrinsics.i32_zero,
|
||||||
|
&state.var_name(),
|
||||||
|
);
|
||||||
|
|
||||||
|
builder.build_conditional_branch(cond_value, &if_then_block, &if_else_block);
|
||||||
|
builder.position_at_end(&if_then_block);
|
||||||
|
state.push_if(if_then_block, if_else_block, end_block, end_phis);
|
||||||
|
}
|
||||||
|
Operator::Else => {
|
||||||
|
if state.reachable {
|
||||||
|
let frame = state.frame_at_depth(0)?;
|
||||||
|
builder.build_unconditional_branch(frame.code_after());
|
||||||
|
let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
|
||||||
|
message: "not currently in a block",
|
||||||
|
offset: -1isize as usize,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
for phi in frame.phis().to_vec().iter().rev() {
|
||||||
|
let value = state.pop1()?;
|
||||||
|
phi.add_incoming(&[(&value, ¤t_block)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (if_else_block, if_else_state) = if let ControlFrame::IfElse {
|
||||||
|
if_else,
|
||||||
|
if_else_state,
|
||||||
|
..
|
||||||
|
} = state.frame_at_depth_mut(0)?
|
||||||
|
{
|
||||||
|
(if_else, if_else_state)
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
*if_else_state = IfElseState::Else;
|
||||||
|
|
||||||
|
builder.position_at_end(if_else_block);
|
||||||
|
state.reachable = true;
|
||||||
|
}
|
||||||
|
|
||||||
Operator::End => {
|
Operator::End => {
|
||||||
let frame = state.pop_frame()?;
|
let frame = state.pop_frame()?;
|
||||||
|
let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
|
||||||
|
message: "not currently in a block",
|
||||||
|
offset: -1isize as usize,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if state.reachable {
|
||||||
|
builder.build_unconditional_branch(frame.code_after());
|
||||||
|
|
||||||
|
for phi in frame.phis().iter().rev() {
|
||||||
|
let value = state.pop1()?;
|
||||||
|
phi.add_incoming(&[(&value, ¤t_block)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ControlFrame::IfElse {
|
||||||
|
if_else,
|
||||||
|
next,
|
||||||
|
phis,
|
||||||
|
if_else_state,
|
||||||
|
..
|
||||||
|
} = &frame
|
||||||
|
{
|
||||||
|
if let IfElseState::If = if_else_state {
|
||||||
|
builder.position_at_end(if_else);
|
||||||
|
builder.build_unconditional_branch(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.position_at_end(frame.code_after());
|
||||||
|
state.reset_stack(&frame);
|
||||||
|
|
||||||
|
state.reachable = true;
|
||||||
|
|
||||||
// Push each phi value to the value stack.
|
// Push each phi value to the value stack.
|
||||||
for phi in frame.phis() {
|
for phi in frame.phis() {
|
||||||
state.push1(phi.as_basic_value());
|
state.push1(phi.as_basic_value());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Operator::Return => {
|
||||||
|
let frame = state.outermost_frame()?;
|
||||||
|
|
||||||
state.reset_stack(&frame);
|
builder.build_unconditional_branch(frame.br_dest());
|
||||||
|
state.reachable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Operator::Unreachable => {
|
Operator::Unreachable => {
|
||||||
@ -294,6 +451,7 @@ fn parse_function(
|
|||||||
// If llvm cannot prove that this is never touched,
|
// If llvm cannot prove that this is never touched,
|
||||||
// it will emit a `ud2` instruction on x86_64 arches.
|
// it will emit a `ud2` instruction on x86_64 arches.
|
||||||
builder.build_unreachable();
|
builder.build_unreachable();
|
||||||
|
state.reachable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
@ -1021,6 +1179,26 @@ fn parse_function(
|
|||||||
unimplemented!("waiting on better bitcasting support in inkwell")
|
unimplemented!("waiting on better bitcasting support in inkwell")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Operator::MemoryGrow { reserved } => {
|
||||||
|
|
||||||
|
let memory_grow_const = intrinsics.i32_ty.const_int(reserved as u64, false);
|
||||||
|
|
||||||
|
let memory_index = MemoryIndex::new(reserved);
|
||||||
|
match memory_index.local_or_import(info) {
|
||||||
|
LocalOrImport::Local(local_mem_index) => {
|
||||||
|
let mem_desc = &info.memories[local_mem_index];
|
||||||
|
match mem_desc.memory_type() {
|
||||||
|
MemoryType::Dynamic => {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
LocalOrImport::Import(import_mem_index) => {
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
op @ _ => {
|
op @ _ => {
|
||||||
println!("{}", module.print_to_string().to_string());
|
println!("{}", module.print_to_string().to_string());
|
||||||
unimplemented!("{:?}", op);
|
unimplemented!("{:?}", op);
|
||||||
@ -1028,5 +1206,12 @@ fn parse_function(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pass_manager = PassManager::create_for_module();
|
||||||
|
pass_manager.add_promote_memory_to_register_pass();
|
||||||
|
pass_manager.add_cfg_simplification_pass();
|
||||||
|
pass_manager.run_on_module(module);
|
||||||
|
|
||||||
|
println!("{}", module.print_to_string().to_string());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,22 @@ pub struct Intrinsics {
|
|||||||
pub i64_zero: IntValue,
|
pub i64_zero: IntValue,
|
||||||
pub f32_zero: FloatValue,
|
pub f32_zero: FloatValue,
|
||||||
pub f64_zero: FloatValue,
|
pub f64_zero: FloatValue,
|
||||||
|
|
||||||
|
// VM intrinsics.
|
||||||
|
pub memory_grow_dynamic_local: FunctionValue,
|
||||||
|
pub memory_grow_static_local: FunctionValue,
|
||||||
|
pub memory_grow_shared_local: FunctionValue,
|
||||||
|
pub memory_grow_dynamic_import: FunctionValue,
|
||||||
|
pub memory_grow_static_import: FunctionValue,
|
||||||
|
pub memory_grow_shared_import: FunctionValue,
|
||||||
|
|
||||||
|
pub memory_size_dynamic_local: FunctionValue,
|
||||||
|
pub memory_size_static_local: FunctionValue,
|
||||||
|
pub memory_size_shared_local: FunctionValue,
|
||||||
|
pub memory_size_dynamic_import: FunctionValue,
|
||||||
|
pub memory_size_static_import: FunctionValue,
|
||||||
|
pub memory_size_shared_import: FunctionValue,
|
||||||
|
// pub ctx_ty: StructType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Intrinsics {
|
impl Intrinsics {
|
||||||
@ -64,6 +80,7 @@ impl Intrinsics {
|
|||||||
let i64_ty = context.i64_type();
|
let i64_ty = context.i64_type();
|
||||||
let f32_ty = context.f32_type();
|
let f32_ty = context.f32_type();
|
||||||
let f64_ty = context.f64_type();
|
let f64_ty = context.f64_type();
|
||||||
|
// let ctx_ty = context.struct_type(&[], false);
|
||||||
|
|
||||||
let i1_zero = i1_ty.const_int(0, false);
|
let i1_zero = i1_ty.const_int(0, false);
|
||||||
let i32_zero = i32_ty.const_int(0, false);
|
let i32_zero = i32_ty.const_int(0, false);
|
||||||
@ -89,6 +106,9 @@ impl Intrinsics {
|
|||||||
let ret_f32_take_f32_f32 = f32_ty.fn_type(&[f32_ty_basic, f32_ty_basic], false);
|
let ret_f32_take_f32_f32 = f32_ty.fn_type(&[f32_ty_basic, f32_ty_basic], false);
|
||||||
let ret_f64_take_f64_f64 = f64_ty.fn_type(&[f64_ty_basic, f64_ty_basic], false);
|
let ret_f64_take_f64_f64 = f64_ty.fn_type(&[f64_ty_basic, f64_ty_basic], false);
|
||||||
|
|
||||||
|
let ret_i32_take_i64_i32_i32 = i32_ty.fn_type(&[i64_ty, i32_ty, i32_ty], false);
|
||||||
|
let ret_i32_take_i64_i32 = i32_ty.fn_type(&[i64_ty, i32_ty], false);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None),
|
ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None),
|
||||||
ctlz_i64: module.add_function("llvm.ctlz.i64", ret_i64_take_i64_i1, None),
|
ctlz_i64: module.add_function("llvm.ctlz.i64", ret_i64_take_i64_i1, None),
|
||||||
@ -138,6 +158,25 @@ impl Intrinsics {
|
|||||||
i64_zero,
|
i64_zero,
|
||||||
f32_zero,
|
f32_zero,
|
||||||
f64_zero,
|
f64_zero,
|
||||||
|
|
||||||
|
// VM intrinsics.
|
||||||
|
memory_grow_dynamic_local: module.add_function("vm.memory.grow.dynamic.local", ret_i32_take_i64_i32_i32, None),
|
||||||
|
memory_grow_static_local: module.add_function("vm.memory.grow.static.local", ret_i32_take_i64_i32_i32, None),
|
||||||
|
memory_grow_shared_local: module.add_function("vm.memory.grow.shared.local", ret_i32_take_i64_i32_i32, None),
|
||||||
|
memory_grow_dynamic_import: module.add_function("vm.memory.grow.dynamic.import", ret_i32_take_i64_i32_i32, None),
|
||||||
|
memory_grow_static_import: module.add_function("vm.memory.grow.static.import", ret_i32_take_i64_i32_i32, None),
|
||||||
|
memory_grow_shared_import: module.add_function("vm.memory.grow.shared.import", ret_i32_take_i64_i32_i32, None),
|
||||||
|
|
||||||
|
memory_size_dynamic_local: module.add_function("vm.memory.size.dynamic.local", ret_i32_take_i64_i32, None),
|
||||||
|
memory_size_static_local: module.add_function("vm.memory.size.static.local", ret_i32_take_i64_i32, None),
|
||||||
|
memory_size_shared_local: module.add_function("vm.memory.size.shared.local", ret_i32_take_i64_i32, None),
|
||||||
|
memory_size_dynamic_import: module.add_function("vm.memory.size.dynamic.import", ret_i32_take_i64_i32, None),
|
||||||
|
memory_size_static_import: module.add_function("vm.memory.size.static.import", ret_i32_take_i64_i32, None),
|
||||||
|
memory_size_shared_import: module.add_function("vm.memory.size.shared.import", ret_i32_take_i64_i32, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub struct CtxType {
|
||||||
|
// ctx_ty: StructType,
|
||||||
|
// }
|
||||||
|
@ -30,21 +30,26 @@ impl Compiler for LLVMCompiler {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_read_module() {
|
fn test_read_module() {
|
||||||
use wabt::wat2wasm;
|
use wabt::wat2wasm;
|
||||||
let WAT: &'static str = r#"
|
let wat = r#"
|
||||||
(module
|
(module
|
||||||
(type $t0 (func (param i32) (result i32)))
|
(type $t0 (func (param i32) (result i32)))
|
||||||
(import "env" "memory" (memory 1 1))
|
(type $t1 (func (result i32)))
|
||||||
(import "env" "table" (table 10 anyfunc))
|
(func $foo (type $t0) (param i32) (result i32)
|
||||||
(import "env" "global" (global i32))
|
get_local 0
|
||||||
(import "env" "print_i32" (func $print_i32 (type $t0)))
|
(if
|
||||||
(func $identity (type $t0) (param $p0 i32) (result i32)
|
(then
|
||||||
get_local $p0)
|
i32.const 42
|
||||||
(func $print_num (export "print_num") (type $t0) (param $p0 i32) (result i32)
|
set_local 0
|
||||||
get_global 0
|
)
|
||||||
call $identity
|
(else
|
||||||
call $print_i32))
|
i32.const 24
|
||||||
|
set_local 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
get_local 0
|
||||||
|
))
|
||||||
"#;
|
"#;
|
||||||
let wasm = wat2wasm(WAT).unwrap();
|
let wasm = wat2wasm(wat).unwrap();
|
||||||
|
|
||||||
let (info, code_reader) = read_info::read_module(&wasm).unwrap();
|
let (info, code_reader) = read_info::read_module(&wasm).unwrap();
|
||||||
|
|
||||||
|
@ -285,7 +285,12 @@ pub fn type_to_type(ty: WpType) -> Result<Type, BinaryReaderError> {
|
|||||||
offset: -1isize as usize,
|
offset: -1isize as usize,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => panic!("broken invariant, invalid type"),
|
_ => {
|
||||||
|
return Err(BinaryReaderError {
|
||||||
|
message: "that type is not supported as a wasmer type",
|
||||||
|
offset: -1isize as usize,
|
||||||
|
});
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,33 +6,73 @@ use smallvec::SmallVec;
|
|||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use wasmparser::BinaryReaderError;
|
use wasmparser::BinaryReaderError;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ControlFrame {
|
pub enum ControlFrame {
|
||||||
Block {
|
Block {
|
||||||
end_label: BasicBlock,
|
next: BasicBlock,
|
||||||
phis: SmallVec<[PhiValue; 1]>,
|
phis: SmallVec<[PhiValue; 1]>,
|
||||||
stack_size_snapshot: usize,
|
stack_size_snapshot: usize,
|
||||||
},
|
},
|
||||||
|
Loop {
|
||||||
|
body: BasicBlock,
|
||||||
|
next: BasicBlock,
|
||||||
|
phis: SmallVec<[PhiValue; 1]>,
|
||||||
|
stack_size_snapshot: usize,
|
||||||
|
},
|
||||||
|
IfElse {
|
||||||
|
if_then: BasicBlock,
|
||||||
|
if_else: BasicBlock,
|
||||||
|
next: BasicBlock,
|
||||||
|
phis: SmallVec<[PhiValue; 1]>,
|
||||||
|
stack_size_snapshot: usize,
|
||||||
|
if_else_state: IfElseState,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum IfElseState {
|
||||||
|
If,
|
||||||
|
Else,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ControlFrame {
|
impl ControlFrame {
|
||||||
pub fn dest(&self) -> &BasicBlock {
|
pub fn code_after(&self) -> &BasicBlock {
|
||||||
match self {
|
match self {
|
||||||
ControlFrame::Block { ref end_label, .. } => end_label,
|
ControlFrame::Block { ref next, .. }
|
||||||
|
| ControlFrame::Loop { ref next, .. }
|
||||||
|
| ControlFrame::IfElse { ref next, .. } => next,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn br_dest(&self) -> &BasicBlock {
|
||||||
|
match self {
|
||||||
|
ControlFrame::Block { ref next, .. } | ControlFrame::IfElse { ref next, .. } => next,
|
||||||
|
ControlFrame::Loop { ref body, .. } => body,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn phis(&self) -> &[PhiValue] {
|
pub fn phis(&self) -> &[PhiValue] {
|
||||||
match self {
|
match self {
|
||||||
ControlFrame::Block { ref phis, .. } => phis.as_slice(),
|
ControlFrame::Block { ref phis, .. }
|
||||||
|
| ControlFrame::Loop { ref phis, .. }
|
||||||
|
| ControlFrame::IfElse { ref phis, .. } => phis.as_slice(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_loop(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
ControlFrame::Loop { .. } => true,
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
stack: Vec<BasicValueEnum>,
|
stack: Vec<BasicValueEnum>,
|
||||||
control_stack: Vec<ControlFrame>,
|
control_stack: Vec<ControlFrame>,
|
||||||
value_counter: Cell<usize>,
|
value_counter: Cell<usize>,
|
||||||
block_counter: Cell<usize>,
|
pub reachable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
@ -41,7 +81,7 @@ impl State {
|
|||||||
stack: vec![],
|
stack: vec![],
|
||||||
control_stack: vec![],
|
control_stack: vec![],
|
||||||
value_counter: Cell::new(0),
|
value_counter: Cell::new(0),
|
||||||
block_counter: Cell::new(0),
|
reachable: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,11 +90,26 @@ impl State {
|
|||||||
ControlFrame::Block {
|
ControlFrame::Block {
|
||||||
stack_size_snapshot,
|
stack_size_snapshot,
|
||||||
..
|
..
|
||||||
|
}
|
||||||
|
| ControlFrame::Loop {
|
||||||
|
stack_size_snapshot,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
| ControlFrame::IfElse {
|
||||||
|
stack_size_snapshot,
|
||||||
|
..
|
||||||
} => *stack_size_snapshot,
|
} => *stack_size_snapshot,
|
||||||
};
|
};
|
||||||
self.stack.truncate(stack_size_snapshot);
|
self.stack.truncate(stack_size_snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn outermost_frame(&self) -> Result<&ControlFrame, BinaryReaderError> {
|
||||||
|
self.control_stack.get(0).ok_or(BinaryReaderError {
|
||||||
|
message: "invalid control stack depth",
|
||||||
|
offset: -1isize as usize,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn frame_at_depth(&self, depth: u32) -> Result<&ControlFrame, BinaryReaderError> {
|
pub fn frame_at_depth(&self, depth: u32) -> Result<&ControlFrame, BinaryReaderError> {
|
||||||
let index = self.control_stack.len() - 1 - (depth as usize);
|
let index = self.control_stack.len() - 1 - (depth as usize);
|
||||||
self.control_stack.get(index).ok_or(BinaryReaderError {
|
self.control_stack.get(index).ok_or(BinaryReaderError {
|
||||||
@ -63,6 +118,17 @@ impl State {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn frame_at_depth_mut(
|
||||||
|
&mut self,
|
||||||
|
depth: u32,
|
||||||
|
) -> Result<&mut ControlFrame, BinaryReaderError> {
|
||||||
|
let index = self.control_stack.len() - 1 - (depth as usize);
|
||||||
|
self.control_stack.get_mut(index).ok_or(BinaryReaderError {
|
||||||
|
message: "invalid control stack depth",
|
||||||
|
offset: -1isize as usize,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pop_frame(&mut self) -> Result<ControlFrame, BinaryReaderError> {
|
pub fn pop_frame(&mut self) -> Result<ControlFrame, BinaryReaderError> {
|
||||||
self.control_stack.pop().ok_or(BinaryReaderError {
|
self.control_stack.pop().ok_or(BinaryReaderError {
|
||||||
message: "cannot pop from control stack",
|
message: "cannot pop from control stack",
|
||||||
@ -70,13 +136,6 @@ impl State {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn block_name(&self) -> String {
|
|
||||||
let counter = self.block_counter.get();
|
|
||||||
let s = format!("block{}", counter);
|
|
||||||
self.block_counter.set(counter + 1);
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn var_name(&self) -> String {
|
pub fn var_name(&self) -> String {
|
||||||
let counter = self.value_counter.get();
|
let counter = self.value_counter.get();
|
||||||
let s = format!("s{}", counter);
|
let s = format!("s{}", counter);
|
||||||
@ -129,6 +188,12 @@ impl State {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn popn_save(&mut self, n: usize) -> Result<Vec<BasicValueEnum>, BinaryReaderError> {
|
||||||
|
let v = self.peekn(n)?.to_vec();
|
||||||
|
self.popn(n)?;
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn popn(&mut self, n: usize) -> Result<(), BinaryReaderError> {
|
pub fn popn(&mut self, n: usize) -> Result<(), BinaryReaderError> {
|
||||||
if self.stack.len() < n {
|
if self.stack.len() < n {
|
||||||
return Err(BinaryReaderError {
|
return Err(BinaryReaderError {
|
||||||
@ -142,11 +207,37 @@ impl State {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_block(&mut self, end_label: BasicBlock, phis: SmallVec<[PhiValue; 1]>) {
|
pub fn push_block(&mut self, next: BasicBlock, phis: SmallVec<[PhiValue; 1]>) {
|
||||||
self.control_stack.push(ControlFrame::Block {
|
self.control_stack.push(ControlFrame::Block {
|
||||||
end_label,
|
next,
|
||||||
phis,
|
phis,
|
||||||
stack_size_snapshot: self.stack.len(),
|
stack_size_snapshot: self.stack.len(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn push_loop(&mut self, body: BasicBlock, next: BasicBlock, phis: SmallVec<[PhiValue; 1]>) {
|
||||||
|
self.control_stack.push(ControlFrame::Loop {
|
||||||
|
body,
|
||||||
|
next,
|
||||||
|
phis,
|
||||||
|
stack_size_snapshot: self.stack.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_if(
|
||||||
|
&mut self,
|
||||||
|
if_then: BasicBlock,
|
||||||
|
if_else: BasicBlock,
|
||||||
|
next: BasicBlock,
|
||||||
|
phis: SmallVec<[PhiValue; 1]>,
|
||||||
|
) {
|
||||||
|
self.control_stack.push(ControlFrame::IfElse {
|
||||||
|
if_then,
|
||||||
|
if_else,
|
||||||
|
next,
|
||||||
|
phis,
|
||||||
|
stack_size_snapshot: self.stack.len(),
|
||||||
|
if_else_state: IfElseState::If,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user