repl: Change lots of pointers to addresses

This commit is contained in:
Brian Carroll 2022-01-27 09:40:18 +00:00
parent c27f2a2592
commit 4a08fead1a
3 changed files with 158 additions and 105 deletions

View file

@ -1,9 +1,9 @@
use crate::repl::from_memory::FromMemory;
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use libloading::Library; use libloading::Library;
use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_collections::all::MutMap; use roc_collections::all::MutMap;
use roc_gen_llvm::llvm::build::tag_pointer_tag_id_bits_and_mask;
use roc_gen_llvm::{run_jit_function, run_jit_function_dynamic_type}; use roc_gen_llvm::{run_jit_function, run_jit_function_dynamic_type};
use roc_module::called_via::CalledVia; use roc_module::called_via::CalledVia;
use roc_module::ident::TagName; use roc_module::ident::TagName;
@ -182,7 +182,7 @@ fn get_tags_vars_and_variant<'a, M>(
fn expr_of_tag<'a, M>( fn expr_of_tag<'a, M>(
env: &Env<'a, 'a, M>, env: &Env<'a, 'a, M>,
ptr_to_data: *const u8, data_addr: usize,
tag_name: &TagName, tag_name: &TagName,
arg_layouts: &'a [Layout<'a>], arg_layouts: &'a [Layout<'a>],
arg_vars: &[Variable], arg_vars: &[Variable],
@ -195,7 +195,7 @@ fn expr_of_tag<'a, M>(
// NOTE assumes the data bytes are the first bytes // NOTE assumes the data bytes are the first bytes
let it = arg_vars.iter().copied().zip(arg_layouts.iter()); let it = arg_vars.iter().copied().zip(arg_layouts.iter());
let output = sequence_of_expr(env, ptr_to_data, it, when_recursive); let output = sequence_of_expr(env, data_addr, it, when_recursive);
let output = output.into_bump_slice(); let output = output.into_bump_slice();
Expr::Apply(loc_tag_expr, output, CalledVia::Space) Expr::Apply(loc_tag_expr, output, CalledVia::Space)
@ -203,57 +203,56 @@ fn expr_of_tag<'a, M>(
/// Gets the tag ID of a union variant, assuming that the tag ID is stored alongside (after) the /// Gets the tag ID of a union variant, assuming that the tag ID is stored alongside (after) the
/// tag data. The caller is expected to check that the tag ID is indeed stored this way. /// tag data. The caller is expected to check that the tag ID is indeed stored this way.
fn tag_id_from_data(union_layout: UnionLayout, data_ptr: *const u8, ptr_bytes: u32) -> i64 { fn tag_id_from_data<'a, M>(
let offset = union_layout.data_size_without_tag_id(ptr_bytes).unwrap(); env: &Env<'a, 'a, M>,
union_layout: UnionLayout,
data_addr: usize,
) -> i64 {
let offset = union_layout
.data_size_without_tag_id(env.ptr_bytes)
.unwrap();
unsafe { let tag_id_addr = data_addr + offset as usize;
match union_layout.tag_id_builtin() {
Builtin::Bool => *(data_ptr.add(offset as usize) as *const i8) as i64, match union_layout.tag_id_builtin() {
Builtin::Int(IntWidth::U8) => *(data_ptr.add(offset as usize) as *const i8) as i64, Builtin::Bool => u8::from_memory(&env.app_memory, tag_id_addr) as i64,
Builtin::Int(IntWidth::U16) => *(data_ptr.add(offset as usize) as *const i16) as i64, Builtin::Int(IntWidth::U8) => u8::from_memory(&env.app_memory, tag_id_addr) as i64,
Builtin::Int(IntWidth::U64) => { Builtin::Int(IntWidth::U16) => u16::from_memory(&env.app_memory, tag_id_addr) as i64,
// used by non-recursive unions at the Builtin::Int(IntWidth::U64) => {
// moment, remove if that is no longer the case // used by non-recursive unions at the
*(data_ptr.add(offset as usize) as *const i64) as i64 // moment, remove if that is no longer the case
} i64::from_memory(&env.app_memory, tag_id_addr)
_ => unreachable!("invalid tag id layout"),
} }
_ => unreachable!("invalid tag id layout"),
} }
} }
fn deref_ptr_of_ptr(ptr_of_ptr: *const u8, ptr_bytes: u32) -> *const u8 { fn deref_addr_of_addr<'a, M>(env: &Env<'a, 'a, M>, addr_of_addr: usize) -> usize {
unsafe { usize::from_memory(&env.app_memory, addr_of_addr)
match ptr_bytes {
// Our LLVM codegen represents pointers as i32/i64s.
4 => *(ptr_of_ptr as *const i32) as *const u8,
8 => *(ptr_of_ptr as *const i64) as *const u8,
_ => unreachable!(),
}
}
} }
/// Gets the tag ID of a union variant from its recursive pointer (that is, the pointer to the /// Gets the tag ID of a union variant from its recursive pointer (that is, the pointer to the
/// pointer to the data of the union variant). Returns /// pointer to the data of the union variant). Returns
/// - the tag ID /// - the tag ID
/// - the pointer to the data of the union variant, unmasked if the pointer held the tag ID /// - the pointer to the data of the union variant, unmasked if the pointer held the tag ID
fn tag_id_from_recursive_ptr( fn tag_id_from_recursive_ptr<'a, M>(
env: &Env<'a, 'a, M>,
union_layout: UnionLayout, union_layout: UnionLayout,
rec_ptr: *const u8, rec_addr: usize,
ptr_bytes: u32, ) -> (i64, usize) {
) -> (i64, *const u8) { let tag_in_ptr = union_layout.stores_tag_id_in_pointer(env.ptr_bytes);
let tag_in_ptr = union_layout.stores_tag_id_in_pointer(ptr_bytes);
if tag_in_ptr { if tag_in_ptr {
let masked_ptr_to_data = deref_ptr_of_ptr(rec_ptr, ptr_bytes) as i64; let masked_data_addr = deref_addr_of_addr(env, rec_addr);
let (tag_id_bits, tag_id_mask) = tag_pointer_tag_id_bits_and_mask(ptr_bytes); let (tag_id_bits, tag_id_mask) = UnionLayout::tag_id_pointer_bits_and_mask(env.ptr_bytes);
let tag_id = masked_ptr_to_data & (tag_id_mask as i64); let tag_id = masked_data_addr & tag_id_mask;
// Clear the tag ID data from the pointer // Clear the tag ID data from the pointer
let ptr_to_data = ((masked_ptr_to_data >> tag_id_bits) << tag_id_bits) as *const u8; let data_addr = (masked_data_addr >> tag_id_bits) << tag_id_bits;
(tag_id as i64, ptr_to_data) (tag_id as i64, data_addr)
} else { } else {
let ptr_to_data = deref_ptr_of_ptr(rec_ptr, ptr_bytes); let data_addr = deref_addr_of_addr(env, rec_addr);
let tag_id = tag_id_from_data(union_layout, ptr_to_data, ptr_bytes); let tag_id = tag_id_from_data(env, union_layout, data_addr);
(tag_id, ptr_to_data) (tag_id, data_addr)
} }
} }
@ -335,8 +334,8 @@ fn jit_to_ast_help<'a, M>(
Layout::Builtin(Builtin::List(elem_layout)) => Ok(run_jit_function!( Layout::Builtin(Builtin::List(elem_layout)) => Ok(run_jit_function!(
lib, lib,
main_fn_name, main_fn_name,
(*const u8, usize), (usize, usize),
|(ptr, len): (*const u8, usize)| { list_to_ast(env, ptr, len, elem_layout, content) } |(addr, len): (usize, usize)| { list_to_ast(env, addr, len, elem_layout, content) }
)), )),
Layout::Builtin(other) => { Layout::Builtin(other) => {
todo!("add support for rendering builtin {:?} to the REPL", other) todo!("add support for rendering builtin {:?} to the REPL", other)
@ -407,7 +406,7 @@ fn jit_to_ast_help<'a, M>(
main_fn_name, main_fn_name,
size as usize, size as usize,
|ptr: *const u8| { |ptr: *const u8| {
ptr_to_ast(env, ptr, layout, WhenRecursive::Unreachable, content) addr_to_ast(env, ptr, layout, WhenRecursive::Unreachable, content)
} }
)) ))
} }
@ -421,7 +420,7 @@ fn jit_to_ast_help<'a, M>(
main_fn_name, main_fn_name,
size as usize, size as usize,
|ptr: *const u8| { |ptr: *const u8| {
ptr_to_ast(env, ptr, layout, WhenRecursive::Loop(*layout), content) addr_to_ast(env, ptr, layout, WhenRecursive::Loop(*layout), content)
} }
)) ))
} }
@ -455,16 +454,16 @@ enum WhenRecursive<'a> {
Loop(Layout<'a>), Loop(Layout<'a>),
} }
fn ptr_to_ast<'a, M>( fn addr_to_ast<'a, M>(
env: &Env<'a, 'a, M>, env: &Env<'a, 'a, M>,
ptr: *const u8, addr: usize,
layout: &Layout<'a>, layout: &Layout<'a>,
when_recursive: WhenRecursive<'a>, when_recursive: WhenRecursive<'a>,
content: &'a Content, content: &'a Content,
) -> Expr<'a> { ) -> Expr<'a> {
macro_rules! helper { macro_rules! helper {
($ty:ty) => {{ ($ty:ty) => {{
let num = unsafe { *(ptr as *const $ty) }; let num = <$ty>::from_memory(&env.app_memory, addr);
num_to_ast(env, number_literal_to_ast(env.arena, num), content) num_to_ast(env, number_literal_to_ast(env.arena, num), content)
}}; }};
@ -478,7 +477,7 @@ fn ptr_to_ast<'a, M>(
(_, Layout::Builtin(Builtin::Bool)) => { (_, Layout::Builtin(Builtin::Bool)) => {
// TODO: bits are not as expected here. // TODO: bits are not as expected here.
// num is always false at the moment. // num is always false at the moment.
let num = unsafe { *(ptr as *const bool) }; let num = bool::from_memory(&env.app_memory, addr);
bool_to_ast(env, num, content) bool_to_ast(env, num, content)
} }
@ -508,33 +507,32 @@ fn ptr_to_ast<'a, M>(
} }
} }
(_, Layout::Builtin(Builtin::List(elem_layout))) => { (_, Layout::Builtin(Builtin::List(elem_layout))) => {
// Turn the (ptr, len) wrapper struct into actual ptr and len values. let elem_addr = usize::from_memory(&env.app_memory, addr);
let len = unsafe { *(ptr.offset(env.ptr_bytes as isize) as *const usize) }; let len = usize::from_memory(&env.app_memory, addr + env.ptr_bytes as usize);
let ptr = unsafe { *(ptr as *const *const u8) };
list_to_ast(env, ptr, len, elem_layout, content) list_to_ast(env, elem_addr, len, elem_layout, content)
} }
(_, Layout::Builtin(Builtin::Str)) => { (_, Layout::Builtin(Builtin::Str)) => {
let arena_str = unsafe { *(ptr as *const &'static str) }; let arena_str = <&'a str>::from_memory(&env.app_memory, addr);
str_to_ast(env.arena, arena_str) str_to_ast(env.arena, arena_str)
} }
(_, Layout::Struct(field_layouts)) => match content { (_, Layout::Struct(field_layouts)) => match content {
Content::Structure(FlatType::Record(fields, _)) => { Content::Structure(FlatType::Record(fields, _)) => {
struct_to_ast(env, ptr, field_layouts, *fields) struct_to_ast(env, addr, field_layouts, *fields)
} }
Content::Structure(FlatType::TagUnion(tags, _)) => { Content::Structure(FlatType::TagUnion(tags, _)) => {
debug_assert_eq!(tags.len(), 1); debug_assert_eq!(tags.len(), 1);
let (tag_name, payload_vars) = unpack_single_element_tag_union(env.subs, *tags); let (tag_name, payload_vars) = unpack_single_element_tag_union(env.subs, *tags);
single_tag_union_to_ast(env, ptr, field_layouts, tag_name, payload_vars) single_tag_union_to_ast(env, addr, field_layouts, tag_name, payload_vars)
} }
Content::Structure(FlatType::FunctionOrTagUnion(tag_name, _, _)) => { Content::Structure(FlatType::FunctionOrTagUnion(tag_name, _, _)) => {
let tag_name = &env.subs[*tag_name]; let tag_name = &env.subs[*tag_name];
single_tag_union_to_ast(env, ptr, field_layouts, tag_name, &[]) single_tag_union_to_ast(env, addr, field_layouts, tag_name, &[])
} }
Content::Structure(FlatType::EmptyRecord) => { Content::Structure(FlatType::EmptyRecord) => {
struct_to_ast(env, ptr, &[], RecordFields::empty()) struct_to_ast(env, addr, &[], RecordFields::empty())
} }
other => { other => {
unreachable!( unreachable!(
@ -550,7 +548,7 @@ fn ptr_to_ast<'a, M>(
opt_name: _, opt_name: _,
}, WhenRecursive::Loop(union_layout)) => { }, WhenRecursive::Loop(union_layout)) => {
let content = env.subs.get_content_without_compacting(*structure); let content = env.subs.get_content_without_compacting(*structure);
ptr_to_ast(env, ptr, &union_layout, when_recursive, content) addr_to_ast(env, addr, &union_layout, when_recursive, content)
} }
other => unreachable!("Something had a RecursivePointer layout, but instead of being a RecursionVar and having a known recursive layout, I found {:?}", other), other => unreachable!("Something had a RecursivePointer layout, but instead of being a RecursionVar and having a known recursive layout, I found {:?}", other),
} }
@ -575,8 +573,7 @@ fn ptr_to_ast<'a, M>(
}; };
// Because this is a `NonRecursive`, the tag ID is definitely after the data. // Because this is a `NonRecursive`, the tag ID is definitely after the data.
let tag_id = let tag_id = tag_id_from_data(env, union_layout, addr);
tag_id_from_data(union_layout, ptr, env.ptr_bytes);
// use the tag ID as an index, to get its name and layout of any arguments // use the tag ID as an index, to get its name and layout of any arguments
let (tag_name, arg_layouts) = let (tag_name, arg_layouts) =
@ -584,7 +581,7 @@ fn ptr_to_ast<'a, M>(
expr_of_tag( expr_of_tag(
env, env,
ptr, addr,
tag_name, tag_name,
arg_layouts, arg_layouts,
&vars_of_tag[tag_name], &vars_of_tag[tag_name],
@ -608,7 +605,7 @@ fn ptr_to_ast<'a, M>(
_ => unreachable!("any other variant would have a different layout"), _ => unreachable!("any other variant would have a different layout"),
}; };
let (tag_id, ptr_to_data) = tag_id_from_recursive_ptr(*union_layout, ptr, env.ptr_bytes); let (tag_id, ptr_to_data) = tag_id_from_recursive_ptr(env, *union_layout, addr);
let (tag_name, arg_layouts) = &tags_and_layouts[tag_id as usize]; let (tag_name, arg_layouts) = &tags_and_layouts[tag_id as usize];
expr_of_tag( expr_of_tag(
@ -636,7 +633,7 @@ fn ptr_to_ast<'a, M>(
_ => unreachable!("any other variant would have a different layout"), _ => unreachable!("any other variant would have a different layout"),
}; };
let ptr_to_data = deref_ptr_of_ptr(ptr, env.ptr_bytes); let ptr_to_data = deref_addr_of_addr(addr, env.ptr_bytes);
expr_of_tag( expr_of_tag(
env, env,
@ -666,7 +663,7 @@ fn ptr_to_ast<'a, M>(
_ => unreachable!("any other variant would have a different layout"), _ => unreachable!("any other variant would have a different layout"),
}; };
let ptr_to_data = deref_ptr_of_ptr(ptr, env.ptr_bytes); let ptr_to_data = deref_addr_of_addr(addr, env.ptr_bytes);
if ptr_to_data.is_null() { if ptr_to_data.is_null() {
tag_name_to_expr(env, &nullable_name) tag_name_to_expr(env, &nullable_name)
} else { } else {
@ -697,11 +694,11 @@ fn ptr_to_ast<'a, M>(
_ => unreachable!("any other variant would have a different layout"), _ => unreachable!("any other variant would have a different layout"),
}; };
let ptr_to_data = deref_ptr_of_ptr(ptr, env.ptr_bytes); let ptr_to_data = deref_addr_of_addr(addr, env.ptr_bytes);
if ptr_to_data.is_null() { if ptr_to_data.is_null() {
tag_name_to_expr(env, &nullable_name) tag_name_to_expr(env, &nullable_name)
} else { } else {
let (tag_id, ptr_to_data) = tag_id_from_recursive_ptr(*union_layout, ptr, env.ptr_bytes); let (tag_id, ptr_to_data) = tag_id_from_recursive_ptr(env, *union_layout, addr);
let tag_id = if tag_id > nullable_id.into() { tag_id - 1 } else { tag_id }; let tag_id = if tag_id > nullable_id.into() { tag_id - 1 } else { tag_id };
@ -728,7 +725,7 @@ fn ptr_to_ast<'a, M>(
fn list_to_ast<'a, M>( fn list_to_ast<'a, M>(
env: &Env<'a, 'a, M>, env: &Env<'a, 'a, M>,
ptr: *const u8, addr: usize,
len: usize, len: usize,
elem_layout: &Layout<'a>, elem_layout: &Layout<'a>,
content: &Content, content: &Content,
@ -756,11 +753,11 @@ fn list_to_ast<'a, M>(
for index in 0..len { for index in 0..len {
let offset_bytes = index * elem_size; let offset_bytes = index * elem_size;
let elem_ptr = unsafe { ptr.add(offset_bytes) }; let elem_addr = addr + offset_bytes;
let (newtype_containers, elem_content) = unroll_newtypes(env, elem_content); let (newtype_containers, elem_content) = unroll_newtypes(env, elem_content);
let expr = ptr_to_ast( let expr = addr_to_ast(
env, env,
elem_ptr, elem_addr,
elem_layout, elem_layout,
WhenRecursive::Unreachable, WhenRecursive::Unreachable,
elem_content, elem_content,
@ -777,7 +774,7 @@ fn list_to_ast<'a, M>(
fn single_tag_union_to_ast<'a, M>( fn single_tag_union_to_ast<'a, M>(
env: &Env<'a, 'a, M>, env: &Env<'a, 'a, M>,
ptr: *const u8, addr: usize,
field_layouts: &'a [Layout<'a>], field_layouts: &'a [Layout<'a>],
tag_name: &TagName, tag_name: &TagName,
payload_vars: &[Variable], payload_vars: &[Variable],
@ -789,11 +786,11 @@ fn single_tag_union_to_ast<'a, M>(
let output = if field_layouts.len() == payload_vars.len() { let output = if field_layouts.len() == payload_vars.len() {
let it = payload_vars.iter().copied().zip(field_layouts); let it = payload_vars.iter().copied().zip(field_layouts);
sequence_of_expr(env, ptr, it, WhenRecursive::Unreachable).into_bump_slice() sequence_of_expr(env, addr, it, WhenRecursive::Unreachable).into_bump_slice()
} else if field_layouts.is_empty() && !payload_vars.is_empty() { } else if field_layouts.is_empty() && !payload_vars.is_empty() {
// happens for e.g. `Foo Bar` where unit structures are nested and the inner one is dropped // happens for e.g. `Foo Bar` where unit structures are nested and the inner one is dropped
let it = payload_vars.iter().copied().zip([&Layout::Struct(&[])]); let it = payload_vars.iter().copied().zip([&Layout::Struct(&[])]);
sequence_of_expr(env, ptr, it, WhenRecursive::Unreachable).into_bump_slice() sequence_of_expr(env, addr, it, WhenRecursive::Unreachable).into_bump_slice()
} else { } else {
unreachable!() unreachable!()
}; };
@ -803,7 +800,7 @@ fn single_tag_union_to_ast<'a, M>(
fn sequence_of_expr<'a, I, M>( fn sequence_of_expr<'a, I, M>(
env: &Env<'a, 'a, M>, env: &Env<'a, 'a, M>,
ptr: *const u8, addr: usize,
sequence: I, sequence: I,
when_recursive: WhenRecursive<'a>, when_recursive: WhenRecursive<'a>,
) -> Vec<'a, &'a Loc<Expr<'a>>> ) -> Vec<'a, &'a Loc<Expr<'a>>>
@ -816,17 +813,17 @@ where
let mut output = Vec::with_capacity_in(sequence.len(), arena); let mut output = Vec::with_capacity_in(sequence.len(), arena);
// We'll advance this as we iterate through the fields // We'll advance this as we iterate through the fields
let mut field_ptr = ptr; let mut field_addr = addr;
for (var, layout) in sequence { for (var, layout) in sequence {
let content = subs.get_content_without_compacting(var); let content = subs.get_content_without_compacting(var);
let expr = ptr_to_ast(env, field_ptr, layout, when_recursive, content); let expr = addr_to_ast(env, field_addr, layout, when_recursive, content);
let loc_expr = Loc::at_zero(expr); let loc_expr = Loc::at_zero(expr);
output.push(&*arena.alloc(loc_expr)); output.push(&*arena.alloc(loc_expr));
// Advance the field pointer to the next field. // Advance the field pointer to the next field.
field_ptr = unsafe { field_ptr.offset(layout.stack_size(env.ptr_bytes) as isize) }; field_addr += layout.stack_size(env.ptr_bytes) as usize;
} }
output output
@ -834,7 +831,7 @@ where
fn struct_to_ast<'a, M>( fn struct_to_ast<'a, M>(
env: &Env<'a, 'a, M>, env: &Env<'a, 'a, M>,
ptr: *const u8, addr: usize,
field_layouts: &'a [Layout<'a>], field_layouts: &'a [Layout<'a>],
record_fields: RecordFields, record_fields: RecordFields,
) -> Expr<'a> { ) -> Expr<'a> {
@ -854,9 +851,9 @@ fn struct_to_ast<'a, M>(
let inner_content = env.subs.get_content_without_compacting(field.into_inner()); let inner_content = env.subs.get_content_without_compacting(field.into_inner());
let loc_expr = &*arena.alloc(Loc { let loc_expr = &*arena.alloc(Loc {
value: ptr_to_ast( value: addr_to_ast(
env, env,
ptr, addr,
&Layout::Struct(field_layouts), &Layout::Struct(field_layouts),
WhenRecursive::Unreachable, WhenRecursive::Unreachable,
inner_content, inner_content,
@ -880,7 +877,7 @@ fn struct_to_ast<'a, M>(
debug_assert_eq!(sorted_fields.len(), field_layouts.len()); debug_assert_eq!(sorted_fields.len(), field_layouts.len());
// We'll advance this as we iterate through the fields // We'll advance this as we iterate through the fields
let mut field_ptr = ptr; let mut field_addr = addr;
for ((label, field), field_layout) in sorted_fields.into_iter().zip(field_layouts.iter()) { for ((label, field), field_layout) in sorted_fields.into_iter().zip(field_layouts.iter()) {
let var = field.into_inner(); let var = field.into_inner();
@ -888,9 +885,9 @@ fn struct_to_ast<'a, M>(
let content = subs.get_content_without_compacting(var); let content = subs.get_content_without_compacting(var);
let loc_expr = &*arena.alloc(Loc { let loc_expr = &*arena.alloc(Loc {
value: ptr_to_ast( value: addr_to_ast(
env, env,
field_ptr, field_addr,
field_layout, field_layout,
WhenRecursive::Unreachable, WhenRecursive::Unreachable,
content, content,
@ -910,8 +907,7 @@ fn struct_to_ast<'a, M>(
output.push(loc_field); output.push(loc_field);
// Advance the field pointer to the next field. // Advance the field pointer to the next field.
field_ptr = field_addr += field_layout.stack_size(env.ptr_bytes) as usize;
unsafe { field_ptr.offset(field_layout.stack_size(env.ptr_bytes) as isize) };
} }
let output = output.into_bump_slice(); let output = output.into_bump_slice();

View file

@ -1,29 +1,33 @@
use std::mem::size_of; use std::mem::size_of;
pub trait FromMemory<M> { pub trait FromMemory<M: AppMemory> {
fn from_memory(memory: M, address: usize) -> Self; fn from_memory(memory: &M, address: usize) -> Self;
} }
pub trait AppMemory {}
impl AppMemory for AppMemoryInternal {}
impl<'a> AppMemory for AppMemoryExternal<'a> {}
/// A block of app memory in the same address space as the compiler /// A block of app memory in the same address space as the compiler
pub struct AppMemoryInternal; pub struct AppMemoryInternal;
/// A block of app memory in a separate address space from the compiler /// A block of app memory in a separate address space from the compiler
/// (e.g. compiler and app are in separate Wasm modules) /// (e.g. compiler and app are in separate Wasm modules)
pub struct AppMemoryExternal { pub struct AppMemoryExternal<'a> {
bytes: Vec<u8>, bytes: &'a [u8],
} }
macro_rules! impl_primitive { macro_rules! impl_number_type {
($t: ty) => { ($t: ty) => {
impl FromMemory<AppMemoryInternal> for $t { impl FromMemory<AppMemoryInternal> for $t {
fn from_memory(_: AppMemoryInternal, address: usize) -> Self { fn from_memory(_: &AppMemoryInternal, address: usize) -> Self {
let ptr = address as *const _; let ptr = address as *const _;
unsafe { *ptr } unsafe { *ptr }
} }
} }
impl FromMemory<AppMemoryExternal> for $t { impl FromMemory<AppMemoryExternal<'_>> for $t {
fn from_memory(memory: AppMemoryExternal, address: usize) -> Self { fn from_memory(memory: &AppMemoryExternal, address: usize) -> Self {
const N: usize = size_of::<$t>(); const N: usize = size_of::<$t>();
let mut array = [0; N]; let mut array = [0; N];
array.copy_from_slice(&memory.bytes[address..][..N]); array.copy_from_slice(&memory.bytes[address..][..N]);
@ -33,19 +37,64 @@ macro_rules! impl_primitive {
}; };
} }
impl_primitive!(u8); impl FromMemory<AppMemoryInternal> for u8 {
impl_primitive!(u16); fn from_memory(_: &AppMemoryInternal, address: usize) -> Self {
impl_primitive!(u32); let ptr = address as *const _;
impl_primitive!(u64); unsafe { *ptr }
impl_primitive!(u128); }
impl_primitive!(usize); }
impl_primitive!(i8); impl FromMemory<AppMemoryExternal<'_>> for u8 {
impl_primitive!(i16); fn from_memory(memory: &AppMemoryExternal, address: usize) -> Self {
impl_primitive!(i32); const N: usize = size_of::<u8>();
impl_primitive!(i64); let mut array = [0; N];
impl_primitive!(i128); array.copy_from_slice(&memory.bytes[address..][..N]);
impl_primitive!(isize); Self::from_le_bytes(array)
}
}
impl_primitive!(f32); // impl_number_type!(u8);
impl_primitive!(f64); impl_number_type!(u16);
impl_number_type!(u32);
impl_number_type!(u64);
impl_number_type!(u128);
impl_number_type!(usize);
impl_number_type!(i8);
impl_number_type!(i16);
impl_number_type!(i32);
impl_number_type!(i64);
impl_number_type!(i128);
impl_number_type!(isize);
impl_number_type!(f32);
impl_number_type!(f64);
impl FromMemory<AppMemoryInternal> for bool {
fn from_memory(_: &AppMemoryInternal, address: usize) -> Self {
let ptr = address as *const _;
unsafe { *ptr }
}
}
impl FromMemory<AppMemoryExternal<'_>> for bool {
fn from_memory(memory: &AppMemoryExternal, address: usize) -> Self {
memory.bytes[address] != 0
}
}
impl FromMemory<AppMemoryInternal> for &str {
fn from_memory(_: &AppMemoryInternal, address: usize) -> Self {
let ptr = address as *const _;
unsafe { *ptr }
}
}
impl<'a> FromMemory<AppMemoryExternal<'a>> for &'a str {
fn from_memory(memory: &AppMemoryExternal<'a>, address: usize) -> Self {
let len = usize::from_memory(memory, address + std::mem::size_of::<usize>());
let content_addr = usize::from_memory(memory, address);
let content_bytes: &'a [u8] = &memory.bytes[content_addr..][..len];
std::str::from_utf8(content_bytes).unwrap()
}
}

View file

@ -364,6 +364,14 @@ impl<'a> UnionLayout<'a> {
tags.len() < ptr_bytes as usize tags.len() < ptr_bytes as usize
} }
pub fn tag_id_pointer_bits_and_mask(ptr_bytes: u32) -> (usize, usize) {
match ptr_bytes {
8 => (3, 0b0000_0111),
4 => (2, 0b0000_0011),
_ => unreachable!(),
}
}
// i.e. it is not implicit and not stored in the pointer bits // i.e. it is not implicit and not stored in the pointer bits
pub fn stores_tag_id_as_data(&self, ptr_bytes: u32) -> bool { pub fn stores_tag_id_as_data(&self, ptr_bytes: u32) -> bool {
match self { match self {