implement load* and store* instructions

This commit is contained in:
Lachlan Sneff
2019-02-14 15:13:58 -08:00
parent 2572a0259b
commit 8827830aba
5 changed files with 811 additions and 132 deletions

View File

@ -3,30 +3,35 @@ use inkwell::{
context::Context,
module::Module,
passes::PassManager,
types::{BasicType, BasicTypeEnum, FunctionType},
values::{BasicValue, FunctionValue, PhiValue},
types::{BasicType, BasicTypeEnum, FunctionType, PointerType},
values::{BasicValue, FunctionValue, PhiValue, PointerValue},
FloatPredicate, IntPredicate,
};
use smallvec::SmallVec;
use wasmer_runtime_core::{
memory::MemoryType,
module::ModuleInfo,
structures::{Map, SliceMap, TypedIndex},
types::{FuncIndex, MemoryIndex, FuncSig, LocalFuncIndex, LocalOrImport, SigIndex, Type, MemoryType},
types::{FuncIndex, FuncSig, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, Type},
};
use wasmparser::{
BinaryReaderError, CodeSectionReader, LocalsReader, MemoryImmediate, Operator, OperatorsReader,
};
use wasmparser::{BinaryReaderError, CodeSectionReader, LocalsReader, Operator, OperatorsReader};
use crate::intrinsics::Intrinsics;
use crate::intrinsics::{CtxType, Intrinsics};
use crate::read_info::type_to_type;
use crate::state::{ControlFrame, IfElseState, State};
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 param_types: Vec<_> = user_param_types.collect();
let param_types: Vec<_> = std::iter::once(intrinsics.ctx_ptr_ty.as_basic_type_enum())
.chain(user_param_types)
.collect();
match sig.returns() {
[] => intrinsics.void_ty.fn_type(&param_types, false),
[single_value] => type_to_llvm(intrinsics, *single_value).fn_type(&param_types, false),
&[] => intrinsics.void_ty.fn_type(&param_types, false),
&[single_value] => type_to_llvm(intrinsics, single_value).fn_type(&param_types, false),
returns @ _ => {
let basic_types: Vec<_> = returns
.iter()
@ -149,14 +154,22 @@ fn parse_function(
state.push_block(return_block, phis);
builder.position_at_end(&entry_block);
let mut locals = Vec::with_capacity(locals_reader.get_count() as usize);
locals.extend(function.get_param_iter().enumerate().map(|(index, param)| {
let ty = param.get_type();
let mut ctx = intrinsics.ctx(info, builder, &function);
let alloca = builder.build_alloca(ty, &format!("local{}", index));
builder.build_store(alloca, param);
alloca
}));
let mut locals = Vec::with_capacity(locals_reader.get_count() as usize);
locals.extend(
function
.get_param_iter()
.skip(1)
.enumerate()
.map(|(index, param)| {
let ty = param.get_type();
let alloca = builder.build_alloca(ty, &format!("local{}", index));
builder.build_store(alloca, param);
alloca
}),
);
for (index, local) in locals_reader.into_iter().enumerate().skip(locals.len()) {
let (_, ty) = local?;
@ -520,11 +533,13 @@ fn parse_function(
LocalOrImport::Local(local_func_index) => {
let func_sig = &info.signatures[sigindex];
let func_value = functions[local_func_index];
let call_site = builder.build_call(
func_value,
&state.peekn(func_sig.params().len())?.to_vec(),
&state.var_name(),
);
let params: Vec<_> = [ctx.basic()]
.iter()
.chain(state.peekn(func_sig.params().len())?.iter())
.map(|v| *v)
.collect();
let call_site = builder.build_call(func_value, &params, &state.var_name());
if let Some(basic_value) = call_site.try_as_basic_value().left() {
match func_sig.returns().len() {
1 => state.push1(basic_value),
@ -1179,24 +1194,378 @@ fn parse_function(
unimplemented!("waiting on better bitcasting support in inkwell")
}
/***************************
* Load and Store instructions.
* https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#load-and-store-instructions
***************************/
Operator::I32Load { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i32_ptr_ty,
)?;
let result = builder.build_load(effective_address, &state.var_name());
state.push1(result);
}
Operator::I64Load { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i64_ptr_ty,
)?;
let result = builder.build_load(effective_address, &state.var_name());
state.push1(result);
}
Operator::F32Load { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i32_ptr_ty,
)?;
let result = builder.build_load(effective_address, &state.var_name());
state.push1(result);
}
Operator::F64Load { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.f64_ptr_ty,
)?;
let result = builder.build_load(effective_address, &state.var_name());
state.push1(result);
}
Operator::I32Store { memarg } => {
let value = state.pop1()?;
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i32_ptr_ty,
)?;
builder.build_store(effective_address, value);
}
Operator::I64Store { memarg } => {
let value = state.pop1()?;
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i64_ptr_ty,
)?;
builder.build_store(effective_address, value);
}
Operator::F32Store { memarg } => {
let value = state.pop1()?;
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.f32_ptr_ty,
)?;
builder.build_store(effective_address, value);
}
Operator::F64Store { memarg } => {
let value = state.pop1()?;
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.f64_ptr_ty,
)?;
builder.build_store(effective_address, value);
}
Operator::I32Load8S { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i8_ptr_ty,
)?;
let narrow_result = builder
.build_load(effective_address, &state.var_name())
.into_int_value();
let result =
builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name());
state.push1(result);
}
Operator::I32Load16S { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i16_ptr_ty,
)?;
let narrow_result = builder
.build_load(effective_address, &state.var_name())
.into_int_value();
let result =
builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name());
state.push1(result);
}
Operator::I64Load8S { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i8_ptr_ty,
)?;
let narrow_result = builder
.build_load(effective_address, &state.var_name())
.into_int_value();
let result =
builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name());
state.push1(result);
}
Operator::I64Load16S { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i16_ptr_ty,
)?;
let narrow_result = builder
.build_load(effective_address, &state.var_name())
.into_int_value();
let result =
builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name());
state.push1(result);
}
Operator::I64Load32S { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i32_ptr_ty,
)?;
let narrow_result = builder
.build_load(effective_address, &state.var_name())
.into_int_value();
let result =
builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name());
state.push1(result);
}
Operator::I32Load8U { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i8_ptr_ty,
)?;
let narrow_result = builder
.build_load(effective_address, &state.var_name())
.into_int_value();
let result =
builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name());
state.push1(result);
}
Operator::I32Load16U { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i16_ptr_ty,
)?;
let narrow_result = builder
.build_load(effective_address, &state.var_name())
.into_int_value();
let result =
builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name());
state.push1(result);
}
Operator::I64Load8U { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i8_ptr_ty,
)?;
let narrow_result = builder
.build_load(effective_address, &state.var_name())
.into_int_value();
let result =
builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name());
state.push1(result);
}
Operator::I64Load16U { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i16_ptr_ty,
)?;
let narrow_result = builder
.build_load(effective_address, &state.var_name())
.into_int_value();
let result =
builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name());
state.push1(result);
}
Operator::I64Load32U { memarg } => {
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i32_ptr_ty,
)?;
let narrow_result = builder
.build_load(effective_address, &state.var_name())
.into_int_value();
let result =
builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name());
state.push1(result);
}
Operator::I32Store8 { memarg } | Operator::I64Store8 { memarg } => {
let value = state.pop1()?.into_int_value();
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i8_ptr_ty,
)?;
let narrow_value =
builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name());
builder.build_store(effective_address, narrow_value);
}
Operator::I32Store16 { memarg } | Operator::I64Store16 { memarg } => {
let value = state.pop1()?.into_int_value();
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i16_ptr_ty,
)?;
let narrow_value =
builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name());
builder.build_store(effective_address, narrow_value);
}
Operator::I64Store32 { memarg } => {
let value = state.pop1()?.into_int_value();
let effective_address = resolve_memory_ptr(
builder,
intrinsics,
&mut state,
&mut ctx,
memarg,
intrinsics.i32_ptr_ty,
)?;
let narrow_value =
builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name());
builder.build_store(effective_address, narrow_value);
}
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) {
let memory_index = MemoryIndex::new(reserved as usize);
let func_value = 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 => {
}
MemoryType::Dynamic => intrinsics.memory_grow_dynamic_local,
MemoryType::Static => intrinsics.memory_grow_static_local,
MemoryType::SharedStatic => intrinsics.memory_grow_shared_local,
}
},
}
LocalOrImport::Import(import_mem_index) => {
let mem_desc = &info.imported_memories[import_mem_index].1;
match mem_desc.memory_type() {
MemoryType::Dynamic => intrinsics.memory_grow_dynamic_import,
MemoryType::Static => intrinsics.memory_grow_static_import,
MemoryType::SharedStatic => intrinsics.memory_grow_shared_import,
}
}
};
},
}
let memory_index_const = intrinsics
.i32_ty
.const_int(reserved as u64, false)
.as_basic_value_enum();
let delta = state.pop1()?;
let result = builder.build_call(
func_value,
&[ctx.basic(), memory_index_const, delta],
&state.var_name(),
);
state.push1(result.try_as_basic_value().left().unwrap());
}
Operator::MemorySize { reserved } => {
let memory_index = MemoryIndex::new(reserved as usize);
let func_value = 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 => intrinsics.memory_size_dynamic_local,
MemoryType::Static => intrinsics.memory_size_static_local,
MemoryType::SharedStatic => intrinsics.memory_size_shared_local,
}
}
LocalOrImport::Import(import_mem_index) => {
let mem_desc = &info.imported_memories[import_mem_index].1;
match mem_desc.memory_type() {
MemoryType::Dynamic => intrinsics.memory_size_dynamic_import,
MemoryType::Static => intrinsics.memory_size_static_import,
MemoryType::SharedStatic => intrinsics.memory_size_shared_import,
}
}
};
let memory_index_const = intrinsics
.i32_ty
.const_int(reserved as u64, false)
.as_basic_value_enum();
let result = builder.build_call(
func_value,
&[ctx.basic(), memory_index_const],
&state.var_name(),
);
state.push1(result.try_as_basic_value().left().unwrap());
}
op @ _ => {
@ -1209,9 +1578,41 @@ 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.add_instruction_combining_pass();
// pass_manager.add_aggressive_inst_combiner_pass();
// pass_manager.add_merged_load_store_motion_pass();
// pass_manager.add_sccp_pass();
pass_manager.add_gvn_pass();
pass_manager.add_new_gvn_pass();
pass_manager.add_aggressive_dce_pass();
pass_manager.run_on_module(module);
println!("{}", module.print_to_string().to_string());
Ok(())
}
fn resolve_memory_ptr(
builder: &Builder,
intrinsics: &Intrinsics,
state: &mut State,
ctx: &mut CtxType,
memarg: MemoryImmediate,
ptr_ty: PointerType,
) -> Result<PointerValue, BinaryReaderError> {
// Ignore alignment hint for the time being.
let imm_offset = intrinsics.i64_ty.const_int(memarg.offset as u64, false);
let var_offset_i32 = state.pop1()?.into_int_value();
let var_offset =
builder.build_int_z_extend(var_offset_i32, intrinsics.i64_ty, &state.var_name());
let effective_offset = builder.build_int_add(var_offset, imm_offset, &state.var_name());
let (mem_base, mem_bound) = ctx.memory(MemoryIndex::new(0));
let mem_base_int = builder.build_ptr_to_int(mem_base, intrinsics.i64_ty, &state.var_name());
let effective_address_int =
builder.build_int_add(mem_base_int, effective_offset, &state.var_name());
Ok(builder.build_int_to_ptr(
effective_address_int,
intrinsics.i32_ptr_ty,
&state.var_name(),
))
}

