What can WebAssembly return? - io

As I understand it, there are three ways for a WebAssembly instance to return values to the external caller:
returning a value directly as the result of a method call (is this only a single value of the basic datatypes {i32, i64, f32, f64}?)
calling an imported function with arguments, this function can store the arguments or access the memory while it is called and save the contents somewhere else
writing to a memory and have the external environment access it after execution
Are there more? What are the details?

Your assessment is roughly correct. Functions can either return a WebAssembly value (i32, i64, f32, f64) directly or return data indirectly via modifying elements in the global environment such as Memory, Table and Globals. If you are talking about returns data to a caller outside of the WebAssembly module than any such elemennts would themselves need to to be exported from he module. i.e. you can't use the WebAssembly memory to indirectly return data unless he memory itself is also exports.
With the multi-value proposal you will also be able to directly return more than one value: https://github.com/WebAssembly/multi-value. Likewise the GC proposal will allow you to directly return complex structures. But neither of those is available today.

Your list is almost complete- the only other mechanism I can think of is global variables. These can also be exported to allow access by the host environment so could conceivably be used as a mechanism for returning results.
Yes, you are correct in your statement that you can only return a single numeric value from exported functions

Related

Point a pointer to local variable created within a function

Here is the code:
var timePointer *[]time.Time
func UpdateHolidayList() error {
//updating logic: pulling list of holidays from API
holidaySlice := make([]time.Time, 0)
//appending some holidays of type time.Time to holidaySlice
//now holidaySlice contains a few time.Time values
timePointer = &holidaySlice
return nil
}
func main() {
//run UpdateHoliday every 7 days
go func() {
for {
UpdateHoliday()
time.Sleep(7 * 3600 * time.Hour)
}
}()
}
I have 4 questions:
holidaySlice is a local variable, is it safe to point a (global) pointer to it?
Is this whole code multi-thread safe?
After pointing timePointer to holidaySlice, can I access the values via timePointer
(If answer to 3. is "yes") The holiday list is constantly changing, so holidaySlice will be different each update. Will the values accessed via timePointer change accordingly then?
holidaySlice is a local variable allocated on the heap. Any variable pointing to the same heap location can access the data structure at that location. Whether or not it is safe depends on how you access it. Even if holidaySlice was not explicitly allocated on the heap, once you make a global variable point to it, Go compiler would detect that it "escapes", so it would allocate that on the heap.
The code is not thread-safe. You are modifying a shared variable (the global variable) without any explicit synchronization, so there is no guarantee on when or if other goroutines will see the updates to that variable.
If you update the contents of the timePointer array without explicit synchronization, there is no guarantee on when or if other goroutines will see those updates. You have to use synchronization primitives like sync/Mutex to delimit read/write access to data structures that can be updated/read by multiple goroutines.
As long as your main does not end timePointer will have access to the pointer that holidaySlice creates - since its heap allocated, compiler will detect its escape and not free the memory.
Nope, absolutely not. Look at the sync package
Yes you can. Just remember to iterate using *timePointer instead of timePointer
It will change - but not accordingly. Since you have not done any synchronization - you have no defined way of knowing what data is stored at slice pointed to by timePointer when it is read.

Static objects in rust

