mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 06:15:33 +00:00
Implement memory and global operations
This commit is contained in:
parent
2d87f64f82
commit
73b4f7d337
1358
Cargo.lock
generated
Normal file
1358
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -5,20 +5,22 @@ use inkwell::{
|
||||
passes::PassManager,
|
||||
types::{BasicType, BasicTypeEnum, FunctionType, PointerType},
|
||||
values::{BasicValue, FunctionValue, PhiValue, PointerValue},
|
||||
FloatPredicate, IntPredicate,
|
||||
AddressSpace, FloatPredicate, IntPredicate,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use wasmer_runtime_core::{
|
||||
memory::MemoryType,
|
||||
module::ModuleInfo,
|
||||
structures::{Map, SliceMap, TypedIndex},
|
||||
types::{FuncIndex, FuncSig, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, Type},
|
||||
types::{
|
||||
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, Type,
|
||||
},
|
||||
};
|
||||
use wasmparser::{
|
||||
BinaryReaderError, CodeSectionReader, LocalsReader, MemoryImmediate, Operator, OperatorsReader,
|
||||
};
|
||||
|
||||
use crate::intrinsics::{CtxType, Intrinsics};
|
||||
use crate::intrinsics::{CtxType, GlobalCache, Intrinsics};
|
||||
use crate::read_info::type_to_type;
|
||||
use crate::state::{ControlFrame, IfElseState, State};
|
||||
|
||||
@ -515,8 +517,32 @@ fn parse_function(
|
||||
builder.build_store(pointer_value, v);
|
||||
}
|
||||
|
||||
Operator::GetGlobal { global_index } => unimplemented!(),
|
||||
Operator::SetGlobal { global_index } => unimplemented!(),
|
||||
Operator::GetGlobal { global_index } => {
|
||||
let index = GlobalIndex::new(global_index as usize);
|
||||
let global_cache = ctx.global_cache(index);
|
||||
match global_cache {
|
||||
GlobalCache::Const { value } => {
|
||||
state.push1(value.as_basic_value_enum());
|
||||
}
|
||||
GlobalCache::Mut { ptr_to_value } => {
|
||||
let value = builder.build_load(ptr_to_value, "global_value");
|
||||
state.push1(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
Operator::SetGlobal { global_index } => {
|
||||
let value = state.pop1()?;
|
||||
let index = GlobalIndex::new(global_index as usize);
|
||||
let global_cache = ctx.global_cache(index);
|
||||
match global_cache {
|
||||
GlobalCache::Mut { ptr_to_value } => {
|
||||
builder.build_store(ptr_to_value, value);
|
||||
}
|
||||
GlobalCache::Const { value: _ } => {
|
||||
unreachable!("cannot set non-mutable globals")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Operator::Select => {
|
||||
let (v1, v2, cond) = state.pop3()?;
|
||||
@ -528,10 +554,10 @@ fn parse_function(
|
||||
let func_index = FuncIndex::new(function_index as usize);
|
||||
let sigindex = info.func_assoc[func_index];
|
||||
let llvm_sig = signatures[sigindex];
|
||||
let func_sig = &info.signatures[sig_index];
|
||||
|
||||
match func_index.local_or_import(info) {
|
||||
let call_site = match func_index.local_or_import(info) {
|
||||
LocalOrImport::Local(local_func_index) => {
|
||||
let func_sig = &info.signatures[sigindex];
|
||||
let func_value = functions[local_func_index];
|
||||
let params: Vec<_> = [ctx.basic()]
|
||||
.iter()
|
||||
@ -539,26 +565,45 @@ fn parse_function(
|
||||
.map(|v| *v)
|
||||
.collect();
|
||||
|
||||
let call_site = builder.build_call(func_value, ¶ms, &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),
|
||||
count @ _ => {
|
||||
// This is a multi-value return.
|
||||
let struct_value = basic_value.into_struct_value();
|
||||
for i in 0..(count as u32) {
|
||||
let value = builder.build_extract_value(
|
||||
struct_value,
|
||||
i,
|
||||
&state.var_name(),
|
||||
);
|
||||
state.push1(value);
|
||||
}
|
||||
}
|
||||
builder.build_call(func_value, ¶ms, &state.var_name())
|
||||
}
|
||||
LocalOrImport::Import(import_func_index) => {
|
||||
let (func_ptr_untyped, ctx_ptr) = ctx.imported_func(import_func_index);
|
||||
let params: Vec<_> = [ctx_ptr.as_basic_value_enum()]
|
||||
.iter()
|
||||
.chain(state.peekn(func_sig.params().len())?.iter())
|
||||
.map(|v| *v)
|
||||
.collect();
|
||||
|
||||
let func_ptr_ty = llvm_sig.ptr_type(AddressSpace::Generic);
|
||||
|
||||
// Once we can just bitcast between pointer types, remove this.
|
||||
let func_ptr = {
|
||||
let ptr_int = builder.build_ptr_to_int(
|
||||
func_ptr_untyped,
|
||||
intrinsics.i64_ty,
|
||||
"func_ptr_int",
|
||||
);
|
||||
builder.build_int_to_ptr(ptr_int, func_ptr_ty, "typed_func_ptr")
|
||||
};
|
||||
|
||||
builder.build_call(func_ptr, ¶ms, &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),
|
||||
count @ _ => {
|
||||
// This is a multi-value return.
|
||||
let struct_value = basic_value.into_struct_value();
|
||||
for i in 0..(count as u32) {
|
||||
let value =
|
||||
builder.build_extract_value(struct_value, i, &state.var_name());
|
||||
state.push1(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
LocalOrImport::Import(import_func_index) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
Operator::CallIndirect { index, table_index } => {
|
||||
@ -1129,25 +1174,37 @@ fn parse_function(
|
||||
let res = builder.build_int_z_extend(v1, intrinsics.i64_ty, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32TruncSF32 | Operator::I32TruncSF64 => {
|
||||
Operator::I32TruncSF32
|
||||
| Operator::I32TruncSF64
|
||||
| Operator::I32TruncSSatF32
|
||||
| Operator::I32TruncSSatF64 => {
|
||||
let v1 = state.pop1()?.into_float_value();
|
||||
let res =
|
||||
builder.build_float_to_signed_int(v1, intrinsics.i32_ty, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I64TruncSF32 | Operator::I64TruncSF64 => {
|
||||
Operator::I64TruncSF32
|
||||
| Operator::I64TruncSF64
|
||||
| Operator::I64TruncSSatF32
|
||||
| Operator::I64TruncSSatF64 => {
|
||||
let v1 = state.pop1()?.into_float_value();
|
||||
let res =
|
||||
builder.build_float_to_signed_int(v1, intrinsics.i64_ty, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32TruncUF32 | Operator::I32TruncUF64 => {
|
||||
Operator::I32TruncUF32
|
||||
| Operator::I32TruncUF64
|
||||
| Operator::I32TruncUSatF32
|
||||
| Operator::I32TruncUSatF64 => {
|
||||
let v1 = state.pop1()?.into_float_value();
|
||||
let res =
|
||||
builder.build_float_to_unsigned_int(v1, intrinsics.i32_ty, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I64TruncUF32 | Operator::I64TruncUF64 => {
|
||||
Operator::I64TruncUF32
|
||||
| Operator::I64TruncUF64
|
||||
| Operator::I64TruncUSatF32
|
||||
| Operator::I64TruncUSatF64 => {
|
||||
let v1 = state.pop1()?.into_float_value();
|
||||
let res =
|
||||
builder.build_float_to_unsigned_int(v1, intrinsics.i64_ty, &state.var_name());
|
||||
@ -1194,6 +1251,51 @@ fn parse_function(
|
||||
unimplemented!("waiting on better bitcasting support in inkwell")
|
||||
}
|
||||
|
||||
/***************************
|
||||
* Sign-extension operators.
|
||||
* https://github.com/WebAssembly/sign-extension-ops/blob/master/proposals/sign-extension-ops/Overview.md
|
||||
***************************/
|
||||
Operator::I32Extend8S => {
|
||||
let value = state.pop1()?.into_int_value();
|
||||
let narrow_value =
|
||||
builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name());
|
||||
let extended_value =
|
||||
builder.build_int_s_extend(narrow_value, intrinsics.i32_ty, &state.var_name());
|
||||
state.push1(extended_value);
|
||||
}
|
||||
Operator::I32Extend16S => {
|
||||
let value = state.pop1()?.into_int_value();
|
||||
let narrow_value =
|
||||
builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name());
|
||||
let extended_value =
|
||||
builder.build_int_s_extend(narrow_value, intrinsics.i32_ty, &state.var_name());
|
||||
state.push1(extended_value);
|
||||
}
|
||||
Operator::I64Extend8S => {
|
||||
let value = state.pop1()?.into_int_value();
|
||||
let narrow_value =
|
||||
builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name());
|
||||
let extended_value =
|
||||
builder.build_int_s_extend(narrow_value, intrinsics.i64_ty, &state.var_name());
|
||||
state.push1(extended_value);
|
||||
}
|
||||
Operator::I64Extend16S => {
|
||||
let value = state.pop1()?.into_int_value();
|
||||
let narrow_value =
|
||||
builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name());
|
||||
let extended_value =
|
||||
builder.build_int_s_extend(narrow_value, intrinsics.i64_ty, &state.var_name());
|
||||
state.push1(extended_value);
|
||||
}
|
||||
Operator::I64Extend32S => {
|
||||
let value = state.pop1()?.into_int_value();
|
||||
let narrow_value =
|
||||
builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name());
|
||||
let extended_value =
|
||||
builder.build_int_s_extend(narrow_value, intrinsics.i64_ty, &state.var_name());
|
||||
state.push1(extended_value);
|
||||
}
|
||||
|
||||
/***************************
|
||||
* Load and Store instructions.
|
||||
* https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#load-and-store-instructions
|
||||
@ -1566,15 +1668,15 @@ fn parse_function(
|
||||
&state.var_name(),
|
||||
);
|
||||
state.push1(result.try_as_basic_value().left().unwrap());
|
||||
}
|
||||
|
||||
op @ _ => {
|
||||
println!("{}", module.print_to_string().to_string());
|
||||
unimplemented!("{:?}", op);
|
||||
}
|
||||
} // op @ _ => {
|
||||
// println!("{}", module.print_to_string().to_string());
|
||||
// unimplemented!("{:?}", op);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
println!("finished translating");
|
||||
|
||||
let pass_manager = PassManager::create_for_module();
|
||||
pass_manager.add_promote_memory_to_register_pass();
|
||||
pass_manager.add_cfg_simplification_pass();
|
||||
@ -1585,6 +1687,7 @@ fn parse_function(
|
||||
pass_manager.add_gvn_pass();
|
||||
pass_manager.add_new_gvn_pass();
|
||||
pass_manager.add_aggressive_dce_pass();
|
||||
pass_manager.add_verifier_pass();
|
||||
pass_manager.run_on_module(module);
|
||||
|
||||
println!("{}", module.print_to_string().to_string());
|
||||
|
@ -12,9 +12,18 @@ use wasmer_runtime_core::{
|
||||
memory::MemoryType,
|
||||
module::ModuleInfo,
|
||||
structures::TypedIndex,
|
||||
types::{LocalOrImport, MemoryIndex},
|
||||
types::{GlobalIndex, ImportedFuncIndex, LocalOrImport, MemoryIndex, TableIndex, Type},
|
||||
};
|
||||
|
||||
fn type_to_llvm_ptr(intrinsics: &Intrinsics, ty: Type) -> PointerType {
|
||||
match ty {
|
||||
Type::I32 => intrinsics.i32_ptr_ty,
|
||||
Type::I64 => intrinsics.i64_ptr_ty,
|
||||
Type::F32 => intrinsics.f32_ptr_ty,
|
||||
Type::F64 => intrinsics.f64_ptr_ty,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Intrinsics {
|
||||
pub ctlz_i32: FunctionValue,
|
||||
pub ctlz_i64: FunctionValue,
|
||||
@ -111,8 +120,6 @@ impl Intrinsics {
|
||||
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);
|
||||
let i64_zero = i64_ty.const_int(0, false);
|
||||
@ -125,19 +132,16 @@ impl Intrinsics {
|
||||
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);
|
||||
context.struct_type(&[i8_ptr_ty_basic, i64_ty_basic, i8_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,
|
||||
);
|
||||
let imported_func_ty =
|
||||
context.struct_type(&[i8_ptr_ty_basic, ctx_ptr_ty.as_basic_type_enum()], false);
|
||||
ctx_ty.set_body(
|
||||
&[
|
||||
local_memory_ty
|
||||
@ -184,9 +188,12 @@ 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_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);
|
||||
let ret_i32_take_ctx_i32_i32 = i32_ty.fn_type(
|
||||
&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic],
|
||||
false,
|
||||
);
|
||||
let ret_i32_take_ctx_i32 =
|
||||
i32_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false);
|
||||
|
||||
Self {
|
||||
ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None),
|
||||
@ -250,63 +257,63 @@ impl Intrinsics {
|
||||
// VM intrinsics.
|
||||
memory_grow_dynamic_local: module.add_function(
|
||||
"vm.memory.grow.dynamic.local",
|
||||
ret_i32_take_i64_i32_i32,
|
||||
ret_i32_take_ctx_i32_i32,
|
||||
None,
|
||||
),
|
||||
memory_grow_static_local: module.add_function(
|
||||
"vm.memory.grow.static.local",
|
||||
ret_i32_take_i64_i32_i32,
|
||||
ret_i32_take_ctx_i32_i32,
|
||||
None,
|
||||
),
|
||||
memory_grow_shared_local: module.add_function(
|
||||
"vm.memory.grow.shared.local",
|
||||
ret_i32_take_i64_i32_i32,
|
||||
ret_i32_take_ctx_i32_i32,
|
||||
None,
|
||||
),
|
||||
memory_grow_dynamic_import: module.add_function(
|
||||
"vm.memory.grow.dynamic.import",
|
||||
ret_i32_take_i64_i32_i32,
|
||||
ret_i32_take_ctx_i32_i32,
|
||||
None,
|
||||
),
|
||||
memory_grow_static_import: module.add_function(
|
||||
"vm.memory.grow.static.import",
|
||||
ret_i32_take_i64_i32_i32,
|
||||
ret_i32_take_ctx_i32_i32,
|
||||
None,
|
||||
),
|
||||
memory_grow_shared_import: module.add_function(
|
||||
"vm.memory.grow.shared.import",
|
||||
ret_i32_take_i64_i32_i32,
|
||||
ret_i32_take_ctx_i32_i32,
|
||||
None,
|
||||
),
|
||||
|
||||
memory_size_dynamic_local: module.add_function(
|
||||
"vm.memory.size.dynamic.local",
|
||||
ret_i32_take_i64_i32,
|
||||
ret_i32_take_ctx_i32,
|
||||
None,
|
||||
),
|
||||
memory_size_static_local: module.add_function(
|
||||
"vm.memory.size.static.local",
|
||||
ret_i32_take_i64_i32,
|
||||
ret_i32_take_ctx_i32,
|
||||
None,
|
||||
),
|
||||
memory_size_shared_local: module.add_function(
|
||||
"vm.memory.size.shared.local",
|
||||
ret_i32_take_i64_i32,
|
||||
ret_i32_take_ctx_i32,
|
||||
None,
|
||||
),
|
||||
memory_size_dynamic_import: module.add_function(
|
||||
"vm.memory.size.dynamic.import",
|
||||
ret_i32_take_i64_i32,
|
||||
ret_i32_take_ctx_i32,
|
||||
None,
|
||||
),
|
||||
memory_size_static_import: module.add_function(
|
||||
"vm.memory.size.static.import",
|
||||
ret_i32_take_i64_i32,
|
||||
ret_i32_take_ctx_i32,
|
||||
None,
|
||||
),
|
||||
memory_size_shared_import: module.add_function(
|
||||
"vm.memory.size.shared.import",
|
||||
ret_i32_take_i64_i32,
|
||||
ret_i32_take_ctx_i32,
|
||||
None,
|
||||
),
|
||||
|
||||
@ -332,6 +339,9 @@ impl Intrinsics {
|
||||
info,
|
||||
|
||||
cached_memories: HashMap::new(),
|
||||
cached_tables: HashMap::new(),
|
||||
cached_globals: HashMap::new(),
|
||||
cached_imported_functions: HashMap::new(),
|
||||
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
@ -351,6 +361,22 @@ enum MemoryCache {
|
||||
},
|
||||
}
|
||||
|
||||
struct TableCache {
|
||||
ptr_to_base_ptr: PointerValue,
|
||||
ptr_to_bounds: PointerValue,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum GlobalCache {
|
||||
Mut { ptr_to_value: PointerValue },
|
||||
Const { value: IntValue },
|
||||
}
|
||||
|
||||
struct ImportedFuncCache {
|
||||
func_ptr: PointerValue,
|
||||
ctx_ptr: PointerValue,
|
||||
}
|
||||
|
||||
pub struct CtxType<'a> {
|
||||
ctx_ty: StructType,
|
||||
ctx_ptr_ty: PointerType,
|
||||
@ -362,6 +388,9 @@ pub struct CtxType<'a> {
|
||||
info: &'a ModuleInfo,
|
||||
|
||||
cached_memories: HashMap<MemoryIndex, MemoryCache>,
|
||||
cached_tables: HashMap<TableIndex, TableCache>,
|
||||
cached_globals: HashMap<GlobalIndex, GlobalCache>,
|
||||
cached_imported_functions: HashMap<ImportedFuncIndex, ImportedFuncCache>,
|
||||
|
||||
_phantom: PhantomData<&'a FunctionValue>,
|
||||
}
|
||||
@ -443,6 +472,119 @@ impl<'a> CtxType<'a> {
|
||||
MemoryCache::Static { base_ptr, bounds } => (*base_ptr, *bounds),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn global_cache(&mut self, index: GlobalIndex) -> GlobalCache {
|
||||
let (cached_globals, builder, ctx_ptr_value, info, intrinsics) = (
|
||||
&mut self.cached_globals,
|
||||
self.builder,
|
||||
self.ctx_ptr_value,
|
||||
self.info,
|
||||
self.intrinsics,
|
||||
);
|
||||
|
||||
*cached_globals.entry(index).or_insert_with(|| {
|
||||
let (globals_array_ptr_ptr, index, mutable, wasmer_ty) =
|
||||
match index.local_or_import(info) {
|
||||
LocalOrImport::Local(local_global_index) => {
|
||||
let desc = info.globals[local_global_index].desc;
|
||||
(
|
||||
unsafe {
|
||||
builder.build_struct_gep(ctx_ptr_value, 2, "globals_array_ptr_ptr")
|
||||
},
|
||||
local_global_index.index() as u64,
|
||||
desc.mutable,
|
||||
desc.ty,
|
||||
)
|
||||
}
|
||||
LocalOrImport::Import(import_global_index) => {
|
||||
let desc = info.imported_globals[import_global_index].1;
|
||||
(
|
||||
unsafe {
|
||||
builder.build_struct_gep(ctx_ptr_value, 5, "globals_array_ptr_ptr")
|
||||
},
|
||||
import_global_index.index() as u64,
|
||||
desc.mutable,
|
||||
desc.ty,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let llvm_ptr_ty = type_to_llvm_ptr(intrinsics, wasmer_ty);
|
||||
|
||||
let global_array_ptr = builder
|
||||
.build_load(globals_array_ptr_ptr, "global_array_ptr")
|
||||
.into_pointer_value();
|
||||
let const_index = intrinsics.i32_ty.const_int(index, false);
|
||||
let global_ptr_ptr = unsafe {
|
||||
builder.build_in_bounds_gep(global_array_ptr, &[const_index], "global_ptr_ptr")
|
||||
};
|
||||
let global_ptr = builder
|
||||
.build_load(global_ptr_ptr, "global_ptr")
|
||||
.into_pointer_value();
|
||||
|
||||
let global_ptr_typed = {
|
||||
let int = builder.build_ptr_to_int(global_ptr, intrinsics.i64_ty, "global_ptr_int");
|
||||
builder.build_int_to_ptr(int, llvm_ptr_ty, "global_ptr_typed")
|
||||
};
|
||||
println!("global_ptr: {:?}", global_ptr_typed);
|
||||
|
||||
if mutable {
|
||||
GlobalCache::Mut {
|
||||
ptr_to_value: global_ptr_typed,
|
||||
}
|
||||
} else {
|
||||
GlobalCache::Const {
|
||||
value: builder
|
||||
.build_load(global_ptr_typed, "global_value")
|
||||
.into_int_value(),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn imported_func(&mut self, index: ImportedFuncIndex) -> (PointerValue, PointerValue) {
|
||||
let (cached_imported_functions, builder, ctx_ptr_value, intrinsics) = (
|
||||
&mut self.cached_imported_functions,
|
||||
self.builder,
|
||||
self.ctx_ptr_value,
|
||||
self.intrinsics,
|
||||
);
|
||||
|
||||
let imported_func_cache = cached_imported_functions.entry(index).or_insert_with(|| {
|
||||
let func_array_ptr_ptr = unsafe {
|
||||
builder.build_struct_gep(ctx_ptr_value, 6, "imported_func_array_ptr_ptr")
|
||||
};
|
||||
let func_array_ptr = builder
|
||||
.build_load(func_array_ptr_ptr, "func_array_ptr")
|
||||
.into_pointer_value();
|
||||
let const_index = intrinsics.i32_ty.const_int(index.index() as u64, false);
|
||||
let imported_func_ptr_ptr = unsafe {
|
||||
builder.build_in_bounds_gep(func_array_ptr, &[const_index], "imported_func_ptr_ptr")
|
||||
};
|
||||
let imported_func_ptr = builder
|
||||
.build_load(imported_func_ptr_ptr, "imported_func_ptr")
|
||||
.into_pointer_value();
|
||||
let (func_ptr_ptr, ctx_ptr_ptr) = unsafe {
|
||||
(
|
||||
builder.build_struct_gep(imported_func_ptr, 0, "func_ptr_ptr"),
|
||||
builder.build_struct_gep(imported_func_ptr, 1, "ctx_ptr_ptr"),
|
||||
)
|
||||
};
|
||||
|
||||
let func_ptr = builder
|
||||
.build_load(func_ptr_ptr, "func_ptr")
|
||||
.into_pointer_value();
|
||||
let ctx_ptr = builder
|
||||
.build_load(ctx_ptr_ptr, "ctx_ptr")
|
||||
.into_pointer_value();
|
||||
|
||||
ImportedFuncCache { func_ptr, ctx_ptr }
|
||||
});
|
||||
|
||||
(imported_func_cache.func_ptr, imported_func_cache.ctx_ptr)
|
||||
}
|
||||
|
||||
// pub fn table(&mut self, table_index: TableIndex, elem_index: IntValue) ->
|
||||
}
|
||||
|
||||
// pub struct Ctx {
|
||||
|
@ -30,20 +30,17 @@ impl Compiler for LLVMCompiler {
|
||||
#[test]
|
||||
fn test_read_module() {
|
||||
use wabt::wat2wasm;
|
||||
// let wasm = include_bytes!("../../spectests/examples/simple/simple.wasm") as &[u8];
|
||||
let wat = r#"
|
||||
(module
|
||||
(type $t0 (func (param i32) (result i32)))
|
||||
(type $t1 (func (result i32)))
|
||||
(memory 1)
|
||||
(global $g0 (mut i32) (i32.const 0))
|
||||
(func $foo (type $t0) (param i32) (result i32)
|
||||
get_local 0
|
||||
i32.load offset=16
|
||||
i32.const 1
|
||||
memory.grow
|
||||
drop
|
||||
i32.const 0
|
||||
i32.load offset=4
|
||||
i32.add
|
||||
set_global $g0
|
||||
get_global $g0
|
||||
))
|
||||
"#;
|
||||
let wasm = wat2wasm(wat).unwrap();
|
||||
|
Loading…
Reference in New Issue
Block a user