Giter Site home page Giter Site logo

f64 return value mismatch about wasmer HOT 11 CLOSED

wasmerio avatar wasmerio commented on May 4, 2024
f64 return value mismatch

from wasmer.

Comments (11)

CryZe avatar CryZe commented on May 4, 2024 2

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.

CryZe avatar CryZe commented on May 4, 2024

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.

CryZe avatar CryZe commented on May 4, 2024

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.

syrusakbary avatar syrusakbary commented on May 4, 2024

Thanks for the super detailed examples, we'll take a look on it soon!

from wasmer.

CryZe avatar CryZe commented on May 4, 2024

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:

https://i.imgur.com/ATms1zT.png

from wasmer.

xmclark avatar xmclark commented on May 4, 2024

@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.

CryZe avatar CryZe commented on May 4, 2024

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.

xmclark avatar xmclark commented on May 4, 2024

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.

image

from wasmer.

CryZe avatar CryZe commented on May 4, 2024

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.

CryZe avatar CryZe commented on May 4, 2024

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.

lachlansneff avatar lachlansneff commented on May 4, 2024

That seems like a good solution to me! Make a pr!

from wasmer.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.