Often times in embedded setting we need to declare static structs (drivers etc) so that
their memory is known and assigned at compile time.
Is there any way to achieve something similar in rust?
For example, I want to have a uart driver struct
struct DriverUart{
...
}
and an associated impl block.
Now, I want to avoid having a function named new(), and instead, I want to somewhere allocate this memory a-priori (or to have a new function that I can call statically outside
any code block).
In C I would simply put an instantiation of this struct in some header file and it will be statically allocated and globally available.
I haven't found any thing similar in rust.
If it is not possible then why? and what is the best why we can achieve something similar?
Thanks!
Now, I want to avoid having a function named new(), and instead, I want to somewhere allocate this memory a-priori (or to have a new function that I can call statically outside any code block). In C I would simply put an instantiation of this struct in some header file and it will be statically allocated and globally available. I haven't found any thing similar in rust. If it is not possible then why? and what is the best why we can achieve something similar?
https://doc.rust-lang.org/std/keyword.static.html
You can do the same in Rust, without the header, as long as all the elements are const:
struct DriverUart {
whatever: u32
}
static thing: DriverUart = DriverUart { whatever: 5 };
If you need to evaluate non-const expressions, then that obviously will not work and you'll need to use something like lazy_static or once_cell to instantiate simili-statics.
And of course, what with Rust being a safe languages and statics being shared state, mutable statics are wildly unsafe if not mitigated via thread-safe interior-mutability containers (e.g. an atomic, or a Mutex though those are currently non-const, and it's unclear if they can ever be otherwise), a static is considered to always be shared between threads.

How can the memory address of a struct be the same inside a function and after the struct has been returned?

The phrase "when scope exits the values get automatically popped from stack" is repeated many times, but the example I provide here disproves the statement:
fn main() {
let foo = foobar();
println!("The address in main {:p}", &foo);
}
fn foobar() -> Employee {
let emp = Employee {
company: String::from("xyz"),
name: String::from("somename"),
age: 50,
};
println!("The address inside func {:p}", &emp);
emp
}
#[derive(Debug)]
struct Employee {
name: String,
company: String,
age: u32,
}
The output is:
The address inside func 0x7fffc34011e8
The address in main 0x7fffc34011e8
This makes sense. When I use Box to create the struct the address differs as I expected.
If the function returns ownership (move) of the return value to the caller, then after the function execution the memory corresponds to that function gets popped which is not safe, then how is the struct created inside the function accessible even after the function exits?
The same things happens when returning an array. Where are these elements stored in memory, whether in the stack or on the heap?
Will the compiler do escape analysis at compile time and move the values to the heap like Go does?
I'm sure that Employee doesn't implement the Copy trait.
In many languages, variables are just a convenient means for
humans to name some values.
Even if on a logical point of view we can assume that there is one
specific storage for each specific variable, and we can reason about
this in terms of copy, move... it does not imply that these copies
and moves physically happen (and notably because of the optimizer).
Moreover, when reading various documents about Rust, we often find
the term binding instead of variable; this reinforces the idea
that we just refer to a value that exists somewhere.
It is exactly the same as writing let a=something(); then let b=a;,
the again let c=b;... we simply change our mind about the name
but no data is actually moved.
When it comes to debugging, the generated code is generally
sub-optimal by giving each variable its own storage
in order to inspect these variables in memory.
This can be misleading about the true nature of the optimised code.
Back to your example, you detected that Rust decided to perform
a kind of return-value-optimization (common C++ term nowadays)
because it knows that a temporary value must appear in the calling
context to provide the result, and this result comes from a local
variable inside the function.
So, instead of creating two different storages and copying or moving from
one to another, it is better to use the same storage: the local
variable is stored outside the function (where the result is
expected).
On the logical point of view it does not change anything but it
is much more efficient.
And when code inlining comes into play, no one can predict where
our variables/values/bindings are actually stored.
Some comments below state that this return-value-optimisation
can be counted on since it takes place in the Rust ABI.
(I was not aware of that, still a beginner ;^)

Correctly storing a Rust Rc<T> in C-managed memory

I'm wrapping a Rust object to be used from Lua. I need the object to be destroyed when neither Rust code nor Lua still has a reference to it, so the obvious (to me) solution is to use Rc<T>, stored in Lua-managed memory.
The Lua API (I'm using rust-lua53 for now) lets you allocate a chunk of memory and attach methods and a finalizer to it, so I want to store an Rc<T> into that chunk of memory.
My current attempt looks like. First, creating an object:
/* Allocate a block of uninitialized memory to use */
let p = state.new_userdata(mem::size_of::<Rc<T>>() as size_t) as *mut Rc<T>;
/* Make a ref-counted pointer to a Rust object */
let rc = Rc::<T>::new(...);
/* Store the Rc */
unsafe { ptr::write(p, rc) };
And in the finaliser:
let p: *mut Rc<T> = ...; /* Get a pointer to the item to finalize */
unsafe { ptr::drop_in_place(p) }; /* Release the object */
Now this seems to work (as briefly tested by adding a println!() to the drop method). But is it correct and safe (as long as I make sure it's not accessed after finalization)? I don't feel confident enough in unsafe Rust to be sure that it's ok to ptr::write an Rc<T>.
I'm also wondering about, rather than storing an Rc<T> directly, storing an Option<Rc<T>>; then instead of drop_in_place() I would ptr::swap() it with None. This would make it easy to handle any use after finalization.
Now this seems to work (as briefly tested by adding a println!() to the drop method). But is it correct and safe (as long as I make sure it's not accessed after finalisation)? I don't feel confident enough in unsafe Rust to be sure that it's ok to ptr::write an Rc<T>.
Yes, you may ptr::write any Rust type to any memory location. This "leaks" the Rc<T> object, but writes a bit-equivalent to the target location.
When using it, you need to guarantee that no one modified it outside of Rust code and that you are still in the same thread as the one where it was created. If you want to be able to move across threads, you need to use Arc.
Rust's thread safety cannot protect you here, because you are using raw pointers.
I'm also wondering about, rather than storing an Rc<T> directly, storing an Option<Rc<T>>; then instead of drop_in_place() I would ptr::swap() it with None. This would make it easy to handle any use after finalisation.
The pendant to ptr::write is ptr::read. So if you can guarantee that no one ever tries to ptr::read or drop_in_place() the object, then you can just call ptr::read (which returns the object) and use that object as you would use any other Rc<T> object. You don't need to care about dropping or anything, because now it's back in Rust's control.
You should also be using new_userdata_typed instead of new_userdata, since that takes the memory handling off your hands. There are other convenience wrapper functions ending with the postfix _typed for most userdata needs.
Your code will work; of course, note that the drop_in_place(p) will just decrease the counter of the Rc and only drop the contained T if and only if it was the last reference, which is the correct action.

Are objects accessed indirectly in D?

As I've read all objects in D are fully location independent. How this requirement is achieved?
One thing that comes to my mind, is that all references are not pointers to the objects, but to some proxy, so when you move object (in memory) you just update that proxy, not all references used in program.
But this is just my guess. How it is done in D for real?
edit: bottom line up front, no proxy object, objects are referenced directly through regular pointers. /edit
structs aren't allowed to keep a pointer to themselves, so if they get copied, they should continue to just work. This isn't strictly enforced by the language though:
struct S {
S* lol;
void beBad() {
lol = &this; // this compiler will allow this....
}
}
S pain() {
S s;
s.beBad();
return s;
}
void main() {
S s;
s = pain();
assert(s.lol !is &s); // but it will also move the object without notice!
}
(EDIT: actually, I guess you could use a postblit to update internal pointers, so it isn't quite without notice. If you're careful enough, you could make it work, but then again, if you're careful enough, you can shoot between your toes without hitting your foot too. EDIT2: Actually no, the compiler/runtime is still allowed to move it without even calling the postblit. One example of where this happens is if it copies a stack frame to the heap to make a closure. The struct data is moved to a new address without being informed. So yeah. /edit)
And actually, that assert isn't guaranteed to pass, the compiler might choose to call pain straight on the local object declared in main, so the pointer would work (though I'm not able to force this optimization here for a demo, generally, when you return a struct from a function, it is actually done via a hidden pointer the caller passes - the caller says "put the return value right here" thus avoiding a copy/move in some cases).
But anyway, the point just is that the compiler is free to copy or not to copy a struct at its leisure, so if you do keep the address of this around in it, it may become invalid without notice; keeping that pointer is not a compile error, but it is undefined behavior.
The situation is different with classes. Classes are allowed to keep references to this internally since a class is (in theory, realized by the garbage collector implementation)) an independent object with an infinite lifetime. While it may be moved (such as be a moving GC (not implemented in D today)), if it is moved, all references to it, internal and external, would also be required to be updated.
So classes can't have the memory pulled out from under them like structs can (unless you the programmer take matters into your own hands and bypass the GC...)
The location independent thing I'm pretty sure is referring only to structs and only to the rule that they can't have pointers to themselves. There's no magic done with references or pointers - they indeed work with memory addresses, no proxy objects.

Resources