Comments (11)
So I tweaked the macro so I can specify the repr per S* type and gave the S1 a repr(transparent) and now everything works. Would that be a sufficient solution that I could PR (or maybe you guys do the change real quick) or is there a better solution?
from wasmer.
The RefCell is not necessary, this results in a much smaller file:
fn main() {
let binary = [
0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60, 0x00, 0x00, 0x60,
0x00, 0x01, 0x7C, 0x03, 0x03, 0x02, 0x00, 0x01, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01, 0x01,
0x05, 0x03, 0x01, 0x00, 0x11, 0x06, 0x19, 0x03, 0x7F, 0x01, 0x41, 0x80, 0x80, 0xC0, 0x00,
0x0B, 0x7F, 0x00, 0x41, 0x90, 0x80, 0xC0, 0x00, 0x0B, 0x7F, 0x00, 0x41, 0x90, 0x80, 0xC0,
0x00, 0x0B, 0x07, 0x4D, 0x05, 0x06, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0x02, 0x00, 0x19,
0x5F, 0x5F, 0x69, 0x6E, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5F, 0x66, 0x75, 0x6E, 0x63,
0x74, 0x69, 0x6F, 0x6E, 0x5F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x01, 0x00, 0x0B, 0x5F, 0x5F,
0x68, 0x65, 0x61, 0x70, 0x5F, 0x62, 0x61, 0x73, 0x65, 0x03, 0x01, 0x0A, 0x5F, 0x5F, 0x64,
0x61, 0x74, 0x61, 0x5F, 0x65, 0x6E, 0x64, 0x03, 0x02, 0x09, 0x67, 0x61, 0x6D, 0x65, 0x5F,
0x74, 0x69, 0x6D, 0x65, 0x00, 0x01, 0x0A, 0x42, 0x02, 0x02, 0x00, 0x0B, 0x3D, 0x00, 0x02,
0x40, 0x41, 0x00, 0x29, 0x03, 0x80, 0x80, 0x40, 0x42, 0x01, 0x52, 0x0D, 0x00, 0x41, 0x00,
0x2B, 0x03, 0x88, 0x80, 0x40, 0x0F, 0x0B, 0x41, 0x00, 0x42, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0xD0, 0xB7, 0xC0, 0x00, 0x37, 0x03, 0x88, 0x80, 0x40, 0x41, 0x00, 0x42, 0x01, 0x37,
0x03, 0x80, 0x80, 0x40, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6F, 0x40, 0x0B, 0x0B,
0x19, 0x01, 0x00, 0x41, 0x80, 0x80, 0xC0, 0x00, 0x0B, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x04, 0x6E,
0x61, 0x6D, 0x65, 0x01, 0x1F, 0x02, 0x00, 0x11, 0x5F, 0x5F, 0x77, 0x61, 0x73, 0x6D, 0x5F,
0x63, 0x61, 0x6C, 0x6C, 0x5F, 0x63, 0x74, 0x6F, 0x72, 0x73, 0x01, 0x09, 0x67, 0x61, 0x6D,
0x65, 0x5F, 0x74, 0x69, 0x6D, 0x65, 0x02, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00,
];
let import_object = wasmer_runtime::imports! {};
let instance = wasmer_runtime::instantiate(&binary, &import_object).unwrap();
if let Ok(func) = instance.func::<(), f64>("game_time") {
let ret_val = func.call().unwrap();
println!("{} {:#016x}", ret_val, ret_val.to_bits());
}
}
WAST:
(module
(type $t0 (func))
(type $t1 (func (result f64)))
(func $__wasm_call_ctors (type $t0))
(func $game_time (type $t1) (result f64)
block $B0
i32.const 0
i64.load offset=1048576
i64.const 1
i64.ne
br_if $B0
i32.const 0
f64.load offset=1048584
return
end
i32.const 0
i64.const 4643000109586448384
i64.store offset=1048584
i32.const 0
i64.const 1
i64.store offset=1048576
f64.const 0x1.f4p+7 (;=250;))
(table $__indirect_function_table 1 1 anyfunc)
(memory $memory 17)
(global $g0 (mut i32) (i32.const 1048576))
(global $__heap_base i32 (i32.const 1048592))
(global $__data_end i32 (i32.const 1048592))
(export "memory" (memory 0))
(export "__indirect_function_table" (table 0))
(export "__heap_base" (global 1))
(export "__data_end" (global 2))
(export "game_time" (func $game_time))
(data (i32.const 1048576) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"))
Source:
use std::cell::RefCell;
struct Context {
val: f64,
}
fn build_context() -> Context {
Context {
val: 250.0,
}
}
thread_local! {
static CONTEXT: Context = build_context();
}
#[no_mangle]
pub extern "C" fn game_time() -> f64 {
CONTEXT.with(|ctx| {
ctx.val
})
}
from wasmer.
It seems like global variables don't work at all actually (if they are sufficiently uninlinable) as shown here:
(module
(type $t0 (func))
(type $t1 (func (result f64)))
(func $__wasm_call_ctors (type $t0))
(func $mutate (type $t0)
i32.const 0
i64.const 4636737291354636288
i64.store offset=1048576)
(func $game_time (type $t1) (result f64)
i32.const 0
f64.load offset=1048576)
(table $__indirect_function_table 1 1 anyfunc)
(memory $memory 17)
(global $g0 (mut i32) (i32.const 1048576))
(global $__heap_base i32 (i32.const 1048584))
(global $__data_end i32 (i32.const 1048584))
(export "memory" (memory 0))
(export "__indirect_function_table" (table 0))
(export "__heap_base" (global 1))
(export "__data_end" (global 2))
(export "mutate" (func $mutate))
(export "game_time" (func $game_time))
(data (i32.const 1048576) "\00\00\00\00\00@o@"))
Neither calling mutate nor skipping it produce the correct value, suggesting that it is indeed an ABI problem, because even if it would store / load from an incorrect address, at least mutate
would write to the same location as the game_time
function is loading from, and yet it still doesn't return the correct value.
from wasmer.
Thanks for the super detailed examples, we'll take a look on it soon!
from wasmer.
Ah, I figured out the problem. It's the assumption that c structs with a single element have the same ABI as the single element itself, but that isn't always the case. So the S1<f64> WasmExternType impl destructures the S1 by derefencing from a pointer, storing the value in XMM0. However the JIT'ed code already has the f64 residing in the XMM0 register, which now gets overwritten by garbage:
from wasmer.
@CryZe Looks like you're using visual studio to debug Rust! I personally have not got this to work correctly. This is unrelated to the issue, but could you point me to resources on how you got visual studio configured for rust? How you're attaching the debugger?
In addition to learning how to do that, I want to reproduce and visual the problem the same way you have.
from wasmer.
I did not really set up much. It works straight out of the box. You just need to make sure you use the msvc target and then you open the actual .exe file as a project (not as a file) in Visual Studio. After the "project" is opened you want to open the main.rs and put a breakpoint in there. Then you can start the project and it should hit the breakpoint. From there I added the disassembly and register view (which you can find under debugging -> views (or something, mine is german)). And then I right clicked the register view to show the SSE registers.
from wasmer.
Wow that is totally unintuitive, but that works. Do you manually open the source files with the "Open" button, or have you found a way to load the source into the solution explorer? As it is now, I only have the wasmer.exe shown in solution explorer.
from wasmer.
I actually usually use the Visual Studio Debugger in VS Code where I also have direct access to all my source files and stuff. However for this, VS Code's debugger is missing the disassembly and register view, which was necessary here. So I switched to Visual Studio instead. So since this is such a temporary occurance I just manually stepped through the calls which auto opened the files, and didn't bother with properly setting up any solution or anything. But I guess you could theoretically add the folders to the solution and then save it as a proper solution? I really don't know though.
from wasmer.
I also was able to replicate this on Godbolt right now, where #[repr(C)] struct F(f64) and f64 behave differently when targeting windows (not linux though): https://rust.godbolt.org/z/pNibCT
from wasmer.
That seems like a good solution to me! Make a pr!
from wasmer.
Related Issues (20)
- `fd_prestat_get` doesn't return the mapped directory since v4.2.6
- CI: Weekly wasmer-argus run
- Wasmer can't run Doom HOT 5
- llvm: v128 loads with invalid memory offsets inconsistently traps
- llvm: Incorrect result for extmul instructions
- Encrypting wasm in browser HOT 1
- postgresql driver for wasmer
- CLI - Prune the cache for an app
- Have Wasmer Argus to create webc for all packages and see if they work the same
- Support unnamed packages in "wasmer run"
- Support "wasmer deploy" with unnamed packages
- wasmer run and WasiRunner: prioritize webcv2 over v3
- cli: Allow "app create" should support unnamed packages
- Add webc v3 execution tests
- Improve import creation times
- c-api shows no error message when failing instantiation, how to check what is wrong? HOT 2
- Lift dependencies into workspace
- wasmer-config Package manifest: Remove legacy CommandV1 support
- wasmer_config::package::PackageHash - Refactor to enum
- `fd_advise` behavior diverges from other runtimes with large offset + len HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from wasmer.