View File

@ -1,8 +1,18 @@
use hashbrown::HashMap;
use inkwell::{
builder::Builder,
context::Context,
module::Module,
types::{BasicType, FloatType, IntType, VoidType},
values::{FloatValue, FunctionValue, IntValue},
types::{BasicType, FloatType, IntType, PointerType, StructType, VoidType},
values::{BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue},
AddressSpace,
};
use std::marker::PhantomData;
use wasmer_runtime_core::{
memory::MemoryType,
module::ModuleInfo,
structures::TypedIndex,
types::{LocalOrImport, MemoryIndex},
};
pub struct Intrinsics {
@ -44,11 +54,20 @@ pub struct Intrinsics {
pub void_ty: VoidType,
pub i1_ty: IntType,
pub i8_ty: IntType,
pub i16_ty: IntType,
pub i32_ty: IntType,
pub i64_ty: IntType,
pub f32_ty: FloatType,
pub f64_ty: FloatType,
pub i8_ptr_ty: PointerType,
pub i16_ptr_ty: PointerType,
pub i32_ptr_ty: PointerType,
pub i64_ptr_ty: PointerType,
pub f32_ptr_ty: PointerType,
pub f64_ptr_ty: PointerType,
pub i1_zero: IntValue,
pub i32_zero: IntValue,
pub i64_zero: IntValue,
@ -69,18 +88,30 @@ pub struct Intrinsics {
pub memory_size_dynamic_import: FunctionValue,
pub memory_size_static_import: FunctionValue,
pub memory_size_shared_import: FunctionValue,
// pub ctx_ty: StructType,
ctx_ty: StructType,
pub ctx_ptr_ty: PointerType,
}
impl Intrinsics {
pub fn declare(module: &Module, context: &Context) -> Self {
let void_ty = context.void_type();
let i1_ty = context.bool_type();
let i8_ty = context.i8_type();
let i16_ty = context.i16_type();
let i32_ty = context.i32_type();
let i64_ty = context.i64_type();
let f32_ty = context.f32_type();
let f64_ty = context.f64_type();
// let ctx_ty = context.struct_type(&[], false);
let i8_ptr_ty = i8_ty.ptr_type(AddressSpace::Generic);
let i16_ptr_ty = i16_ty.ptr_type(AddressSpace::Generic);
let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::Generic);
let i64_ptr_ty = i64_ty.ptr_type(AddressSpace::Generic);
let f32_ptr_ty = f32_ty.ptr_type(AddressSpace::Generic);
let f64_ptr_ty = f64_ty.ptr_type(AddressSpace::Generic);
let opaque_ptr_ty = void_ty.ptr_type(AddressSpace::Generic);
let i1_zero = i1_ty.const_int(0, false);
let i32_zero = i32_ty.const_int(0, false);
@ -93,6 +124,53 @@ impl Intrinsics {
let i64_ty_basic = i64_ty.as_basic_type_enum();
let f32_ty_basic = f32_ty.as_basic_type_enum();
let f64_ty_basic = f64_ty.as_basic_type_enum();
let i8_ptr_ty_basic = i8_ptr_ty.as_basic_type_enum();
let opaque_ptr_ty_basic = opaque_ptr_ty.as_basic_type_enum();
let ctx_ty = context.opaque_struct_type("ctx");
let ctx_ptr_ty = ctx_ty.ptr_type(AddressSpace::Generic);
let local_memory_ty =
context.struct_type(&[i8_ptr_ty_basic, i64_ty_basic, opaque_ptr_ty_basic], false);
let local_table_ty = local_memory_ty;
let local_global_ty = i64_ty;
let imported_func_ty = context.struct_type(
&[opaque_ptr_ty_basic, ctx_ptr_ty.as_basic_type_enum()],
false,
);
ctx_ty.set_body(
&[
local_memory_ty
.ptr_type(AddressSpace::Generic)
.ptr_type(AddressSpace::Generic)
.as_basic_type_enum(),
local_table_ty
.ptr_type(AddressSpace::Generic)
.ptr_type(AddressSpace::Generic)
.as_basic_type_enum(),
local_global_ty
.ptr_type(AddressSpace::Generic)
.ptr_type(AddressSpace::Generic)
.as_basic_type_enum(),
local_memory_ty
.ptr_type(AddressSpace::Generic)
.ptr_type(AddressSpace::Generic)
.as_basic_type_enum(),
local_table_ty
.ptr_type(AddressSpace::Generic)
.ptr_type(AddressSpace::Generic)
.as_basic_type_enum(),
local_global_ty
.ptr_type(AddressSpace::Generic)
.ptr_type(AddressSpace::Generic)
.as_basic_type_enum(),
imported_func_ty
.ptr_type(AddressSpace::Generic)
.ptr_type(AddressSpace::Generic)
.as_basic_type_enum(),
],
false,
);
let ret_i32_take_i32_i1 = i32_ty.fn_type(&[i32_ty_basic, i1_ty_basic], false);
let ret_i64_take_i64_i1 = i64_ty.fn_type(&[i64_ty_basic, i1_ty_basic], false);
@ -106,8 +184,9 @@ impl Intrinsics {
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_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);
let ret_i32_take_i64_i32_i32 =
i32_ty.fn_type(&[i64_ty_basic, i32_ty_basic, i32_ty_basic], false);
let ret_i32_take_i64_i32 = i32_ty.fn_type(&[i64_ty_basic, i32_ty_basic], false);
Self {
ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None),
@ -148,11 +227,20 @@ impl Intrinsics {
void_ty,
i1_ty,
i8_ty,
i16_ty,
i32_ty,
i64_ty,
f32_ty,
f64_ty,
i8_ptr_ty,
i16_ptr_ty,
i32_ptr_ty,
i64_ptr_ty,
f32_ptr_ty,
f64_ptr_ty,
i1_zero,
i32_zero,
i64_zero,
@ -160,23 +248,229 @@ impl Intrinsics {
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_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),
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,
),
ctx_ty,
ctx_ptr_ty,
}
}
pub fn ctx<'a>(
&'a self,
info: &'a ModuleInfo,
builder: &'a Builder,
func_value: &'a FunctionValue,
) -> CtxType<'a> {
CtxType {
ctx_ty: self.ctx_ty,
ctx_ptr_ty: self.ctx_ptr_ty,
ctx_ptr_value: func_value.get_nth_param(0).unwrap().into_pointer_value(),
builder,
intrinsics: self,
info,
cached_memories: HashMap::new(),
_phantom: PhantomData,
}
}
}
// pub struct CtxType {
// ctx_ty: StructType,
enum MemoryCache {
/// The memory moves around.
Dynamic {
ptr_to_base_ptr: PointerValue,
ptr_to_bounds: PointerValue,
},
/// The memory is always in the same place.
Static {
base_ptr: PointerValue,
bounds: IntValue,
},
}
pub struct CtxType<'a> {
ctx_ty: StructType,
ctx_ptr_ty: PointerType,
ctx_ptr_value: PointerValue,
builder: &'a Builder,
intrinsics: &'a Intrinsics,
info: &'a ModuleInfo,
cached_memories: HashMap<MemoryIndex, MemoryCache>,
_phantom: PhantomData<&'a FunctionValue>,
}
impl<'a> CtxType<'a> {
pub fn basic(&self) -> BasicValueEnum {
self.ctx_ptr_value.as_basic_value_enum()
}
pub fn memory(&mut self, index: MemoryIndex) -> (PointerValue, IntValue) {
let (cached_memories, builder, info, ctx_ptr_value, intrinsics) = (
&mut self.cached_memories,
self.builder,
self.info,
self.ctx_ptr_value,
self.intrinsics,
);
let memory_cache = cached_memories.entry(index).or_insert_with(|| {
let (memory_array_ptr_ptr, index, memory_type) = match index.local_or_import(info) {
LocalOrImport::Local(local_mem_index) => (
unsafe { builder.build_struct_gep(ctx_ptr_value, 0, "memory_array_ptr_ptr") },
local_mem_index.index() as u64,
info.memories[local_mem_index].memory_type(),
),
LocalOrImport::Import(import_mem_index) => (
unsafe { builder.build_struct_gep(ctx_ptr_value, 3, "memory_array_ptr_ptr") },
import_mem_index.index() as u64,
info.imported_memories[import_mem_index].1.memory_type(),
),
};
let memory_array_ptr = builder
.build_load(memory_array_ptr_ptr, "memory_array_ptr")
.into_pointer_value();
let const_index = intrinsics.i32_ty.const_int(index, false);
let memory_ptr_ptr = unsafe {
builder.build_in_bounds_gep(memory_array_ptr, &[const_index], "memory_ptr_ptr")
};
let memory_ptr = builder
.build_load(memory_ptr_ptr, "memory_ptr")
.into_pointer_value();
let (ptr_to_base_ptr, ptr_to_bounds) = unsafe {
(
builder.build_struct_gep(memory_ptr, 0, "base_ptr"),
builder.build_struct_gep(memory_ptr, 1, "bounds_ptr"),
)
};
match memory_type {
MemoryType::Dynamic => MemoryCache::Dynamic {
ptr_to_base_ptr,
ptr_to_bounds,
},
MemoryType::Static | MemoryType::SharedStatic => MemoryCache::Static {
base_ptr: builder
.build_load(ptr_to_base_ptr, "base")
.into_pointer_value(),
bounds: builder.build_load(ptr_to_bounds, "bounds").into_int_value(),
},
}
});
match memory_cache {
MemoryCache::Dynamic {
ptr_to_base_ptr,
ptr_to_bounds,
} => {
let base = builder
.build_load(*ptr_to_base_ptr, "base")
.into_pointer_value();
let bounds = builder
.build_load(*ptr_to_bounds, "bounds")
.into_int_value();
(base, bounds)
}
MemoryCache::Static { base_ptr, bounds } => (*base_ptr, *bounds),
}
}
}
// pub struct Ctx {
// /// A pointer to an array of locally-defined memories, indexed by `MemoryIndex`.
// pub(crate) memories: *mut *mut LocalMemory,
// /// A pointer to an array of locally-defined tables, indexed by `TableIndex`.
// pub(crate) tables: *mut *mut LocalTable,
// /// A pointer to an array of locally-defined globals, indexed by `GlobalIndex`.
// pub(crate) globals: *mut *mut LocalGlobal,
// /// A pointer to an array of imported memories, indexed by `MemoryIndex,
// pub(crate) imported_memories: *mut *mut LocalMemory,
// /// A pointer to an array of imported tables, indexed by `TableIndex`.
// pub(crate) imported_tables: *mut *mut LocalTable,
// /// A pointer to an array of imported globals, indexed by `GlobalIndex`.
// pub(crate) imported_globals: *mut *mut LocalGlobal,
// /// A pointer to an array of imported functions, indexed by `FuncIndex`.
// pub(crate) imported_funcs: *mut ImportedFunc,
// local_backing: *mut LocalBacking,
// import_backing: *mut ImportBacking,
// module: *const ModuleInner,
// pub data: *mut c_void,
// pub data_finalizer: Option<extern "C" fn(data: *mut c_void)>,
// }

View File

@ -34,19 +34,16 @@ fn test_read_module() {
(module
(type $t0 (func (param i32) (result i32)))
(type $t1 (func (result i32)))
(memory 1)
(func $foo (type $t0) (param i32) (result i32)
get_local 0
(if
(then
i32.const 42
set_local 0
)
(else
i32.const 24
set_local 0
)
)
get_local 0
i32.load offset=16
i32.const 1
memory.grow
drop
i32.const 0
i32.load offset=4
i32.add
))
"#;
let wasm = wat2wasm(wat).unwrap();

View File

@ -72,6 +72,7 @@ pub struct State {
stack: Vec<BasicValueEnum>,
control_stack: Vec<ControlFrame>,
value_counter: Cell<usize>,
pub reachable: bool,
}