diff --git a/src/prebuilt/wasm2c_atomicops_source_declarations.cc b/src/prebuilt/wasm2c_atomicops_source_declarations.cc index 0bfe0cd1e5..1d14381c17 100644 --- a/src/prebuilt/wasm2c_atomicops_source_declarations.cc +++ b/src/prebuilt/wasm2c_atomicops_source_declarations.cc @@ -17,19 +17,53 @@ R"w2c_template( TRAP(UNALIGNED); \ R"w2c_template( } )w2c_template" R"w2c_template( -#define DEFINE_SHARED_LOAD(name, t1, t2, t3, force_read) \ +#if !WABT_BIG_ENDIAN +)w2c_template" +R"w2c_template(#define DEFINE_SHARED_LOAD(name, t1, atomic_type, t2, t3, force_read) \ )w2c_template" R"w2c_template( static inline t3 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ )w2c_template" R"w2c_template( wasm_rt_shared_memory_t* mem, u64 addr) { \ )w2c_template" -R"w2c_template( t1 result; \ +R"w2c_template( t1 result = atomic_load_explicit((_Atomic volatile t1*)&mem->data[addr], \ +)w2c_template" +R"w2c_template( memory_order_relaxed); \ +)w2c_template" +R"w2c_template( t3 ret = (t3)(t2)result; \ +)w2c_template" +R"w2c_template( force_read(ret); \ +)w2c_template" +R"w2c_template( return ret; \ +)w2c_template" +R"w2c_template( } \ +)w2c_template" +R"w2c_template( DEF_MEM_CHECKS0(name, _shared_, t1, return, t3) )w2c_template" -R"w2c_template( result = atomic_load_explicit( \ +R"w2c_template(#else )w2c_template" -R"w2c_template( (_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), \ +R"w2c_template(// Big endian should not use atomic_load_explicit to load float* as Wasm stores +)w2c_template" +R"w2c_template(// these in little endian. Loading arbitrary values into float's may result in +)w2c_template" +R"w2c_template(// loading bytes that get interpreted as signalling nans etc. We avoid this by +)w2c_template" +R"w2c_template(// loading into an unsigned type of the same size. +)w2c_template" +R"w2c_template(#define DEFINE_SHARED_LOAD(name, t1, atomic_type, t2, t3, force_read) \ +)w2c_template" +R"w2c_template( static inline t3 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ +)w2c_template" +R"w2c_template( wasm_rt_shared_memory_t* mem, u64 addr) { \ +)w2c_template" +R"w2c_template( atomic_type raw = WASM_ADJUST_ENDIAN_##atomic_type( \ +)w2c_template" +R"w2c_template( atomic_load_explicit((_Atomic volatile atomic_type*)&mem->data[addr], \ +)w2c_template" +R"w2c_template( memory_order_relaxed)); \ +)w2c_template" +R"w2c_template( t1 result; \ )w2c_template" -R"w2c_template( memory_order_relaxed); \ +R"w2c_template( wasm_rt_memcpy(&result, &raw, sizeof(t1)); \ )w2c_template" R"w2c_template( t3 ret = (t3)(t2)result; \ )w2c_template" @@ -41,37 +75,65 @@ R"w2c_template( } )w2c_template" R"w2c_template( DEF_MEM_CHECKS0(name, _shared_, t1, return, t3) )w2c_template" +R"w2c_template(#endif +)w2c_template" R"w2c_template( -DEFINE_SHARED_LOAD(i32_load_shared, u32, u32, u32, FORCE_READ_INT) +DEFINE_SHARED_LOAD(i32_load_shared, u32, u32, u32, u32, FORCE_READ_INT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(i64_load_shared, u64, u64, u64, FORCE_READ_INT) +R"w2c_template(DEFINE_SHARED_LOAD(i64_load_shared, u64, u64, u64, u64, FORCE_READ_INT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(f32_load_shared, f32, f32, f32, FORCE_READ_FLOAT) +R"w2c_template(DEFINE_SHARED_LOAD(f32_load_shared, f32, u32, f32, f32, FORCE_READ_FLOAT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(f64_load_shared, f64, f64, f64, FORCE_READ_FLOAT) +R"w2c_template(DEFINE_SHARED_LOAD(f64_load_shared, f64, u64, f64, f64, FORCE_READ_FLOAT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(i32_load8_s_shared, s8, s32, u32, FORCE_READ_INT) +R"w2c_template(DEFINE_SHARED_LOAD(i32_load8_s_shared, s8, u8, s32, u32, FORCE_READ_INT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(i64_load8_s_shared, s8, s64, u64, FORCE_READ_INT) +R"w2c_template(DEFINE_SHARED_LOAD(i64_load8_s_shared, s8, u8, s64, u64, FORCE_READ_INT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(i32_load8_u_shared, u8, u32, u32, FORCE_READ_INT) +R"w2c_template(DEFINE_SHARED_LOAD(i32_load8_u_shared, u8, u8, u32, u32, FORCE_READ_INT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(i64_load8_u_shared, u8, u64, u64, FORCE_READ_INT) +R"w2c_template(DEFINE_SHARED_LOAD(i64_load8_u_shared, u8, u8, u64, u64, FORCE_READ_INT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(i32_load16_s_shared, s16, s32, u32, FORCE_READ_INT) +R"w2c_template(DEFINE_SHARED_LOAD(i32_load16_s_shared, s16, u16, s32, u32, FORCE_READ_INT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(i64_load16_s_shared, s16, s64, u64, FORCE_READ_INT) +R"w2c_template(DEFINE_SHARED_LOAD(i64_load16_s_shared, s16, u16, s64, u64, FORCE_READ_INT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(i32_load16_u_shared, u16, u32, u32, FORCE_READ_INT) +R"w2c_template(DEFINE_SHARED_LOAD(i32_load16_u_shared, u16, u16, u32, u32, FORCE_READ_INT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(i64_load16_u_shared, u16, u64, u64, FORCE_READ_INT) +R"w2c_template(DEFINE_SHARED_LOAD(i64_load16_u_shared, u16, u16, u64, u64, FORCE_READ_INT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(i64_load32_s_shared, s32, s64, u64, FORCE_READ_INT) +R"w2c_template(DEFINE_SHARED_LOAD(i64_load32_s_shared, s32, u32, s64, u64, FORCE_READ_INT) )w2c_template" -R"w2c_template(DEFINE_SHARED_LOAD(i64_load32_u_shared, u32, u64, u64, FORCE_READ_INT) +R"w2c_template(DEFINE_SHARED_LOAD(i64_load32_u_shared, u32, u32, u64, u64, FORCE_READ_INT) )w2c_template" R"w2c_template( -#define DEFINE_SHARED_STORE(name, t1, t2) \ +#if !WABT_BIG_ENDIAN +)w2c_template" +R"w2c_template(#define DEFINE_SHARED_STORE(name, t1, atomic_type, t2) \ +)w2c_template" +R"w2c_template( static inline void name##_unchecked( \ +)w2c_template" +R"w2c_template( uint8_t* const wasm_rt_local_memory_base, wasm_rt_shared_memory_t* mem, \ +)w2c_template" +R"w2c_template( u64 addr, t2 value) { \ +)w2c_template" +R"w2c_template( t1 wrapped = (t1)value; \ +)w2c_template" +R"w2c_template( atomic_store_explicit((_Atomic volatile t1*)&mem->data[addr], wrapped, \ +)w2c_template" +R"w2c_template( memory_order_relaxed); \ +)w2c_template" +R"w2c_template( } \ +)w2c_template" +R"w2c_template( DEF_MEM_CHECKS1(name, _shared_, t1, , void, t2) +)w2c_template" +R"w2c_template(#else +)w2c_template" +R"w2c_template(// Big endian should not use atomic_store_explicit to store float* for the same +)w2c_template" +R"w2c_template(// reason as the load +)w2c_template" +R"w2c_template(#define DEFINE_SHARED_STORE(name, t1, atomic_type, t2) \ )w2c_template" R"w2c_template( static inline void name##_unchecked( \ )w2c_template" @@ -81,34 +143,40 @@ R"w2c_template( u64 addr, t2 value) { )w2c_template" R"w2c_template( t1 wrapped = (t1)value; \ )w2c_template" -R"w2c_template( atomic_store_explicit( \ +R"w2c_template( atomic_type raw; \ +)w2c_template" +R"w2c_template( wasm_rt_memcpy(&raw, &wrapped, sizeof(t1)); \ +)w2c_template" +R"w2c_template( atomic_store_explicit((_Atomic volatile atomic_type*)&mem->data[addr], \ )w2c_template" -R"w2c_template( (_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), wrapped, \ +R"w2c_template( WASM_ADJUST_ENDIAN_##atomic_type(raw), \ )w2c_template" -R"w2c_template( memory_order_relaxed); \ +R"w2c_template( memory_order_relaxed); \ )w2c_template" R"w2c_template( } \ )w2c_template" R"w2c_template( DEF_MEM_CHECKS1(name, _shared_, t1, , void, t2) )w2c_template" +R"w2c_template(#endif +)w2c_template" R"w2c_template( -DEFINE_SHARED_STORE(i32_store_shared, u32, u32) +DEFINE_SHARED_STORE(i32_store_shared, u32, u32, u32) )w2c_template" -R"w2c_template(DEFINE_SHARED_STORE(i64_store_shared, u64, u64) +R"w2c_template(DEFINE_SHARED_STORE(i64_store_shared, u64, u64, u64) )w2c_template" -R"w2c_template(DEFINE_SHARED_STORE(f32_store_shared, f32, f32) +R"w2c_template(DEFINE_SHARED_STORE(f32_store_shared, f32, u32, f32) )w2c_template" -R"w2c_template(DEFINE_SHARED_STORE(f64_store_shared, f64, f64) +R"w2c_template(DEFINE_SHARED_STORE(f64_store_shared, f64, u64, f64) )w2c_template" -R"w2c_template(DEFINE_SHARED_STORE(i32_store8_shared, u8, u32) +R"w2c_template(DEFINE_SHARED_STORE(i32_store8_shared, u8, u8, u32) )w2c_template" -R"w2c_template(DEFINE_SHARED_STORE(i32_store16_shared, u16, u32) +R"w2c_template(DEFINE_SHARED_STORE(i32_store16_shared, u16, u16, u32) )w2c_template" -R"w2c_template(DEFINE_SHARED_STORE(i64_store8_shared, u8, u64) +R"w2c_template(DEFINE_SHARED_STORE(i64_store8_shared, u8, u8, u64) )w2c_template" -R"w2c_template(DEFINE_SHARED_STORE(i64_store16_shared, u16, u64) +R"w2c_template(DEFINE_SHARED_STORE(i64_store16_shared, u16, u16, u64) )w2c_template" -R"w2c_template(DEFINE_SHARED_STORE(i64_store32_shared, u32, u64) +R"w2c_template(DEFINE_SHARED_STORE(i64_store32_shared, u32, u32, u64) )w2c_template" R"w2c_template( #define DEFINE_ATOMIC_LOAD(name, t1, t2, t3, force_read) \ @@ -121,11 +189,9 @@ R"w2c_template( ATOMIC_ALIGNMENT_CHECK(addr, t1); )w2c_template" R"w2c_template( t1 result; \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ +R"w2c_template( wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ )w2c_template" -R"w2c_template( sizeof(t1)); \ -)w2c_template" -R"w2c_template( t3 ret = (t3)(t2)result; \ +R"w2c_template( t3 ret = (t3)(t2)WASM_ADJUST_ENDIAN_##t1(result); \ )w2c_template" R"w2c_template( force_read(ret); \ )w2c_template" @@ -143,13 +209,9 @@ R"w2c_template( u64 addr) { )w2c_template" R"w2c_template( ATOMIC_ALIGNMENT_CHECK(addr, t1); \ )w2c_template" -R"w2c_template( t1 result; \ -)w2c_template" -R"w2c_template( result = \ +R"w2c_template( t1 result = atomic_load((_Atomic volatile t1*)&mem->data[addr]); \ )w2c_template" -R"w2c_template( atomic_load((_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1))); \ -)w2c_template" -R"w2c_template( t3 ret = (t3)(t2)result; \ +R"w2c_template( t3 ret = (t3)(t2)WASM_ADJUST_ENDIAN_##t1(result); \ )w2c_template" R"w2c_template( force_read(ret); \ )w2c_template" @@ -185,11 +247,9 @@ R"w2c_template( u64 addr, t2 value) { )w2c_template" R"w2c_template( ATOMIC_ALIGNMENT_CHECK(addr, t1); \ )w2c_template" -R"w2c_template( t1 wrapped = (t1)value; \ -)w2c_template" -R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ +R"w2c_template( t1 wrapped = WASM_ADJUST_ENDIAN_##t1((t1)value); \ )w2c_template" -R"w2c_template( sizeof(t1)); \ +R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ )w2c_template" R"w2c_template( } \ )w2c_template" @@ -203,11 +263,9 @@ R"w2c_template( u64 addr, t2 value) { )w2c_template" R"w2c_template( ATOMIC_ALIGNMENT_CHECK(addr, t1); \ )w2c_template" -R"w2c_template( t1 wrapped = (t1)value; \ -)w2c_template" -R"w2c_template( atomic_store((_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), \ +R"w2c_template( t1 wrapped = WASM_ADJUST_ENDIAN_##t1((t1)value); \ )w2c_template" -R"w2c_template( wrapped); \ +R"w2c_template( atomic_store((_Atomic volatile t1*)&mem->data[addr], wrapped); \ )w2c_template" R"w2c_template( } \ )w2c_template" @@ -229,6 +287,45 @@ R"w2c_template(DEFINE_ATOMIC_STORE(i64_atomic_store16, u16, u64) R"w2c_template(DEFINE_ATOMIC_STORE(i64_atomic_store32, u32, u64) )w2c_template" R"w2c_template( +#if WABT_BIG_ENDIAN +)w2c_template" +R"w2c_template(// Since native read-modify-write operations expect values to have the host +)w2c_template" +R"w2c_template(// endianness, we can use them. So we have to do this in multiple steps, while +)w2c_template" +R"w2c_template(// checking that the value hasn't changed in the middle. +)w2c_template" +R"w2c_template(#define WASM_RT_ATOMIC_RMW(t, ptr, value, opname, op, ret) \ +)w2c_template" +R"w2c_template( do { \ +)w2c_template" +R"w2c_template( t raw = atomic_load(ptr); \ +)w2c_template" +R"w2c_template( while (1) { \ +)w2c_template" +R"w2c_template( ret = WASM_ADJUST_ENDIAN_##t(raw); \ +)w2c_template" +R"w2c_template( t new_raw = WASM_ADJUST_ENDIAN_##t((ret)op(value)); \ +)w2c_template" +R"w2c_template( if (atomic_compare_exchange_weak(ptr, &raw, new_raw)) { \ +)w2c_template" +R"w2c_template( break; \ +)w2c_template" +R"w2c_template( } \ +)w2c_template" +R"w2c_template( } \ +)w2c_template" +R"w2c_template( } while (0) +)w2c_template" +R"w2c_template(#else +)w2c_template" +R"w2c_template(#define WASM_RT_ATOMIC_RMW(t, ptr, value, opname, op, ret) \ +)w2c_template" +R"w2c_template( ret = atomic_##opname(ptr, value) +)w2c_template" +R"w2c_template(#endif +)w2c_template" +R"w2c_template( #define DEFINE_ATOMIC_RMW(name, opname, op, t1, t2) \ )w2c_template" R"w2c_template( static inline t2 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ @@ -243,13 +340,13 @@ R"w2c_template( t1 wrapped = (t1)value; )w2c_template" R"w2c_template( t1 ret; \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(&ret, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), sizeof(t1)); \ +R"w2c_template( wasm_rt_memcpy(&ret, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ )w2c_template" -R"w2c_template( t1 newval = ret op wrapped; \ +R"w2c_template( ret = WASM_ADJUST_ENDIAN_##t1(ret); \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &newval, \ +R"w2c_template( t1 newval = WASM_ADJUST_ENDIAN_##t1(ret op wrapped); \ )w2c_template" -R"w2c_template( sizeof(t1)); \ +R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &newval, sizeof(t1)); \ )w2c_template" R"w2c_template( return (t2)ret; \ )w2c_template" @@ -267,9 +364,11 @@ R"w2c_template( ATOMIC_ALIGNMENT_CHECK(addr, t1); )w2c_template" R"w2c_template( t1 wrapped = (t1)value; \ )w2c_template" -R"w2c_template( t1 ret = atomic_##opname( \ +R"w2c_template( t1 ret; \ +)w2c_template" +R"w2c_template( WASM_RT_ATOMIC_RMW(t1, (_Atomic volatile t1*)&mem->data[addr], wrapped, \ )w2c_template" -R"w2c_template( (_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), wrapped); \ +R"w2c_template( opname, op, ret); \ )w2c_template" R"w2c_template( return (t2)ret; \ )w2c_template" @@ -353,49 +452,45 @@ R"w2c_template(DEFINE_ATOMIC_RMW(i64_atomic_rmw32_xor_u, fetch_xor, ^, u32, u64) R"w2c_template(DEFINE_ATOMIC_RMW(i64_atomic_rmw_xor, fetch_xor, ^, u64, u64) )w2c_template" R"w2c_template( -#define DEFINE_ATOMIC_XCHG(name, opname, t1, t2) \ +#define DEFINE_ATOMIC_XCHG(name, opname, t1, t2) \ )w2c_template" -R"w2c_template( static inline t2 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ +R"w2c_template( static inline t2 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ )w2c_template" -R"w2c_template( wasm_rt_memory_t* mem, u64 addr, \ +R"w2c_template( wasm_rt_memory_t* mem, u64 addr, \ )w2c_template" -R"w2c_template( t2 value) { \ +R"w2c_template( t2 value) { \ )w2c_template" -R"w2c_template( ATOMIC_ALIGNMENT_CHECK(addr, t1); \ +R"w2c_template( ATOMIC_ALIGNMENT_CHECK(addr, t1); \ )w2c_template" -R"w2c_template( t1 wrapped = (t1)value; \ +R"w2c_template( t1 wrapped = WASM_ADJUST_ENDIAN_##t1((t1)value); \ )w2c_template" -R"w2c_template( t1 ret; \ +R"w2c_template( t1 ret; \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(&ret, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), sizeof(t1)); \ +R"w2c_template( wasm_rt_memcpy(&ret, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ +R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ )w2c_template" -R"w2c_template( sizeof(t1)); \ +R"w2c_template( return (t2)WASM_ADJUST_ENDIAN_##t1(ret); \ )w2c_template" -R"w2c_template( return (t2)ret; \ +R"w2c_template( } \ )w2c_template" -R"w2c_template( } \ -)w2c_template" -R"w2c_template( DEF_MEM_CHECKS1(name, _, t1, return, t2, t2) \ +R"w2c_template( DEF_MEM_CHECKS1(name, _, t1, return, t2, t2) \ )w2c_template" -R"w2c_template( static inline t2 name##_shared_unchecked( \ -)w2c_template" -R"w2c_template( uint8_t* const wasm_rt_local_memory_base, wasm_rt_shared_memory_t* mem, \ +R"w2c_template( static inline t2 name##_shared_unchecked( \ )w2c_template" -R"w2c_template( u64 addr, t2 value) { \ +R"w2c_template( uint8_t* const wasm_rt_local_memory_base, wasm_rt_shared_memory_t* mem, \ )w2c_template" -R"w2c_template( ATOMIC_ALIGNMENT_CHECK(addr, t1); \ +R"w2c_template( u64 addr, t2 value) { \ )w2c_template" -R"w2c_template( t1 wrapped = (t1)value; \ +R"w2c_template( ATOMIC_ALIGNMENT_CHECK(addr, t1); \ )w2c_template" -R"w2c_template( t1 ret = atomic_##opname( \ +R"w2c_template( t1 wrapped = WASM_ADJUST_ENDIAN_##t1((t1)value); \ )w2c_template" -R"w2c_template( (_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), wrapped); \ +R"w2c_template( t1 ret = atomic_##opname((_Atomic volatile t1*)&mem->data[addr], wrapped); \ )w2c_template" -R"w2c_template( return (t2)ret; \ +R"w2c_template( return (t2)WASM_ADJUST_ENDIAN_##t1(ret); \ )w2c_template" -R"w2c_template( } \ +R"w2c_template( } \ )w2c_template" R"w2c_template( DEF_MEM_CHECKS1(name##_shared, _shared_, t1, return, t2, t2) )w2c_template" @@ -425,23 +520,23 @@ R"w2c_template( t1 expected, t1 replacement) )w2c_template" R"w2c_template( ATOMIC_ALIGNMENT_CHECK(addr, t2); \ )w2c_template" -R"w2c_template( t2 expected_wrapped = (t2)expected; \ +R"w2c_template( t2 expected_wrapped = WASM_ADJUST_ENDIAN_##t2((t2)expected); \ )w2c_template" -R"w2c_template( t2 replacement_wrapped = (t2)replacement; \ +R"w2c_template( t2 replacement_wrapped = WASM_ADJUST_ENDIAN_##t2((t2)replacement); \ )w2c_template" R"w2c_template( t2 ret; \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(&ret, MEM_ADDR_MEMOP(mem, addr, sizeof(t2)), sizeof(t2)); \ +R"w2c_template( wasm_rt_memcpy(&ret, MEM_ADDR_MEMOP(mem, addr), sizeof(t2)); \ )w2c_template" R"w2c_template( if (ret == expected_wrapped) { \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t2)), \ +R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &replacement_wrapped, \ )w2c_template" -R"w2c_template( &replacement_wrapped, sizeof(t2)); \ +R"w2c_template( sizeof(t2)); \ )w2c_template" R"w2c_template( } \ )w2c_template" -R"w2c_template( return (t1)ret; \ +R"w2c_template( return (t1)WASM_ADJUST_ENDIAN_##t2(ret); \ )w2c_template" R"w2c_template( } \ )w2c_template" @@ -455,17 +550,15 @@ R"w2c_template( u64 addr, t1 expected, t1 replacement) { )w2c_template" R"w2c_template( ATOMIC_ALIGNMENT_CHECK(addr, t2); \ )w2c_template" -R"w2c_template( t2 expected_wrapped = (t2)expected; \ -)w2c_template" -R"w2c_template( t2 replacement_wrapped = (t2)replacement; \ +R"w2c_template( t2 expected_wrapped = WASM_ADJUST_ENDIAN_##t2((t2)expected); \ )w2c_template" -R"w2c_template( atomic_compare_exchange_strong( \ +R"w2c_template( t2 replacement_wrapped = WASM_ADJUST_ENDIAN_##t2((t2)replacement); \ )w2c_template" -R"w2c_template( (_Atomic volatile t2*)MEM_ADDR(mem, addr, sizeof(t2)), \ +R"w2c_template( atomic_compare_exchange_strong((_Atomic volatile t2*)&mem->data[addr], \ )w2c_template" -R"w2c_template( &expected_wrapped, replacement_wrapped); \ +R"w2c_template( &expected_wrapped, replacement_wrapped); \ )w2c_template" -R"w2c_template( return (t1)expected_wrapped; \ +R"w2c_template( return (t1)WASM_ADJUST_ENDIAN_##t2(expected_wrapped); \ )w2c_template" R"w2c_template( } \ )w2c_template" diff --git a/src/prebuilt/wasm2c_simd_source_declarations.cc b/src/prebuilt/wasm2c_simd_source_declarations.cc index b1cd5f79c9..06474deda5 100644 --- a/src/prebuilt/wasm2c_simd_source_declarations.cc +++ b/src/prebuilt/wasm2c_simd_source_declarations.cc @@ -39,6 +39,33 @@ R"w2c_template( "Either enable specify -DWASM_RT_NONCONFORMING_ALLOW_OOB_READ_ R"w2c_template(#endif )w2c_template" R"w2c_template( +#if WABT_BIG_ENDIAN +)w2c_template" +R"w2c_template(static inline v128 WASM_ADJUST_ENDIAN_v128(v128 value) { +)w2c_template" +R"w2c_template( u64 input[2]; +)w2c_template" +R"w2c_template( u64 output[2]; +)w2c_template" +R"w2c_template( wasm_rt_memcpy(input, &value, sizeof(input)); +)w2c_template" +R"w2c_template( output[0] = htole64(input[1]); +)w2c_template" +R"w2c_template( output[1] = htole64(input[0]); +)w2c_template" +R"w2c_template( wasm_rt_memcpy(&value, output, sizeof(value)); +)w2c_template" +R"w2c_template( return value; +)w2c_template" +R"w2c_template(} +)w2c_template" +R"w2c_template(#else +)w2c_template" +R"w2c_template(#define WASM_ADJUST_ENDIAN_v128(value) (value) +)w2c_template" +R"w2c_template(#endif +)w2c_template" +R"w2c_template( // The below SIMD operations copy to a local variable first as the )w2c_template" R"w2c_template(// MEM_ADDR_MEMOP maybe segment pointers if WASM_RT_USE_SEGUE_FOR_THIS_MODULE is @@ -47,94 +74,94 @@ R"w2c_template(// defined and regular pointers otherwse. memcpy into the local w )w2c_template" R"w2c_template(// in both cases. )w2c_template" -R"w2c_template(#define DEFINE_SIMD_LOAD_FUNC(name, func, t) \ +R"w2c_template(#define DEFINE_SIMD_LOAD_FUNC(name, func, t) \ )w2c_template" -R"w2c_template( static inline v128 name##_unchecked( \ +R"w2c_template( static inline v128 name##_unchecked( \ )w2c_template" -R"w2c_template( uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ +R"w2c_template( uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ )w2c_template" -R"w2c_template( u64 addr) { \ +R"w2c_template( u64 addr) { \ )w2c_template" -R"w2c_template( t simd_mem_value; \ +R"w2c_template( t simd_mem_value; \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(&simd_mem_value, MEM_ADDR_MEMOP(mem, addr, sizeof(t)), \ +R"w2c_template( wasm_rt_memcpy(&simd_mem_value, MEM_ADDR_MEMOP(mem, addr), sizeof(t)); \ )w2c_template" -R"w2c_template( sizeof(t)); \ +R"w2c_template( simd_mem_value = WASM_ADJUST_ENDIAN_##t(simd_mem_value); \ )w2c_template" -R"w2c_template( v128 result = func(&simd_mem_value); \ +R"w2c_template( v128 result = func(&simd_mem_value); \ )w2c_template" -R"w2c_template( SIMD_FORCE_READ(result); \ +R"w2c_template( SIMD_FORCE_READ(result); \ )w2c_template" -R"w2c_template( return result; \ +R"w2c_template( return result; \ )w2c_template" -R"w2c_template( } \ +R"w2c_template( } \ )w2c_template" R"w2c_template( DEF_MEM_CHECKS0(name, _, t, return, v128); )w2c_template" R"w2c_template( -#define DEFINE_SIMD_LOAD_LANE(name, func, t, lane) \ +#define DEFINE_SIMD_LOAD_LANE(name, func, t, lane) \ )w2c_template" -R"w2c_template( static inline v128 name##_unchecked( \ +R"w2c_template( static inline v128 name##_unchecked( \ )w2c_template" -R"w2c_template( uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ +R"w2c_template( uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ )w2c_template" -R"w2c_template( u64 addr, v128 vec) { \ +R"w2c_template( u64 addr, v128 vec) { \ )w2c_template" -R"w2c_template( t simd_mem_value; \ +R"w2c_template( t simd_mem_value; \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(&simd_mem_value, MEM_ADDR_MEMOP(mem, addr, sizeof(t)), \ +R"w2c_template( wasm_rt_memcpy(&simd_mem_value, MEM_ADDR_MEMOP(mem, addr), sizeof(t)); \ )w2c_template" -R"w2c_template( sizeof(t)); \ +R"w2c_template( simd_mem_value = WASM_ADJUST_ENDIAN_##t(simd_mem_value); \ )w2c_template" -R"w2c_template( v128 result = func(&simd_mem_value, vec, lane); \ +R"w2c_template( v128 result = func(&simd_mem_value, vec, lane); \ )w2c_template" -R"w2c_template( SIMD_FORCE_READ(result); \ +R"w2c_template( SIMD_FORCE_READ(result); \ )w2c_template" -R"w2c_template( return result; \ +R"w2c_template( return result; \ )w2c_template" -R"w2c_template( } \ +R"w2c_template( } \ )w2c_template" R"w2c_template( DEF_MEM_CHECKS1(name, _, t, return, v128, v128); )w2c_template" R"w2c_template( -#define DEFINE_SIMD_STORE(name, t) \ +#define DEFINE_SIMD_STORE(name, t) \ )w2c_template" -R"w2c_template( static inline void name##_unchecked( \ +R"w2c_template( static inline void name##_unchecked( \ )w2c_template" -R"w2c_template( uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ +R"w2c_template( uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ )w2c_template" -R"w2c_template( u64 addr, v128 value) { \ +R"w2c_template( u64 addr, v128 value) { \ )w2c_template" -R"w2c_template( t simd_mem_value; \ +R"w2c_template( t simd_mem_value; \ )w2c_template" -R"w2c_template( simde_wasm_v128_store(&simd_mem_value, value); \ +R"w2c_template( simde_wasm_v128_store(&simd_mem_value, value); \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t)), &simd_mem_value, \ +R"w2c_template( simd_mem_value = WASM_ADJUST_ENDIAN_##t(simd_mem_value); \ )w2c_template" -R"w2c_template( sizeof(t)); \ +R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &simd_mem_value, sizeof(t)); \ )w2c_template" -R"w2c_template( } \ +R"w2c_template( } \ )w2c_template" R"w2c_template( DEF_MEM_CHECKS1(name, _, t, , void, v128); )w2c_template" R"w2c_template( -#define DEFINE_SIMD_STORE_LANE(name, func, t, lane) \ +#define DEFINE_SIMD_STORE_LANE(name, func, t, lane) \ )w2c_template" -R"w2c_template( static inline void name##_unchecked( \ +R"w2c_template( static inline void name##_unchecked( \ )w2c_template" -R"w2c_template( uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ +R"w2c_template( uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ )w2c_template" -R"w2c_template( u64 addr, v128 value) { \ +R"w2c_template( u64 addr, v128 value) { \ )w2c_template" -R"w2c_template( t simd_mem_value; \ +R"w2c_template( t simd_mem_value; \ )w2c_template" -R"w2c_template( func(&simd_mem_value, value, lane); \ +R"w2c_template( func(&simd_mem_value, value, lane); \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t)), &simd_mem_value, \ +R"w2c_template( simd_mem_value = WASM_ADJUST_ENDIAN_##t(simd_mem_value); \ )w2c_template" -R"w2c_template( sizeof(t)); \ +R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &simd_mem_value, sizeof(t)); \ )w2c_template" -R"w2c_template( } \ +R"w2c_template( } \ )w2c_template" R"w2c_template( DEF_MEM_CHECKS1(name, _, t, , void, v128); )w2c_template" diff --git a/src/prebuilt/wasm2c_source_declarations.cc b/src/prebuilt/wasm2c_source_declarations.cc index 1da5d1d100..5174366065 100644 --- a/src/prebuilt/wasm2c_source_declarations.cc +++ b/src/prebuilt/wasm2c_source_declarations.cc @@ -1,46 +1,4 @@ -const char* s_source_declarations = R"w2c_template( -// Computes a pointer to an object of the given size in a little-endian memory. -)w2c_template" -R"w2c_template(// -)w2c_template" -R"w2c_template(// On a little-endian host, this is just &mem->data[addr] - the object's size is -)w2c_template" -R"w2c_template(// unused. On a big-endian host, it's &mem->data[mem->size - addr - n], where n -)w2c_template" -R"w2c_template(// is the object's size. -)w2c_template" -R"w2c_template(// -)w2c_template" -R"w2c_template(// Note that mem may be evaluated multiple times. -)w2c_template" -R"w2c_template(// -)w2c_template" -R"w2c_template(// Parameters: -)w2c_template" -R"w2c_template(// mem - The memory. -)w2c_template" -R"w2c_template(// addr - The address. -)w2c_template" -R"w2c_template(// n - The size of the object. -)w2c_template" -R"w2c_template(// -)w2c_template" -R"w2c_template(// Result: -)w2c_template" -R"w2c_template(// A pointer for an object of size n. -)w2c_template" -R"w2c_template(#if WABT_BIG_ENDIAN -)w2c_template" -R"w2c_template(#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n)) -)w2c_template" -R"w2c_template(#else -)w2c_template" -R"w2c_template(#define MEM_ADDR(mem, addr, n) &((mem)->data[addr]) -)w2c_template" -R"w2c_template(#endif -)w2c_template" -R"w2c_template( -// We can only use Segue for this module if it uses a single unshared, +const char* s_source_declarations = R"w2c_template(// We can only use Segue for this module if it uses a single unshared, )w2c_template" R"w2c_template(// default-page, 32-bit imported or exported memory. )w2c_template" @@ -64,7 +22,7 @@ R"w2c_template(#endif R"w2c_template( #if WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE && WASM_RT_USE_MMAP && \ )w2c_template" -R"w2c_template( IS_SINGLE_UNSHARED_DEFAULT32_MEMORY && !WABT_BIG_ENDIAN +R"w2c_template( IS_SINGLE_UNSHARED_DEFAULT32_MEMORY )w2c_template" R"w2c_template(#define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 1 )w2c_template" @@ -121,15 +79,15 @@ R"w2c_template( } )w2c_template" R"w2c_template(} )w2c_template" -R"w2c_template(#define MEM_ADDR_MEMOP(mem, addr, n) ((uint8_t __seg_gs*)(uintptr_t)addr) +R"w2c_template(#define MEM_ADDR_MEMOP(mem, addr) ((uint8_t __seg_gs*)(uintptr_t)addr) )w2c_template" R"w2c_template(#elif WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE )w2c_template" -R"w2c_template(#define MEM_ADDR_MEMOP(mem, addr, n) (&wasm_rt_local_memory_base[(addr)]) +R"w2c_template(#define MEM_ADDR_MEMOP(mem, addr) (&wasm_rt_local_memory_base[(addr)]) )w2c_template" R"w2c_template(#else )w2c_template" -R"w2c_template(#define MEM_ADDR_MEMOP(mem, addr, n) MEM_ADDR(mem, addr, n) +R"w2c_template(#define MEM_ADDR_MEMOP(mem, addr) (&(mem)->data[addr]) )w2c_template" R"w2c_template(#endif )w2c_template" @@ -414,38 +372,90 @@ R"w2c_template( "Either enable specify -DWASM_RT_NONCONFORMING_ALLOW_OOB_READ_ R"w2c_template(#endif )w2c_template" R"w2c_template( -static inline void load_data(u8* dest, const u8* src, size_t n) { +#define WASM_ADJUST_ENDIAN_u8(value) (value) )w2c_template" -R"w2c_template( if (!n) { +R"w2c_template(#define WASM_ADJUST_ENDIAN_s8(value) (value) )w2c_template" -R"w2c_template( return; +R"w2c_template(#if WABT_BIG_ENDIAN )w2c_template" -R"w2c_template( } +R"w2c_template(#define WASM_ADJUST_ENDIAN_u16 htole16 )w2c_template" -R"w2c_template(#if WABT_BIG_ENDIAN +R"w2c_template(#define WASM_ADJUST_ENDIAN_s16 htole16 )w2c_template" -R"w2c_template( for (size_t i = 0; i < n; i++) { +R"w2c_template(#define WASM_ADJUST_ENDIAN_u32 htole32 )w2c_template" -R"w2c_template( dest[i] = src[n - i - 1]; +R"w2c_template(#define WASM_ADJUST_ENDIAN_s32 htole32 )w2c_template" -R"w2c_template( } +R"w2c_template(#define WASM_ADJUST_ENDIAN_u64 htole64 +)w2c_template" +R"w2c_template(static inline f32 WASM_ADJUST_ENDIAN_f32(f32 value) { +)w2c_template" +R"w2c_template( u32 bits; +)w2c_template" +R"w2c_template( wasm_rt_memcpy(&bits, &value, sizeof(bits)); +)w2c_template" +R"w2c_template( bits = htole32(bits); +)w2c_template" +R"w2c_template( wasm_rt_memcpy(&value, &bits, sizeof(value)); +)w2c_template" +R"w2c_template( return value; +)w2c_template" +R"w2c_template(} +)w2c_template" +R"w2c_template( +static inline f64 WASM_ADJUST_ENDIAN_f64(f64 value) { +)w2c_template" +R"w2c_template( u64 bits; +)w2c_template" +R"w2c_template( wasm_rt_memcpy(&bits, &value, sizeof(bits)); +)w2c_template" +R"w2c_template( bits = htole64(bits); +)w2c_template" +R"w2c_template( wasm_rt_memcpy(&value, &bits, sizeof(value)); +)w2c_template" +R"w2c_template( return value; +)w2c_template" +R"w2c_template(} )w2c_template" R"w2c_template(#else )w2c_template" -R"w2c_template( wasm_rt_memcpy(dest, src, n); +R"w2c_template(#define WASM_ADJUST_ENDIAN_u16(value) (value) +)w2c_template" +R"w2c_template(#define WASM_ADJUST_ENDIAN_s16(value) (value) +)w2c_template" +R"w2c_template(#define WASM_ADJUST_ENDIAN_u32(value) (value) +)w2c_template" +R"w2c_template(#define WASM_ADJUST_ENDIAN_s32(value) (value) +)w2c_template" +R"w2c_template(#define WASM_ADJUST_ENDIAN_u64(value) (value) +)w2c_template" +R"w2c_template(#define WASM_ADJUST_ENDIAN_f32(value) (value) +)w2c_template" +R"w2c_template(#define WASM_ADJUST_ENDIAN_f64(value) (value) )w2c_template" R"w2c_template(#endif )w2c_template" +R"w2c_template( +static inline void load_data(u8* dest, const u8* src, size_t n) { +)w2c_template" +R"w2c_template( if (!n) { +)w2c_template" +R"w2c_template( return; +)w2c_template" +R"w2c_template( } +)w2c_template" +R"w2c_template( wasm_rt_memcpy(dest, src, n); +)w2c_template" R"w2c_template(} )w2c_template" R"w2c_template( -#define LOAD_DATA(m, o, i, s) \ +#define LOAD_DATA(m, o, i, s) \ )w2c_template" -R"w2c_template( do { \ +R"w2c_template( do { \ )w2c_template" -R"w2c_template( RANGE_CHECK((&m), o, s); \ +R"w2c_template( RANGE_CHECK((&m), o, s); \ )w2c_template" -R"w2c_template( load_data(MEM_ADDR(&m, o, s), i, s); \ +R"w2c_template( load_data(&(m).data[o], i, s); \ )w2c_template" R"w2c_template( } while (0) )w2c_template" @@ -553,9 +563,9 @@ R"w2c_template( wasm_rt_memory_t* mem, u64 ad )w2c_template" R"w2c_template( t1 result; \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ +R"w2c_template( wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ )w2c_template" -R"w2c_template( sizeof(t1)); \ +R"w2c_template( result = WASM_ADJUST_ENDIAN_##t1(result); \ )w2c_template" R"w2c_template( t3 ret = (t3)(t2)result; \ )w2c_template" @@ -578,9 +588,9 @@ R"w2c_template( u64 addr, t2 value) { )w2c_template" R"w2c_template( t1 wrapped = (t1)value; \ )w2c_template" -R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ +R"w2c_template( wrapped = WASM_ADJUST_ENDIAN_##t1(wrapped); \ )w2c_template" -R"w2c_template( sizeof(t1)); \ +R"w2c_template( wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ )w2c_template" R"w2c_template( } \ )w2c_template" @@ -1260,7 +1270,7 @@ static inline void memory_fill(wasm_rt_memory_t* mem, u64 d, u32 val, u64 n) { )w2c_template" R"w2c_template( RANGE_CHECK(mem, d, n); )w2c_template" -R"w2c_template( memset(MEM_ADDR(mem, d, n), val, n); +R"w2c_template( memset(&mem->data[d], val, n); )w2c_template" R"w2c_template(} )w2c_template" @@ -1279,7 +1289,7 @@ R"w2c_template( RANGE_CHECK(dest, dest_addr, n); )w2c_template" R"w2c_template( RANGE_CHECK(src, src_addr, n); )w2c_template" -R"w2c_template( memmove(MEM_ADDR(dest, dest_addr, n), MEM_ADDR(src, src_addr, n), n); +R"w2c_template( memmove(&dest->data[dest_addr], &src->data[src_addr], n); )w2c_template" R"w2c_template(} )w2c_template" diff --git a/src/prebuilt/wasm2c_source_includes.cc b/src/prebuilt/wasm2c_source_includes.cc index a17c5511b7..3fa7882ae1 100644 --- a/src/prebuilt/wasm2c_source_includes.cc +++ b/src/prebuilt/wasm2c_source_includes.cc @@ -1,4 +1,46 @@ -const char* s_source_includes = R"w2c_template(#include +const char* s_source_includes = R"w2c_template(#if WABT_BIG_ENDIAN +)w2c_template" +R"w2c_template(#if __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && \ +)w2c_template" +R"w2c_template( __has_builtin(__builtin_bswap64) +)w2c_template" +R"w2c_template(#define htole16 __builtin_bswap16 +)w2c_template" +R"w2c_template(#define htole32 __builtin_bswap32 +)w2c_template" +R"w2c_template(#define htole64 __builtin_bswap64 +)w2c_template" +R"w2c_template(#elif defined(__linux__) || defined(__CYGWIN__) +)w2c_template" +R"w2c_template(#ifndef _DEFAULT_SOURCE +)w2c_template" +R"w2c_template(#define _DEFAULT_SOURCE +)w2c_template" +R"w2c_template(#endif +)w2c_template" +R"w2c_template(#include +)w2c_template" +R"w2c_template(#elif defined(__APPLE__) +)w2c_template" +R"w2c_template(#include +)w2c_template" +R"w2c_template(#define htole16(value) OSSwapHostToLittleInt16(value) +)w2c_template" +R"w2c_template(#define htole32(value) OSSwapHostToLittleInt32(value) +)w2c_template" +R"w2c_template(#define htole64(value) OSSwapHostToLittleInt64(value) +)w2c_template" +R"w2c_template(#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || \ +)w2c_template" +R"w2c_template( defined(__DragonFly__) +)w2c_template" +R"w2c_template(#include +)w2c_template" +R"w2c_template(#endif +)w2c_template" +R"w2c_template(#endif +)w2c_template" +R"w2c_template(#include )w2c_template" R"w2c_template(#include )w2c_template" @@ -30,4 +72,42 @@ R"w2c_template(#include )w2c_template" R"w2c_template(#endif )w2c_template" +R"w2c_template( +#if WABT_BIG_ENDIAN && !defined(htole16) +)w2c_template" +R"w2c_template(// Fallback for missing byteswap definitions +)w2c_template" +R"w2c_template(static inline uint16_t wasm2c_bswap16(uint16_t value) { +)w2c_template" +R"w2c_template( return (uint16_t)((value << 8) | (value >> 8)); +)w2c_template" +R"w2c_template(} +)w2c_template" +R"w2c_template( +static inline uint32_t wasm2c_bswap32(uint32_t value) { +)w2c_template" +R"w2c_template( return ((value & 0x000000ffu) << 24) | ((value & 0x0000ff00u) << 8) | +)w2c_template" +R"w2c_template( ((value & 0x00ff0000u) >> 8) | ((value & 0xff000000u) >> 24); +)w2c_template" +R"w2c_template(} +)w2c_template" +R"w2c_template( +static inline uint64_t wasm2c_bswap64(uint64_t value) { +)w2c_template" +R"w2c_template( return ((uint64_t)wasm2c_bswap32((uint32_t)value) << 32) | +)w2c_template" +R"w2c_template( wasm2c_bswap32((uint32_t)(value >> 32)); +)w2c_template" +R"w2c_template(} +)w2c_template" +R"w2c_template( +#define htole16 wasm2c_bswap16 +)w2c_template" +R"w2c_template(#define htole32 wasm2c_bswap32 +)w2c_template" +R"w2c_template(#define htole64 wasm2c_bswap64 +)w2c_template" +R"w2c_template(#endif +)w2c_template" ; diff --git a/src/template/wasm2c.declarations.c b/src/template/wasm2c.declarations.c index 19a8e85679..29469a6a1d 100644 --- a/src/template/wasm2c.declarations.c +++ b/src/template/wasm2c.declarations.c @@ -1,25 +1,3 @@ - -// Computes a pointer to an object of the given size in a little-endian memory. -// -// On a little-endian host, this is just &mem->data[addr] - the object's size is -// unused. On a big-endian host, it's &mem->data[mem->size - addr - n], where n -// is the object's size. -// -// Note that mem may be evaluated multiple times. -// -// Parameters: -// mem - The memory. -// addr - The address. -// n - The size of the object. -// -// Result: -// A pointer for an object of size n. -#if WABT_BIG_ENDIAN -#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n)) -#else -#define MEM_ADDR(mem, addr, n) &((mem)->data[addr]) -#endif - // We can only use Segue for this module if it uses a single unshared, // default-page, 32-bit imported or exported memory. #if WASM_RT_USE_SEGUE && IS_SINGLE_UNSHARED_DEFAULT32_MEMORY @@ -33,7 +11,7 @@ #endif #if WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE && WASM_RT_USE_MMAP && \ - IS_SINGLE_UNSHARED_DEFAULT32_MEMORY && !WABT_BIG_ENDIAN + IS_SINGLE_UNSHARED_DEFAULT32_MEMORY #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 1 #else #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 0 @@ -63,11 +41,11 @@ static inline void wasm_rt_segue_write_base(void* base) { wasm_rt_syscall_set_segue_base(base); } } -#define MEM_ADDR_MEMOP(mem, addr, n) ((uint8_t __seg_gs*)(uintptr_t)addr) +#define MEM_ADDR_MEMOP(mem, addr) ((uint8_t __seg_gs*)(uintptr_t)addr) #elif WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE -#define MEM_ADDR_MEMOP(mem, addr, n) (&wasm_rt_local_memory_base[(addr)]) +#define MEM_ADDR_MEMOP(mem, addr) (&wasm_rt_local_memory_base[(addr)]) #else -#define MEM_ADDR_MEMOP(mem, addr, n) MEM_ADDR(mem, addr, n) +#define MEM_ADDR_MEMOP(mem, addr) (&(mem)->data[addr]) #endif #define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) @@ -219,23 +197,50 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { "Either enable specify -DWASM_RT_NONCONFORMING_ALLOW_OOB_READ_ELIMINATION=1 during compilation or use -DWASM_RT_MEMCHECK_BOUNDS_CHECK=1 to use bounds check mode" #endif +#define WASM_ADJUST_ENDIAN_u8(value) (value) +#define WASM_ADJUST_ENDIAN_s8(value) (value) +#if WABT_BIG_ENDIAN +#define WASM_ADJUST_ENDIAN_u16 htole16 +#define WASM_ADJUST_ENDIAN_s16 htole16 +#define WASM_ADJUST_ENDIAN_u32 htole32 +#define WASM_ADJUST_ENDIAN_s32 htole32 +#define WASM_ADJUST_ENDIAN_u64 htole64 +static inline f32 WASM_ADJUST_ENDIAN_f32(f32 value) { + u32 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole32(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} + +static inline f64 WASM_ADJUST_ENDIAN_f64(f64 value) { + u64 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole64(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} +#else +#define WASM_ADJUST_ENDIAN_u16(value) (value) +#define WASM_ADJUST_ENDIAN_s16(value) (value) +#define WASM_ADJUST_ENDIAN_u32(value) (value) +#define WASM_ADJUST_ENDIAN_s32(value) (value) +#define WASM_ADJUST_ENDIAN_u64(value) (value) +#define WASM_ADJUST_ENDIAN_f32(value) (value) +#define WASM_ADJUST_ENDIAN_f64(value) (value) +#endif + static inline void load_data(u8* dest, const u8* src, size_t n) { if (!n) { return; } -#if WABT_BIG_ENDIAN - for (size_t i = 0; i < n; i++) { - dest[i] = src[n - i - 1]; - } -#else wasm_rt_memcpy(dest, src, n); -#endif } -#define LOAD_DATA(m, o, i, s) \ - do { \ - RANGE_CHECK((&m), o, s); \ - load_data(MEM_ADDR(&m, o, s), i, s); \ +#define LOAD_DATA(m, o, i, s) \ + do { \ + RANGE_CHECK((&m), o, s); \ + load_data(&(m).data[o], i, s); \ } while (0) #define DEF_MEM_CHECKS0(name, shared, mem_type, ret_kw, return_type) \ @@ -291,8 +296,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { static inline t3 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ wasm_rt_memory_t* mem, u64 addr) { \ t1 result; \ - wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ - sizeof(t1)); \ + wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ + result = WASM_ADJUST_ENDIAN_##t1(result); \ t3 ret = (t3)(t2)result; \ force_read(ret); \ return ret; \ @@ -304,8 +309,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ u64 addr, t2 value) { \ t1 wrapped = (t1)value; \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ - sizeof(t1)); \ + wrapped = WASM_ADJUST_ENDIAN_##t1(wrapped); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ } \ DEF_MEM_CHECKS1(name, _, t1, , void, t2) @@ -671,7 +676,7 @@ static float wasm_sqrtf(float x) { static inline void memory_fill(wasm_rt_memory_t* mem, u64 d, u32 val, u64 n) { RANGE_CHECK(mem, d, n); - memset(MEM_ADDR(mem, d, n), val, n); + memset(&mem->data[d], val, n); } static inline void memory_copy(wasm_rt_memory_t* dest, @@ -681,7 +686,7 @@ static inline void memory_copy(wasm_rt_memory_t* dest, u64 n) { RANGE_CHECK(dest, dest_addr, n); RANGE_CHECK(src, src_addr, n); - memmove(MEM_ADDR(dest, dest_addr, n), MEM_ADDR(src, src_addr, n), n); + memmove(&dest->data[dest_addr], &src->data[src_addr], n); } static inline void memory_init(wasm_rt_memory_t* dest, diff --git a/src/template/wasm2c.includes.c b/src/template/wasm2c.includes.c index bc5a1c9626..be3a069a24 100644 --- a/src/template/wasm2c.includes.c +++ b/src/template/wasm2c.includes.c @@ -1,3 +1,24 @@ +#if WABT_BIG_ENDIAN +#if __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && \ + __has_builtin(__builtin_bswap64) +#define htole16 __builtin_bswap16 +#define htole32 __builtin_bswap32 +#define htole64 __builtin_bswap64 +#elif defined(__linux__) || defined(__CYGWIN__) +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif +#include +#elif defined(__APPLE__) +#include +#define htole16(value) OSSwapHostToLittleInt16(value) +#define htole32(value) OSSwapHostToLittleInt32(value) +#define htole64(value) OSSwapHostToLittleInt64(value) +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || \ + defined(__DragonFly__) +#include +#endif +#endif #include #include #include @@ -14,3 +35,24 @@ #else #include #endif + +#if WABT_BIG_ENDIAN && !defined(htole16) +// Fallback for missing byteswap definitions +static inline uint16_t wasm2c_bswap16(uint16_t value) { + return (uint16_t)((value << 8) | (value >> 8)); +} + +static inline uint32_t wasm2c_bswap32(uint32_t value) { + return ((value & 0x000000ffu) << 24) | ((value & 0x0000ff00u) << 8) | + ((value & 0x00ff0000u) >> 8) | ((value & 0xff000000u) >> 24); +} + +static inline uint64_t wasm2c_bswap64(uint64_t value) { + return ((uint64_t)wasm2c_bswap32((uint32_t)value) << 32) | + wasm2c_bswap32((uint32_t)(value >> 32)); +} + +#define htole16 wasm2c_bswap16 +#define htole32 wasm2c_bswap32 +#define htole64 wasm2c_bswap64 +#endif diff --git a/src/template/wasm2c_atomicops.declarations.c b/src/template/wasm2c_atomicops.declarations.c index d3ea511f40..1188238fcc 100644 --- a/src/template/wasm2c_atomicops.declarations.c +++ b/src/template/wasm2c_atomicops.declarations.c @@ -9,63 +9,96 @@ TRAP(UNALIGNED); \ } -#define DEFINE_SHARED_LOAD(name, t1, t2, t3, force_read) \ +#if !WABT_BIG_ENDIAN +#define DEFINE_SHARED_LOAD(name, t1, atomic_type, t2, t3, force_read) \ static inline t3 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ wasm_rt_shared_memory_t* mem, u64 addr) { \ + t1 result = atomic_load_explicit((_Atomic volatile t1*)&mem->data[addr], \ + memory_order_relaxed); \ + t3 ret = (t3)(t2)result; \ + force_read(ret); \ + return ret; \ + } \ + DEF_MEM_CHECKS0(name, _shared_, t1, return, t3) +#else +// Big endian should not use atomic_load_explicit to load float* as Wasm stores +// these in little endian. Loading arbitrary values into float's may result in +// loading bytes that get interpreted as signalling nans etc. We avoid this by +// loading into an unsigned type of the same size. +#define DEFINE_SHARED_LOAD(name, t1, atomic_type, t2, t3, force_read) \ + static inline t3 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ + wasm_rt_shared_memory_t* mem, u64 addr) { \ + atomic_type raw = WASM_ADJUST_ENDIAN_##atomic_type( \ + atomic_load_explicit((_Atomic volatile atomic_type*)&mem->data[addr], \ + memory_order_relaxed)); \ t1 result; \ - result = atomic_load_explicit( \ - (_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), \ - memory_order_relaxed); \ + wasm_rt_memcpy(&result, &raw, sizeof(t1)); \ t3 ret = (t3)(t2)result; \ force_read(ret); \ return ret; \ } \ DEF_MEM_CHECKS0(name, _shared_, t1, return, t3) +#endif -DEFINE_SHARED_LOAD(i32_load_shared, u32, u32, u32, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load_shared, u64, u64, u64, FORCE_READ_INT) -DEFINE_SHARED_LOAD(f32_load_shared, f32, f32, f32, FORCE_READ_FLOAT) -DEFINE_SHARED_LOAD(f64_load_shared, f64, f64, f64, FORCE_READ_FLOAT) -DEFINE_SHARED_LOAD(i32_load8_s_shared, s8, s32, u32, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load8_s_shared, s8, s64, u64, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i32_load8_u_shared, u8, u32, u32, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load8_u_shared, u8, u64, u64, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i32_load16_s_shared, s16, s32, u32, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load16_s_shared, s16, s64, u64, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i32_load16_u_shared, u16, u32, u32, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load16_u_shared, u16, u64, u64, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load32_s_shared, s32, s64, u64, FORCE_READ_INT) -DEFINE_SHARED_LOAD(i64_load32_u_shared, u32, u64, u64, FORCE_READ_INT) +DEFINE_SHARED_LOAD(i32_load_shared, u32, u32, u32, u32, FORCE_READ_INT) +DEFINE_SHARED_LOAD(i64_load_shared, u64, u64, u64, u64, FORCE_READ_INT) +DEFINE_SHARED_LOAD(f32_load_shared, f32, u32, f32, f32, FORCE_READ_FLOAT) +DEFINE_SHARED_LOAD(f64_load_shared, f64, u64, f64, f64, FORCE_READ_FLOAT) +DEFINE_SHARED_LOAD(i32_load8_s_shared, s8, u8, s32, u32, FORCE_READ_INT) +DEFINE_SHARED_LOAD(i64_load8_s_shared, s8, u8, s64, u64, FORCE_READ_INT) +DEFINE_SHARED_LOAD(i32_load8_u_shared, u8, u8, u32, u32, FORCE_READ_INT) +DEFINE_SHARED_LOAD(i64_load8_u_shared, u8, u8, u64, u64, FORCE_READ_INT) +DEFINE_SHARED_LOAD(i32_load16_s_shared, s16, u16, s32, u32, FORCE_READ_INT) +DEFINE_SHARED_LOAD(i64_load16_s_shared, s16, u16, s64, u64, FORCE_READ_INT) +DEFINE_SHARED_LOAD(i32_load16_u_shared, u16, u16, u32, u32, FORCE_READ_INT) +DEFINE_SHARED_LOAD(i64_load16_u_shared, u16, u16, u64, u64, FORCE_READ_INT) +DEFINE_SHARED_LOAD(i64_load32_s_shared, s32, u32, s64, u64, FORCE_READ_INT) +DEFINE_SHARED_LOAD(i64_load32_u_shared, u32, u32, u64, u64, FORCE_READ_INT) -#define DEFINE_SHARED_STORE(name, t1, t2) \ +#if !WABT_BIG_ENDIAN +#define DEFINE_SHARED_STORE(name, t1, atomic_type, t2) \ + static inline void name##_unchecked( \ + uint8_t* const wasm_rt_local_memory_base, wasm_rt_shared_memory_t* mem, \ + u64 addr, t2 value) { \ + t1 wrapped = (t1)value; \ + atomic_store_explicit((_Atomic volatile t1*)&mem->data[addr], wrapped, \ + memory_order_relaxed); \ + } \ + DEF_MEM_CHECKS1(name, _shared_, t1, , void, t2) +#else +// Big endian should not use atomic_store_explicit to store float* for the same +// reason as the load +#define DEFINE_SHARED_STORE(name, t1, atomic_type, t2) \ static inline void name##_unchecked( \ uint8_t* const wasm_rt_local_memory_base, wasm_rt_shared_memory_t* mem, \ u64 addr, t2 value) { \ t1 wrapped = (t1)value; \ - atomic_store_explicit( \ - (_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), wrapped, \ - memory_order_relaxed); \ + atomic_type raw; \ + wasm_rt_memcpy(&raw, &wrapped, sizeof(t1)); \ + atomic_store_explicit((_Atomic volatile atomic_type*)&mem->data[addr], \ + WASM_ADJUST_ENDIAN_##atomic_type(raw), \ + memory_order_relaxed); \ } \ DEF_MEM_CHECKS1(name, _shared_, t1, , void, t2) +#endif -DEFINE_SHARED_STORE(i32_store_shared, u32, u32) -DEFINE_SHARED_STORE(i64_store_shared, u64, u64) -DEFINE_SHARED_STORE(f32_store_shared, f32, f32) -DEFINE_SHARED_STORE(f64_store_shared, f64, f64) -DEFINE_SHARED_STORE(i32_store8_shared, u8, u32) -DEFINE_SHARED_STORE(i32_store16_shared, u16, u32) -DEFINE_SHARED_STORE(i64_store8_shared, u8, u64) -DEFINE_SHARED_STORE(i64_store16_shared, u16, u64) -DEFINE_SHARED_STORE(i64_store32_shared, u32, u64) +DEFINE_SHARED_STORE(i32_store_shared, u32, u32, u32) +DEFINE_SHARED_STORE(i64_store_shared, u64, u64, u64) +DEFINE_SHARED_STORE(f32_store_shared, f32, u32, f32) +DEFINE_SHARED_STORE(f64_store_shared, f64, u64, f64) +DEFINE_SHARED_STORE(i32_store8_shared, u8, u8, u32) +DEFINE_SHARED_STORE(i32_store16_shared, u16, u16, u32) +DEFINE_SHARED_STORE(i64_store8_shared, u8, u8, u64) +DEFINE_SHARED_STORE(i64_store16_shared, u16, u16, u64) +DEFINE_SHARED_STORE(i64_store32_shared, u32, u32, u64) #define DEFINE_ATOMIC_LOAD(name, t1, t2, t3, force_read) \ static inline t3 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ wasm_rt_memory_t* mem, u64 addr) { \ ATOMIC_ALIGNMENT_CHECK(addr, t1); \ t1 result; \ - wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ - sizeof(t1)); \ - t3 ret = (t3)(t2)result; \ + wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ + t3 ret = (t3)(t2)WASM_ADJUST_ENDIAN_##t1(result); \ force_read(ret); \ return ret; \ } \ @@ -74,10 +107,8 @@ DEFINE_SHARED_STORE(i64_store32_shared, u32, u64) uint8_t* const wasm_rt_local_memory_base, wasm_rt_shared_memory_t* mem, \ u64 addr) { \ ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 result; \ - result = \ - atomic_load((_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1))); \ - t3 ret = (t3)(t2)result; \ + t1 result = atomic_load((_Atomic volatile t1*)&mem->data[addr]); \ + t3 ret = (t3)(t2)WASM_ADJUST_ENDIAN_##t1(result); \ force_read(ret); \ return ret; \ } \ @@ -96,18 +127,16 @@ DEFINE_ATOMIC_LOAD(i64_atomic_load32_u, u32, u64, u64, FORCE_READ_INT) uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ u64 addr, t2 value) { \ ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 wrapped = (t1)value; \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ - sizeof(t1)); \ + t1 wrapped = WASM_ADJUST_ENDIAN_##t1((t1)value); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ } \ DEF_MEM_CHECKS1(name, _, t1, , void, t2) \ static inline void name##_shared_unchecked( \ uint8_t* const wasm_rt_local_memory_base, wasm_rt_shared_memory_t* mem, \ u64 addr, t2 value) { \ ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 wrapped = (t1)value; \ - atomic_store((_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), \ - wrapped); \ + t1 wrapped = WASM_ADJUST_ENDIAN_##t1((t1)value); \ + atomic_store((_Atomic volatile t1*)&mem->data[addr], wrapped); \ } \ DEF_MEM_CHECKS1(name##_shared, _shared_, t1, , void, t2) @@ -119,6 +148,26 @@ DEFINE_ATOMIC_STORE(i64_atomic_store8, u8, u64) DEFINE_ATOMIC_STORE(i64_atomic_store16, u16, u64) DEFINE_ATOMIC_STORE(i64_atomic_store32, u32, u64) +#if WABT_BIG_ENDIAN +// Since native read-modify-write operations expect values to have the host +// endianness, we can use them. So we have to do this in multiple steps, while +// checking that the value hasn't changed in the middle. +#define WASM_RT_ATOMIC_RMW(t, ptr, value, opname, op, ret) \ + do { \ + t raw = atomic_load(ptr); \ + while (1) { \ + ret = WASM_ADJUST_ENDIAN_##t(raw); \ + t new_raw = WASM_ADJUST_ENDIAN_##t((ret)op(value)); \ + if (atomic_compare_exchange_weak(ptr, &raw, new_raw)) { \ + break; \ + } \ + } \ + } while (0) +#else +#define WASM_RT_ATOMIC_RMW(t, ptr, value, opname, op, ret) \ + ret = atomic_##opname(ptr, value) +#endif + #define DEFINE_ATOMIC_RMW(name, opname, op, t1, t2) \ static inline t2 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ wasm_rt_memory_t* mem, u64 addr, \ @@ -126,10 +175,10 @@ DEFINE_ATOMIC_STORE(i64_atomic_store32, u32, u64) ATOMIC_ALIGNMENT_CHECK(addr, t1); \ t1 wrapped = (t1)value; \ t1 ret; \ - wasm_rt_memcpy(&ret, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), sizeof(t1)); \ - t1 newval = ret op wrapped; \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &newval, \ - sizeof(t1)); \ + wasm_rt_memcpy(&ret, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ + ret = WASM_ADJUST_ENDIAN_##t1(ret); \ + t1 newval = WASM_ADJUST_ENDIAN_##t1(ret op wrapped); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &newval, sizeof(t1)); \ return (t2)ret; \ } \ DEF_MEM_CHECKS1(name, _, t1, return, t2, t2) \ @@ -138,8 +187,9 @@ DEFINE_ATOMIC_STORE(i64_atomic_store32, u32, u64) u64 addr, t2 value) { \ ATOMIC_ALIGNMENT_CHECK(addr, t1); \ t1 wrapped = (t1)value; \ - t1 ret = atomic_##opname( \ - (_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), wrapped); \ + t1 ret; \ + WASM_RT_ATOMIC_RMW(t1, (_Atomic volatile t1*)&mem->data[addr], wrapped, \ + opname, op, ret); \ return (t2)ret; \ } \ DEF_MEM_CHECKS1(name##_shared, _shared_, t1, return, t2, t2) @@ -184,28 +234,26 @@ DEFINE_ATOMIC_RMW(i64_atomic_rmw16_xor_u, fetch_xor, ^, u16, u64) DEFINE_ATOMIC_RMW(i64_atomic_rmw32_xor_u, fetch_xor, ^, u32, u64) DEFINE_ATOMIC_RMW(i64_atomic_rmw_xor, fetch_xor, ^, u64, u64) -#define DEFINE_ATOMIC_XCHG(name, opname, t1, t2) \ - static inline t2 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ - wasm_rt_memory_t* mem, u64 addr, \ - t2 value) { \ - ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 wrapped = (t1)value; \ - t1 ret; \ - wasm_rt_memcpy(&ret, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), sizeof(t1)); \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ - sizeof(t1)); \ - return (t2)ret; \ - } \ - DEF_MEM_CHECKS1(name, _, t1, return, t2, t2) \ - static inline t2 name##_shared_unchecked( \ - uint8_t* const wasm_rt_local_memory_base, wasm_rt_shared_memory_t* mem, \ - u64 addr, t2 value) { \ - ATOMIC_ALIGNMENT_CHECK(addr, t1); \ - t1 wrapped = (t1)value; \ - t1 ret = atomic_##opname( \ - (_Atomic volatile t1*)MEM_ADDR(mem, addr, sizeof(t1)), wrapped); \ - return (t2)ret; \ - } \ +#define DEFINE_ATOMIC_XCHG(name, opname, t1, t2) \ + static inline t2 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ + wasm_rt_memory_t* mem, u64 addr, \ + t2 value) { \ + ATOMIC_ALIGNMENT_CHECK(addr, t1); \ + t1 wrapped = WASM_ADJUST_ENDIAN_##t1((t1)value); \ + t1 ret; \ + wasm_rt_memcpy(&ret, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ + return (t2)WASM_ADJUST_ENDIAN_##t1(ret); \ + } \ + DEF_MEM_CHECKS1(name, _, t1, return, t2, t2) \ + static inline t2 name##_shared_unchecked( \ + uint8_t* const wasm_rt_local_memory_base, wasm_rt_shared_memory_t* mem, \ + u64 addr, t2 value) { \ + ATOMIC_ALIGNMENT_CHECK(addr, t1); \ + t1 wrapped = WASM_ADJUST_ENDIAN_##t1((t1)value); \ + t1 ret = atomic_##opname((_Atomic volatile t1*)&mem->data[addr], wrapped); \ + return (t2)WASM_ADJUST_ENDIAN_##t1(ret); \ + } \ DEF_MEM_CHECKS1(name##_shared, _shared_, t1, return, t2, t2) DEFINE_ATOMIC_XCHG(i32_atomic_rmw8_xchg_u, exchange, u8, u32) @@ -221,27 +269,26 @@ DEFINE_ATOMIC_XCHG(i64_atomic_rmw_xchg, exchange, u64, u64) wasm_rt_memory_t* mem, u64 addr, \ t1 expected, t1 replacement) { \ ATOMIC_ALIGNMENT_CHECK(addr, t2); \ - t2 expected_wrapped = (t2)expected; \ - t2 replacement_wrapped = (t2)replacement; \ + t2 expected_wrapped = WASM_ADJUST_ENDIAN_##t2((t2)expected); \ + t2 replacement_wrapped = WASM_ADJUST_ENDIAN_##t2((t2)replacement); \ t2 ret; \ - wasm_rt_memcpy(&ret, MEM_ADDR_MEMOP(mem, addr, sizeof(t2)), sizeof(t2)); \ + wasm_rt_memcpy(&ret, MEM_ADDR_MEMOP(mem, addr), sizeof(t2)); \ if (ret == expected_wrapped) { \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t2)), \ - &replacement_wrapped, sizeof(t2)); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &replacement_wrapped, \ + sizeof(t2)); \ } \ - return (t1)ret; \ + return (t1)WASM_ADJUST_ENDIAN_##t2(ret); \ } \ DEF_MEM_CHECKS2(name, _, t2, return, t1, t1, t1) \ static inline t1 name##_shared_unchecked( \ uint8_t* const wasm_rt_local_memory_base, wasm_rt_shared_memory_t* mem, \ u64 addr, t1 expected, t1 replacement) { \ ATOMIC_ALIGNMENT_CHECK(addr, t2); \ - t2 expected_wrapped = (t2)expected; \ - t2 replacement_wrapped = (t2)replacement; \ - atomic_compare_exchange_strong( \ - (_Atomic volatile t2*)MEM_ADDR(mem, addr, sizeof(t2)), \ - &expected_wrapped, replacement_wrapped); \ - return (t1)expected_wrapped; \ + t2 expected_wrapped = WASM_ADJUST_ENDIAN_##t2((t2)expected); \ + t2 replacement_wrapped = WASM_ADJUST_ENDIAN_##t2((t2)replacement); \ + atomic_compare_exchange_strong((_Atomic volatile t2*)&mem->data[addr], \ + &expected_wrapped, replacement_wrapped); \ + return (t1)WASM_ADJUST_ENDIAN_##t2(expected_wrapped); \ } \ DEF_MEM_CHECKS2(name##_shared, _shared_, t2, return, t1, t1, t1) diff --git a/src/template/wasm2c_simd.declarations.c b/src/template/wasm2c_simd.declarations.c index 0de5500e24..b6b01b1d6f 100644 --- a/src/template/wasm2c_simd.declarations.c +++ b/src/template/wasm2c_simd.declarations.c @@ -19,56 +19,70 @@ "Either enable specify -DWASM_RT_NONCONFORMING_ALLOW_OOB_READ_ELIMINATION=1 during compilation or use -DWASM_RT_MEMCHECK_BOUNDS_CHECK=1 to use bounds check mode" #endif +#if WABT_BIG_ENDIAN +static inline v128 WASM_ADJUST_ENDIAN_v128(v128 value) { + u64 input[2]; + u64 output[2]; + wasm_rt_memcpy(input, &value, sizeof(input)); + output[0] = htole64(input[1]); + output[1] = htole64(input[0]); + wasm_rt_memcpy(&value, output, sizeof(value)); + return value; +} +#else +#define WASM_ADJUST_ENDIAN_v128(value) (value) +#endif + // The below SIMD operations copy to a local variable first as the // MEM_ADDR_MEMOP maybe segment pointers if WASM_RT_USE_SEGUE_FOR_THIS_MODULE is // defined and regular pointers otherwse. memcpy into the local works correctly // in both cases. -#define DEFINE_SIMD_LOAD_FUNC(name, func, t) \ - static inline v128 name##_unchecked( \ - uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ - u64 addr) { \ - t simd_mem_value; \ - wasm_rt_memcpy(&simd_mem_value, MEM_ADDR_MEMOP(mem, addr, sizeof(t)), \ - sizeof(t)); \ - v128 result = func(&simd_mem_value); \ - SIMD_FORCE_READ(result); \ - return result; \ - } \ +#define DEFINE_SIMD_LOAD_FUNC(name, func, t) \ + static inline v128 name##_unchecked( \ + uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ + u64 addr) { \ + t simd_mem_value; \ + wasm_rt_memcpy(&simd_mem_value, MEM_ADDR_MEMOP(mem, addr), sizeof(t)); \ + simd_mem_value = WASM_ADJUST_ENDIAN_##t(simd_mem_value); \ + v128 result = func(&simd_mem_value); \ + SIMD_FORCE_READ(result); \ + return result; \ + } \ DEF_MEM_CHECKS0(name, _, t, return, v128); -#define DEFINE_SIMD_LOAD_LANE(name, func, t, lane) \ - static inline v128 name##_unchecked( \ - uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ - u64 addr, v128 vec) { \ - t simd_mem_value; \ - wasm_rt_memcpy(&simd_mem_value, MEM_ADDR_MEMOP(mem, addr, sizeof(t)), \ - sizeof(t)); \ - v128 result = func(&simd_mem_value, vec, lane); \ - SIMD_FORCE_READ(result); \ - return result; \ - } \ +#define DEFINE_SIMD_LOAD_LANE(name, func, t, lane) \ + static inline v128 name##_unchecked( \ + uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ + u64 addr, v128 vec) { \ + t simd_mem_value; \ + wasm_rt_memcpy(&simd_mem_value, MEM_ADDR_MEMOP(mem, addr), sizeof(t)); \ + simd_mem_value = WASM_ADJUST_ENDIAN_##t(simd_mem_value); \ + v128 result = func(&simd_mem_value, vec, lane); \ + SIMD_FORCE_READ(result); \ + return result; \ + } \ DEF_MEM_CHECKS1(name, _, t, return, v128, v128); -#define DEFINE_SIMD_STORE(name, t) \ - static inline void name##_unchecked( \ - uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ - u64 addr, v128 value) { \ - t simd_mem_value; \ - simde_wasm_v128_store(&simd_mem_value, value); \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t)), &simd_mem_value, \ - sizeof(t)); \ - } \ +#define DEFINE_SIMD_STORE(name, t) \ + static inline void name##_unchecked( \ + uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ + u64 addr, v128 value) { \ + t simd_mem_value; \ + simde_wasm_v128_store(&simd_mem_value, value); \ + simd_mem_value = WASM_ADJUST_ENDIAN_##t(simd_mem_value); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &simd_mem_value, sizeof(t)); \ + } \ DEF_MEM_CHECKS1(name, _, t, , void, v128); -#define DEFINE_SIMD_STORE_LANE(name, func, t, lane) \ - static inline void name##_unchecked( \ - uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ - u64 addr, v128 value) { \ - t simd_mem_value; \ - func(&simd_mem_value, value, lane); \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t)), &simd_mem_value, \ - sizeof(t)); \ - } \ +#define DEFINE_SIMD_STORE_LANE(name, func, t, lane) \ + static inline void name##_unchecked( \ + uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ + u64 addr, v128 value) { \ + t simd_mem_value; \ + func(&simd_mem_value, value, lane); \ + simd_mem_value = WASM_ADJUST_ENDIAN_##t(simd_mem_value); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &simd_mem_value, sizeof(t)); \ + } \ DEF_MEM_CHECKS1(name, _, t, , void, v128); // clang-format off diff --git a/test/wasm2c/add.txt b/test/wasm2c/add.txt index f55b5a3f1c..dbcd360076 100644 --- a/test/wasm2c/add.txt +++ b/test/wasm2c/add.txt @@ -47,6 +47,27 @@ u32 w2c_test_add(w2c_test*, u32, u32); #endif /* WASM_H_GENERATED_ */ /* Automatically generated by wasm2c */ +#if WABT_BIG_ENDIAN +#if __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && \ + __has_builtin(__builtin_bswap64) +#define htole16 __builtin_bswap16 +#define htole32 __builtin_bswap32 +#define htole64 __builtin_bswap64 +#elif defined(__linux__) || defined(__CYGWIN__) +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif +#include +#elif defined(__APPLE__) +#include +#define htole16(value) OSSwapHostToLittleInt16(value) +#define htole32(value) OSSwapHostToLittleInt32(value) +#define htole64(value) OSSwapHostToLittleInt64(value) +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || \ + defined(__DragonFly__) +#include +#endif +#endif #include #include #include @@ -64,29 +85,28 @@ u32 w2c_test_add(w2c_test*, u32, u32); #include #endif -#include "wasm.h" +#if WABT_BIG_ENDIAN && !defined(htole16) +// Fallback for missing byteswap definitions +static inline uint16_t wasm2c_bswap16(uint16_t value) { + return (uint16_t)((value << 8) | (value >> 8)); +} -// Computes a pointer to an object of the given size in a little-endian memory. -// -// On a little-endian host, this is just &mem->data[addr] - the object's size is -// unused. On a big-endian host, it's &mem->data[mem->size - addr - n], where n -// is the object's size. -// -// Note that mem may be evaluated multiple times. -// -// Parameters: -// mem - The memory. -// addr - The address. -// n - The size of the object. -// -// Result: -// A pointer for an object of size n. -#if WABT_BIG_ENDIAN -#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n)) -#else -#define MEM_ADDR(mem, addr, n) &((mem)->data[addr]) +static inline uint32_t wasm2c_bswap32(uint32_t value) { + return ((value & 0x000000ffu) << 24) | ((value & 0x0000ff00u) << 8) | + ((value & 0x00ff0000u) >> 8) | ((value & 0xff000000u) >> 24); +} + +static inline uint64_t wasm2c_bswap64(uint64_t value) { + return ((uint64_t)wasm2c_bswap32((uint32_t)value) << 32) | + wasm2c_bswap32((uint32_t)(value >> 32)); +} + +#define htole16 wasm2c_bswap16 +#define htole32 wasm2c_bswap32 +#define htole64 wasm2c_bswap64 #endif +#include "wasm.h" // We can only use Segue for this module if it uses a single unshared, // default-page, 32-bit imported or exported memory. #if WASM_RT_USE_SEGUE && IS_SINGLE_UNSHARED_DEFAULT32_MEMORY @@ -100,7 +120,7 @@ u32 w2c_test_add(w2c_test*, u32, u32); #endif #if WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE && WASM_RT_USE_MMAP && \ - IS_SINGLE_UNSHARED_DEFAULT32_MEMORY && !WABT_BIG_ENDIAN + IS_SINGLE_UNSHARED_DEFAULT32_MEMORY #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 1 #else #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 0 @@ -130,11 +150,11 @@ static inline void wasm_rt_segue_write_base(void* base) { wasm_rt_syscall_set_segue_base(base); } } -#define MEM_ADDR_MEMOP(mem, addr, n) ((uint8_t __seg_gs*)(uintptr_t)addr) +#define MEM_ADDR_MEMOP(mem, addr) ((uint8_t __seg_gs*)(uintptr_t)addr) #elif WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE -#define MEM_ADDR_MEMOP(mem, addr, n) (&wasm_rt_local_memory_base[(addr)]) +#define MEM_ADDR_MEMOP(mem, addr) (&wasm_rt_local_memory_base[(addr)]) #else -#define MEM_ADDR_MEMOP(mem, addr, n) MEM_ADDR(mem, addr, n) +#define MEM_ADDR_MEMOP(mem, addr) (&(mem)->data[addr]) #endif #define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) @@ -286,23 +306,50 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { "Either enable specify -DWASM_RT_NONCONFORMING_ALLOW_OOB_READ_ELIMINATION=1 during compilation or use -DWASM_RT_MEMCHECK_BOUNDS_CHECK=1 to use bounds check mode" #endif +#define WASM_ADJUST_ENDIAN_u8(value) (value) +#define WASM_ADJUST_ENDIAN_s8(value) (value) +#if WABT_BIG_ENDIAN +#define WASM_ADJUST_ENDIAN_u16 htole16 +#define WASM_ADJUST_ENDIAN_s16 htole16 +#define WASM_ADJUST_ENDIAN_u32 htole32 +#define WASM_ADJUST_ENDIAN_s32 htole32 +#define WASM_ADJUST_ENDIAN_u64 htole64 +static inline f32 WASM_ADJUST_ENDIAN_f32(f32 value) { + u32 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole32(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} + +static inline f64 WASM_ADJUST_ENDIAN_f64(f64 value) { + u64 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole64(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} +#else +#define WASM_ADJUST_ENDIAN_u16(value) (value) +#define WASM_ADJUST_ENDIAN_s16(value) (value) +#define WASM_ADJUST_ENDIAN_u32(value) (value) +#define WASM_ADJUST_ENDIAN_s32(value) (value) +#define WASM_ADJUST_ENDIAN_u64(value) (value) +#define WASM_ADJUST_ENDIAN_f32(value) (value) +#define WASM_ADJUST_ENDIAN_f64(value) (value) +#endif + static inline void load_data(u8* dest, const u8* src, size_t n) { if (!n) { return; } -#if WABT_BIG_ENDIAN - for (size_t i = 0; i < n; i++) { - dest[i] = src[n - i - 1]; - } -#else wasm_rt_memcpy(dest, src, n); -#endif } -#define LOAD_DATA(m, o, i, s) \ - do { \ - RANGE_CHECK((&m), o, s); \ - load_data(MEM_ADDR(&m, o, s), i, s); \ +#define LOAD_DATA(m, o, i, s) \ + do { \ + RANGE_CHECK((&m), o, s); \ + load_data(&(m).data[o], i, s); \ } while (0) #define DEF_MEM_CHECKS0(name, shared, mem_type, ret_kw, return_type) \ @@ -358,8 +405,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { static inline t3 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ wasm_rt_memory_t* mem, u64 addr) { \ t1 result; \ - wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ - sizeof(t1)); \ + wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ + result = WASM_ADJUST_ENDIAN_##t1(result); \ t3 ret = (t3)(t2)result; \ force_read(ret); \ return ret; \ @@ -371,8 +418,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ u64 addr, t2 value) { \ t1 wrapped = (t1)value; \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ - sizeof(t1)); \ + wrapped = WASM_ADJUST_ENDIAN_##t1(wrapped); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ } \ DEF_MEM_CHECKS1(name, _, t1, , void, t2) @@ -738,7 +785,7 @@ static float wasm_sqrtf(float x) { static inline void memory_fill(wasm_rt_memory_t* mem, u64 d, u32 val, u64 n) { RANGE_CHECK(mem, d, n); - memset(MEM_ADDR(mem, d, n), val, n); + memset(&mem->data[d], val, n); } static inline void memory_copy(wasm_rt_memory_t* dest, @@ -748,7 +795,7 @@ static inline void memory_copy(wasm_rt_memory_t* dest, u64 n) { RANGE_CHECK(dest, dest_addr, n); RANGE_CHECK(src, src_addr, n); - memmove(MEM_ADDR(dest, dest_addr, n), MEM_ADDR(src, src_addr, n), n); + memmove(&dest->data[dest_addr], &src->data[src_addr], n); } static inline void memory_init(wasm_rt_memory_t* dest, @@ -892,6 +939,7 @@ DEFINE_TABLE_FILL(externref) wasm_rt_tailcallee_t* next) #endif + static u32 w2c_test_add_0(w2c_test*, u32, u32); FUNC_TYPE_T(w2c_test_t0) = "\x92\xfb\x6a\xdf\x49\x07\x0a\x83\xbe\x08\x02\x68\xcd\xf6\x95\x27\x4a\xc2\xf3\xe5\xe4\x7d\x29\x49\xe8\xed\x42\x92\x6a\x9d\xda\xf0"; diff --git a/test/wasm2c/check-imports.txt b/test/wasm2c/check-imports.txt index eadb8066ae..7d6aba16e2 100644 --- a/test/wasm2c/check-imports.txt +++ b/test/wasm2c/check-imports.txt @@ -71,6 +71,27 @@ extern const u32 wasm2c_test_pagesize_env_0x5F_linear_memory; #endif /* WASM_H_GENERATED_ */ /* Automatically generated by wasm2c */ +#if WABT_BIG_ENDIAN +#if __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && \ + __has_builtin(__builtin_bswap64) +#define htole16 __builtin_bswap16 +#define htole32 __builtin_bswap32 +#define htole64 __builtin_bswap64 +#elif defined(__linux__) || defined(__CYGWIN__) +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif +#include +#elif defined(__APPLE__) +#include +#define htole16(value) OSSwapHostToLittleInt16(value) +#define htole32(value) OSSwapHostToLittleInt32(value) +#define htole64(value) OSSwapHostToLittleInt64(value) +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || \ + defined(__DragonFly__) +#include +#endif +#endif #include #include #include @@ -88,30 +109,29 @@ extern const u32 wasm2c_test_pagesize_env_0x5F_linear_memory; #include #endif -#include "wasm.h" -#define IS_SINGLE_UNSHARED_DEFAULT32_MEMORY 1 +#if WABT_BIG_ENDIAN && !defined(htole16) +// Fallback for missing byteswap definitions +static inline uint16_t wasm2c_bswap16(uint16_t value) { + return (uint16_t)((value << 8) | (value >> 8)); +} -// Computes a pointer to an object of the given size in a little-endian memory. -// -// On a little-endian host, this is just &mem->data[addr] - the object's size is -// unused. On a big-endian host, it's &mem->data[mem->size - addr - n], where n -// is the object's size. -// -// Note that mem may be evaluated multiple times. -// -// Parameters: -// mem - The memory. -// addr - The address. -// n - The size of the object. -// -// Result: -// A pointer for an object of size n. -#if WABT_BIG_ENDIAN -#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n)) -#else -#define MEM_ADDR(mem, addr, n) &((mem)->data[addr]) +static inline uint32_t wasm2c_bswap32(uint32_t value) { + return ((value & 0x000000ffu) << 24) | ((value & 0x0000ff00u) << 8) | + ((value & 0x00ff0000u) >> 8) | ((value & 0xff000000u) >> 24); +} + +static inline uint64_t wasm2c_bswap64(uint64_t value) { + return ((uint64_t)wasm2c_bswap32((uint32_t)value) << 32) | + wasm2c_bswap32((uint32_t)(value >> 32)); +} + +#define htole16 wasm2c_bswap16 +#define htole32 wasm2c_bswap32 +#define htole64 wasm2c_bswap64 #endif +#include "wasm.h" +#define IS_SINGLE_UNSHARED_DEFAULT32_MEMORY 1 // We can only use Segue for this module if it uses a single unshared, // default-page, 32-bit imported or exported memory. #if WASM_RT_USE_SEGUE && IS_SINGLE_UNSHARED_DEFAULT32_MEMORY @@ -125,7 +145,7 @@ extern const u32 wasm2c_test_pagesize_env_0x5F_linear_memory; #endif #if WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE && WASM_RT_USE_MMAP && \ - IS_SINGLE_UNSHARED_DEFAULT32_MEMORY && !WABT_BIG_ENDIAN + IS_SINGLE_UNSHARED_DEFAULT32_MEMORY #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 1 #else #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 0 @@ -155,11 +175,11 @@ static inline void wasm_rt_segue_write_base(void* base) { wasm_rt_syscall_set_segue_base(base); } } -#define MEM_ADDR_MEMOP(mem, addr, n) ((uint8_t __seg_gs*)(uintptr_t)addr) +#define MEM_ADDR_MEMOP(mem, addr) ((uint8_t __seg_gs*)(uintptr_t)addr) #elif WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE -#define MEM_ADDR_MEMOP(mem, addr, n) (&wasm_rt_local_memory_base[(addr)]) +#define MEM_ADDR_MEMOP(mem, addr) (&wasm_rt_local_memory_base[(addr)]) #else -#define MEM_ADDR_MEMOP(mem, addr, n) MEM_ADDR(mem, addr, n) +#define MEM_ADDR_MEMOP(mem, addr) (&(mem)->data[addr]) #endif #define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) @@ -311,23 +331,50 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { "Either enable specify -DWASM_RT_NONCONFORMING_ALLOW_OOB_READ_ELIMINATION=1 during compilation or use -DWASM_RT_MEMCHECK_BOUNDS_CHECK=1 to use bounds check mode" #endif +#define WASM_ADJUST_ENDIAN_u8(value) (value) +#define WASM_ADJUST_ENDIAN_s8(value) (value) +#if WABT_BIG_ENDIAN +#define WASM_ADJUST_ENDIAN_u16 htole16 +#define WASM_ADJUST_ENDIAN_s16 htole16 +#define WASM_ADJUST_ENDIAN_u32 htole32 +#define WASM_ADJUST_ENDIAN_s32 htole32 +#define WASM_ADJUST_ENDIAN_u64 htole64 +static inline f32 WASM_ADJUST_ENDIAN_f32(f32 value) { + u32 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole32(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} + +static inline f64 WASM_ADJUST_ENDIAN_f64(f64 value) { + u64 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole64(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} +#else +#define WASM_ADJUST_ENDIAN_u16(value) (value) +#define WASM_ADJUST_ENDIAN_s16(value) (value) +#define WASM_ADJUST_ENDIAN_u32(value) (value) +#define WASM_ADJUST_ENDIAN_s32(value) (value) +#define WASM_ADJUST_ENDIAN_u64(value) (value) +#define WASM_ADJUST_ENDIAN_f32(value) (value) +#define WASM_ADJUST_ENDIAN_f64(value) (value) +#endif + static inline void load_data(u8* dest, const u8* src, size_t n) { if (!n) { return; } -#if WABT_BIG_ENDIAN - for (size_t i = 0; i < n; i++) { - dest[i] = src[n - i - 1]; - } -#else wasm_rt_memcpy(dest, src, n); -#endif } -#define LOAD_DATA(m, o, i, s) \ - do { \ - RANGE_CHECK((&m), o, s); \ - load_data(MEM_ADDR(&m, o, s), i, s); \ +#define LOAD_DATA(m, o, i, s) \ + do { \ + RANGE_CHECK((&m), o, s); \ + load_data(&(m).data[o], i, s); \ } while (0) #define DEF_MEM_CHECKS0(name, shared, mem_type, ret_kw, return_type) \ @@ -383,8 +430,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { static inline t3 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ wasm_rt_memory_t* mem, u64 addr) { \ t1 result; \ - wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ - sizeof(t1)); \ + wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ + result = WASM_ADJUST_ENDIAN_##t1(result); \ t3 ret = (t3)(t2)result; \ force_read(ret); \ return ret; \ @@ -396,8 +443,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ u64 addr, t2 value) { \ t1 wrapped = (t1)value; \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ - sizeof(t1)); \ + wrapped = WASM_ADJUST_ENDIAN_##t1(wrapped); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ } \ DEF_MEM_CHECKS1(name, _, t1, , void, t2) @@ -763,7 +810,7 @@ static float wasm_sqrtf(float x) { static inline void memory_fill(wasm_rt_memory_t* mem, u64 d, u32 val, u64 n) { RANGE_CHECK(mem, d, n); - memset(MEM_ADDR(mem, d, n), val, n); + memset(&mem->data[d], val, n); } static inline void memory_copy(wasm_rt_memory_t* dest, @@ -773,7 +820,7 @@ static inline void memory_copy(wasm_rt_memory_t* dest, u64 n) { RANGE_CHECK(dest, dest_addr, n); RANGE_CHECK(src, src_addr, n); - memmove(MEM_ADDR(dest, dest_addr, n), MEM_ADDR(src, src_addr, n), n); + memmove(&dest->data[dest_addr], &src->data[src_addr], n); } static inline void memory_init(wasm_rt_memory_t* dest, @@ -917,6 +964,7 @@ DEFINE_TABLE_FILL(externref) wasm_rt_tailcallee_t* next) #endif + static u32 w2c_test_f0(w2c_test*, u32); static u32 w2c_test_f1(w2c_test*); static u32 w2c_test_f2(w2c_test*, u32, u32); diff --git a/test/wasm2c/export-names.txt b/test/wasm2c/export-names.txt index 1b4a62469b..9fb5957e3a 100644 --- a/test/wasm2c/export-names.txt +++ b/test/wasm2c/export-names.txt @@ -71,6 +71,27 @@ void w2c_test_0xE20x9D0xA40xEF0xB80x8F(w2c_test*); #endif /* WASM_H_GENERATED_ */ /* Automatically generated by wasm2c */ +#if WABT_BIG_ENDIAN +#if __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && \ + __has_builtin(__builtin_bswap64) +#define htole16 __builtin_bswap16 +#define htole32 __builtin_bswap32 +#define htole64 __builtin_bswap64 +#elif defined(__linux__) || defined(__CYGWIN__) +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif +#include +#elif defined(__APPLE__) +#include +#define htole16(value) OSSwapHostToLittleInt16(value) +#define htole32(value) OSSwapHostToLittleInt32(value) +#define htole64(value) OSSwapHostToLittleInt64(value) +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || \ + defined(__DragonFly__) +#include +#endif +#endif #include #include #include @@ -88,30 +109,29 @@ void w2c_test_0xE20x9D0xA40xEF0xB80x8F(w2c_test*); #include #endif -#include "wasm.h" -#define IS_SINGLE_UNSHARED_DEFAULT32_MEMORY 1 +#if WABT_BIG_ENDIAN && !defined(htole16) +// Fallback for missing byteswap definitions +static inline uint16_t wasm2c_bswap16(uint16_t value) { + return (uint16_t)((value << 8) | (value >> 8)); +} -// Computes a pointer to an object of the given size in a little-endian memory. -// -// On a little-endian host, this is just &mem->data[addr] - the object's size is -// unused. On a big-endian host, it's &mem->data[mem->size - addr - n], where n -// is the object's size. -// -// Note that mem may be evaluated multiple times. -// -// Parameters: -// mem - The memory. -// addr - The address. -// n - The size of the object. -// -// Result: -// A pointer for an object of size n. -#if WABT_BIG_ENDIAN -#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n)) -#else -#define MEM_ADDR(mem, addr, n) &((mem)->data[addr]) +static inline uint32_t wasm2c_bswap32(uint32_t value) { + return ((value & 0x000000ffu) << 24) | ((value & 0x0000ff00u) << 8) | + ((value & 0x00ff0000u) >> 8) | ((value & 0xff000000u) >> 24); +} + +static inline uint64_t wasm2c_bswap64(uint64_t value) { + return ((uint64_t)wasm2c_bswap32((uint32_t)value) << 32) | + wasm2c_bswap32((uint32_t)(value >> 32)); +} + +#define htole16 wasm2c_bswap16 +#define htole32 wasm2c_bswap32 +#define htole64 wasm2c_bswap64 #endif +#include "wasm.h" +#define IS_SINGLE_UNSHARED_DEFAULT32_MEMORY 1 // We can only use Segue for this module if it uses a single unshared, // default-page, 32-bit imported or exported memory. #if WASM_RT_USE_SEGUE && IS_SINGLE_UNSHARED_DEFAULT32_MEMORY @@ -125,7 +145,7 @@ void w2c_test_0xE20x9D0xA40xEF0xB80x8F(w2c_test*); #endif #if WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE && WASM_RT_USE_MMAP && \ - IS_SINGLE_UNSHARED_DEFAULT32_MEMORY && !WABT_BIG_ENDIAN + IS_SINGLE_UNSHARED_DEFAULT32_MEMORY #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 1 #else #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 0 @@ -155,11 +175,11 @@ static inline void wasm_rt_segue_write_base(void* base) { wasm_rt_syscall_set_segue_base(base); } } -#define MEM_ADDR_MEMOP(mem, addr, n) ((uint8_t __seg_gs*)(uintptr_t)addr) +#define MEM_ADDR_MEMOP(mem, addr) ((uint8_t __seg_gs*)(uintptr_t)addr) #elif WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE -#define MEM_ADDR_MEMOP(mem, addr, n) (&wasm_rt_local_memory_base[(addr)]) +#define MEM_ADDR_MEMOP(mem, addr) (&wasm_rt_local_memory_base[(addr)]) #else -#define MEM_ADDR_MEMOP(mem, addr, n) MEM_ADDR(mem, addr, n) +#define MEM_ADDR_MEMOP(mem, addr) (&(mem)->data[addr]) #endif #define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) @@ -311,23 +331,50 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { "Either enable specify -DWASM_RT_NONCONFORMING_ALLOW_OOB_READ_ELIMINATION=1 during compilation or use -DWASM_RT_MEMCHECK_BOUNDS_CHECK=1 to use bounds check mode" #endif +#define WASM_ADJUST_ENDIAN_u8(value) (value) +#define WASM_ADJUST_ENDIAN_s8(value) (value) +#if WABT_BIG_ENDIAN +#define WASM_ADJUST_ENDIAN_u16 htole16 +#define WASM_ADJUST_ENDIAN_s16 htole16 +#define WASM_ADJUST_ENDIAN_u32 htole32 +#define WASM_ADJUST_ENDIAN_s32 htole32 +#define WASM_ADJUST_ENDIAN_u64 htole64 +static inline f32 WASM_ADJUST_ENDIAN_f32(f32 value) { + u32 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole32(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} + +static inline f64 WASM_ADJUST_ENDIAN_f64(f64 value) { + u64 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole64(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} +#else +#define WASM_ADJUST_ENDIAN_u16(value) (value) +#define WASM_ADJUST_ENDIAN_s16(value) (value) +#define WASM_ADJUST_ENDIAN_u32(value) (value) +#define WASM_ADJUST_ENDIAN_s32(value) (value) +#define WASM_ADJUST_ENDIAN_u64(value) (value) +#define WASM_ADJUST_ENDIAN_f32(value) (value) +#define WASM_ADJUST_ENDIAN_f64(value) (value) +#endif + static inline void load_data(u8* dest, const u8* src, size_t n) { if (!n) { return; } -#if WABT_BIG_ENDIAN - for (size_t i = 0; i < n; i++) { - dest[i] = src[n - i - 1]; - } -#else wasm_rt_memcpy(dest, src, n); -#endif } -#define LOAD_DATA(m, o, i, s) \ - do { \ - RANGE_CHECK((&m), o, s); \ - load_data(MEM_ADDR(&m, o, s), i, s); \ +#define LOAD_DATA(m, o, i, s) \ + do { \ + RANGE_CHECK((&m), o, s); \ + load_data(&(m).data[o], i, s); \ } while (0) #define DEF_MEM_CHECKS0(name, shared, mem_type, ret_kw, return_type) \ @@ -383,8 +430,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { static inline t3 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ wasm_rt_memory_t* mem, u64 addr) { \ t1 result; \ - wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ - sizeof(t1)); \ + wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ + result = WASM_ADJUST_ENDIAN_##t1(result); \ t3 ret = (t3)(t2)result; \ force_read(ret); \ return ret; \ @@ -396,8 +443,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ u64 addr, t2 value) { \ t1 wrapped = (t1)value; \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ - sizeof(t1)); \ + wrapped = WASM_ADJUST_ENDIAN_##t1(wrapped); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ } \ DEF_MEM_CHECKS1(name, _, t1, , void, t2) @@ -763,7 +810,7 @@ static float wasm_sqrtf(float x) { static inline void memory_fill(wasm_rt_memory_t* mem, u64 d, u32 val, u64 n) { RANGE_CHECK(mem, d, n); - memset(MEM_ADDR(mem, d, n), val, n); + memset(&mem->data[d], val, n); } static inline void memory_copy(wasm_rt_memory_t* dest, @@ -773,7 +820,7 @@ static inline void memory_copy(wasm_rt_memory_t* dest, u64 n) { RANGE_CHECK(dest, dest_addr, n); RANGE_CHECK(src, src_addr, n); - memmove(MEM_ADDR(dest, dest_addr, n), MEM_ADDR(src, src_addr, n), n); + memmove(&dest->data[dest_addr], &src->data[src_addr], n); } static inline void memory_init(wasm_rt_memory_t* dest, @@ -917,6 +964,7 @@ DEFINE_TABLE_FILL(externref) wasm_rt_tailcallee_t* next) #endif + static void w2c_test_0x2A0x2F_0(w2c_test*); FUNC_TYPE_T(w2c_test_t0) = "\x36\xa9\xe7\xf1\xc9\x5b\x82\xff\xb9\x97\x43\xe0\xc5\xc4\xce\x95\xd8\x3c\x9a\x43\x0a\xac\x59\xf8\x4e\xf3\xcb\xfa\xb6\x14\x50\x68"; diff --git a/test/wasm2c/hello.txt b/test/wasm2c/hello.txt index 19cfe580d4..72924d9635 100644 --- a/test/wasm2c/hello.txt +++ b/test/wasm2c/hello.txt @@ -80,6 +80,27 @@ void w2c_test_0x5Fstart(w2c_test*); #endif /* WASM_H_GENERATED_ */ /* Automatically generated by wasm2c */ +#if WABT_BIG_ENDIAN +#if __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && \ + __has_builtin(__builtin_bswap64) +#define htole16 __builtin_bswap16 +#define htole32 __builtin_bswap32 +#define htole64 __builtin_bswap64 +#elif defined(__linux__) || defined(__CYGWIN__) +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif +#include +#elif defined(__APPLE__) +#include +#define htole16(value) OSSwapHostToLittleInt16(value) +#define htole32(value) OSSwapHostToLittleInt32(value) +#define htole64(value) OSSwapHostToLittleInt64(value) +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || \ + defined(__DragonFly__) +#include +#endif +#endif #include #include #include @@ -97,30 +118,29 @@ void w2c_test_0x5Fstart(w2c_test*); #include #endif -#include "wasm.h" -#define IS_SINGLE_UNSHARED_DEFAULT32_MEMORY 1 +#if WABT_BIG_ENDIAN && !defined(htole16) +// Fallback for missing byteswap definitions +static inline uint16_t wasm2c_bswap16(uint16_t value) { + return (uint16_t)((value << 8) | (value >> 8)); +} -// Computes a pointer to an object of the given size in a little-endian memory. -// -// On a little-endian host, this is just &mem->data[addr] - the object's size is -// unused. On a big-endian host, it's &mem->data[mem->size - addr - n], where n -// is the object's size. -// -// Note that mem may be evaluated multiple times. -// -// Parameters: -// mem - The memory. -// addr - The address. -// n - The size of the object. -// -// Result: -// A pointer for an object of size n. -#if WABT_BIG_ENDIAN -#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n)) -#else -#define MEM_ADDR(mem, addr, n) &((mem)->data[addr]) +static inline uint32_t wasm2c_bswap32(uint32_t value) { + return ((value & 0x000000ffu) << 24) | ((value & 0x0000ff00u) << 8) | + ((value & 0x00ff0000u) >> 8) | ((value & 0xff000000u) >> 24); +} + +static inline uint64_t wasm2c_bswap64(uint64_t value) { + return ((uint64_t)wasm2c_bswap32((uint32_t)value) << 32) | + wasm2c_bswap32((uint32_t)(value >> 32)); +} + +#define htole16 wasm2c_bswap16 +#define htole32 wasm2c_bswap32 +#define htole64 wasm2c_bswap64 #endif +#include "wasm.h" +#define IS_SINGLE_UNSHARED_DEFAULT32_MEMORY 1 // We can only use Segue for this module if it uses a single unshared, // default-page, 32-bit imported or exported memory. #if WASM_RT_USE_SEGUE && IS_SINGLE_UNSHARED_DEFAULT32_MEMORY @@ -134,7 +154,7 @@ void w2c_test_0x5Fstart(w2c_test*); #endif #if WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE && WASM_RT_USE_MMAP && \ - IS_SINGLE_UNSHARED_DEFAULT32_MEMORY && !WABT_BIG_ENDIAN + IS_SINGLE_UNSHARED_DEFAULT32_MEMORY #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 1 #else #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 0 @@ -164,11 +184,11 @@ static inline void wasm_rt_segue_write_base(void* base) { wasm_rt_syscall_set_segue_base(base); } } -#define MEM_ADDR_MEMOP(mem, addr, n) ((uint8_t __seg_gs*)(uintptr_t)addr) +#define MEM_ADDR_MEMOP(mem, addr) ((uint8_t __seg_gs*)(uintptr_t)addr) #elif WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE -#define MEM_ADDR_MEMOP(mem, addr, n) (&wasm_rt_local_memory_base[(addr)]) +#define MEM_ADDR_MEMOP(mem, addr) (&wasm_rt_local_memory_base[(addr)]) #else -#define MEM_ADDR_MEMOP(mem, addr, n) MEM_ADDR(mem, addr, n) +#define MEM_ADDR_MEMOP(mem, addr) (&(mem)->data[addr]) #endif #define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) @@ -320,23 +340,50 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { "Either enable specify -DWASM_RT_NONCONFORMING_ALLOW_OOB_READ_ELIMINATION=1 during compilation or use -DWASM_RT_MEMCHECK_BOUNDS_CHECK=1 to use bounds check mode" #endif +#define WASM_ADJUST_ENDIAN_u8(value) (value) +#define WASM_ADJUST_ENDIAN_s8(value) (value) +#if WABT_BIG_ENDIAN +#define WASM_ADJUST_ENDIAN_u16 htole16 +#define WASM_ADJUST_ENDIAN_s16 htole16 +#define WASM_ADJUST_ENDIAN_u32 htole32 +#define WASM_ADJUST_ENDIAN_s32 htole32 +#define WASM_ADJUST_ENDIAN_u64 htole64 +static inline f32 WASM_ADJUST_ENDIAN_f32(f32 value) { + u32 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole32(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} + +static inline f64 WASM_ADJUST_ENDIAN_f64(f64 value) { + u64 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole64(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} +#else +#define WASM_ADJUST_ENDIAN_u16(value) (value) +#define WASM_ADJUST_ENDIAN_s16(value) (value) +#define WASM_ADJUST_ENDIAN_u32(value) (value) +#define WASM_ADJUST_ENDIAN_s32(value) (value) +#define WASM_ADJUST_ENDIAN_u64(value) (value) +#define WASM_ADJUST_ENDIAN_f32(value) (value) +#define WASM_ADJUST_ENDIAN_f64(value) (value) +#endif + static inline void load_data(u8* dest, const u8* src, size_t n) { if (!n) { return; } -#if WABT_BIG_ENDIAN - for (size_t i = 0; i < n; i++) { - dest[i] = src[n - i - 1]; - } -#else wasm_rt_memcpy(dest, src, n); -#endif } -#define LOAD_DATA(m, o, i, s) \ - do { \ - RANGE_CHECK((&m), o, s); \ - load_data(MEM_ADDR(&m, o, s), i, s); \ +#define LOAD_DATA(m, o, i, s) \ + do { \ + RANGE_CHECK((&m), o, s); \ + load_data(&(m).data[o], i, s); \ } while (0) #define DEF_MEM_CHECKS0(name, shared, mem_type, ret_kw, return_type) \ @@ -392,8 +439,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { static inline t3 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ wasm_rt_memory_t* mem, u64 addr) { \ t1 result; \ - wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ - sizeof(t1)); \ + wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ + result = WASM_ADJUST_ENDIAN_##t1(result); \ t3 ret = (t3)(t2)result; \ force_read(ret); \ return ret; \ @@ -405,8 +452,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ u64 addr, t2 value) { \ t1 wrapped = (t1)value; \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ - sizeof(t1)); \ + wrapped = WASM_ADJUST_ENDIAN_##t1(wrapped); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ } \ DEF_MEM_CHECKS1(name, _, t1, , void, t2) @@ -772,7 +819,7 @@ static float wasm_sqrtf(float x) { static inline void memory_fill(wasm_rt_memory_t* mem, u64 d, u32 val, u64 n) { RANGE_CHECK(mem, d, n); - memset(MEM_ADDR(mem, d, n), val, n); + memset(&mem->data[d], val, n); } static inline void memory_copy(wasm_rt_memory_t* dest, @@ -782,7 +829,7 @@ static inline void memory_copy(wasm_rt_memory_t* dest, u64 n) { RANGE_CHECK(dest, dest_addr, n); RANGE_CHECK(src, src_addr, n); - memmove(MEM_ADDR(dest, dest_addr, n), MEM_ADDR(src, src_addr, n), n); + memmove(&dest->data[dest_addr], &src->data[src_addr], n); } static inline void memory_init(wasm_rt_memory_t* dest, @@ -926,6 +973,7 @@ DEFINE_TABLE_FILL(externref) wasm_rt_tailcallee_t* next) #endif + static void w2c_test_0x5Fstart_0(w2c_test*); #ifndef wasm_multi_iiii diff --git a/test/wasm2c/minimal.txt b/test/wasm2c/minimal.txt index 373e86de49..eca9d46055 100644 --- a/test/wasm2c/minimal.txt +++ b/test/wasm2c/minimal.txt @@ -41,6 +41,27 @@ wasm_rt_func_type_t wasm2c_test_get_func_type(uint32_t param_count, uint32_t res #endif /* WASM_H_GENERATED_ */ /* Automatically generated by wasm2c */ +#if WABT_BIG_ENDIAN +#if __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && \ + __has_builtin(__builtin_bswap64) +#define htole16 __builtin_bswap16 +#define htole32 __builtin_bswap32 +#define htole64 __builtin_bswap64 +#elif defined(__linux__) || defined(__CYGWIN__) +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif +#include +#elif defined(__APPLE__) +#include +#define htole16(value) OSSwapHostToLittleInt16(value) +#define htole32(value) OSSwapHostToLittleInt32(value) +#define htole64(value) OSSwapHostToLittleInt64(value) +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || \ + defined(__DragonFly__) +#include +#endif +#endif #include #include #include @@ -58,29 +79,28 @@ wasm_rt_func_type_t wasm2c_test_get_func_type(uint32_t param_count, uint32_t res #include #endif -#include "wasm.h" +#if WABT_BIG_ENDIAN && !defined(htole16) +// Fallback for missing byteswap definitions +static inline uint16_t wasm2c_bswap16(uint16_t value) { + return (uint16_t)((value << 8) | (value >> 8)); +} -// Computes a pointer to an object of the given size in a little-endian memory. -// -// On a little-endian host, this is just &mem->data[addr] - the object's size is -// unused. On a big-endian host, it's &mem->data[mem->size - addr - n], where n -// is the object's size. -// -// Note that mem may be evaluated multiple times. -// -// Parameters: -// mem - The memory. -// addr - The address. -// n - The size of the object. -// -// Result: -// A pointer for an object of size n. -#if WABT_BIG_ENDIAN -#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n)) -#else -#define MEM_ADDR(mem, addr, n) &((mem)->data[addr]) +static inline uint32_t wasm2c_bswap32(uint32_t value) { + return ((value & 0x000000ffu) << 24) | ((value & 0x0000ff00u) << 8) | + ((value & 0x00ff0000u) >> 8) | ((value & 0xff000000u) >> 24); +} + +static inline uint64_t wasm2c_bswap64(uint64_t value) { + return ((uint64_t)wasm2c_bswap32((uint32_t)value) << 32) | + wasm2c_bswap32((uint32_t)(value >> 32)); +} + +#define htole16 wasm2c_bswap16 +#define htole32 wasm2c_bswap32 +#define htole64 wasm2c_bswap64 #endif +#include "wasm.h" // We can only use Segue for this module if it uses a single unshared, // default-page, 32-bit imported or exported memory. #if WASM_RT_USE_SEGUE && IS_SINGLE_UNSHARED_DEFAULT32_MEMORY @@ -94,7 +114,7 @@ wasm_rt_func_type_t wasm2c_test_get_func_type(uint32_t param_count, uint32_t res #endif #if WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE && WASM_RT_USE_MMAP && \ - IS_SINGLE_UNSHARED_DEFAULT32_MEMORY && !WABT_BIG_ENDIAN + IS_SINGLE_UNSHARED_DEFAULT32_MEMORY #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 1 #else #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 0 @@ -124,11 +144,11 @@ static inline void wasm_rt_segue_write_base(void* base) { wasm_rt_syscall_set_segue_base(base); } } -#define MEM_ADDR_MEMOP(mem, addr, n) ((uint8_t __seg_gs*)(uintptr_t)addr) +#define MEM_ADDR_MEMOP(mem, addr) ((uint8_t __seg_gs*)(uintptr_t)addr) #elif WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE -#define MEM_ADDR_MEMOP(mem, addr, n) (&wasm_rt_local_memory_base[(addr)]) +#define MEM_ADDR_MEMOP(mem, addr) (&wasm_rt_local_memory_base[(addr)]) #else -#define MEM_ADDR_MEMOP(mem, addr, n) MEM_ADDR(mem, addr, n) +#define MEM_ADDR_MEMOP(mem, addr) (&(mem)->data[addr]) #endif #define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) @@ -280,23 +300,50 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { "Either enable specify -DWASM_RT_NONCONFORMING_ALLOW_OOB_READ_ELIMINATION=1 during compilation or use -DWASM_RT_MEMCHECK_BOUNDS_CHECK=1 to use bounds check mode" #endif +#define WASM_ADJUST_ENDIAN_u8(value) (value) +#define WASM_ADJUST_ENDIAN_s8(value) (value) +#if WABT_BIG_ENDIAN +#define WASM_ADJUST_ENDIAN_u16 htole16 +#define WASM_ADJUST_ENDIAN_s16 htole16 +#define WASM_ADJUST_ENDIAN_u32 htole32 +#define WASM_ADJUST_ENDIAN_s32 htole32 +#define WASM_ADJUST_ENDIAN_u64 htole64 +static inline f32 WASM_ADJUST_ENDIAN_f32(f32 value) { + u32 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole32(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} + +static inline f64 WASM_ADJUST_ENDIAN_f64(f64 value) { + u64 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole64(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} +#else +#define WASM_ADJUST_ENDIAN_u16(value) (value) +#define WASM_ADJUST_ENDIAN_s16(value) (value) +#define WASM_ADJUST_ENDIAN_u32(value) (value) +#define WASM_ADJUST_ENDIAN_s32(value) (value) +#define WASM_ADJUST_ENDIAN_u64(value) (value) +#define WASM_ADJUST_ENDIAN_f32(value) (value) +#define WASM_ADJUST_ENDIAN_f64(value) (value) +#endif + static inline void load_data(u8* dest, const u8* src, size_t n) { if (!n) { return; } -#if WABT_BIG_ENDIAN - for (size_t i = 0; i < n; i++) { - dest[i] = src[n - i - 1]; - } -#else wasm_rt_memcpy(dest, src, n); -#endif } -#define LOAD_DATA(m, o, i, s) \ - do { \ - RANGE_CHECK((&m), o, s); \ - load_data(MEM_ADDR(&m, o, s), i, s); \ +#define LOAD_DATA(m, o, i, s) \ + do { \ + RANGE_CHECK((&m), o, s); \ + load_data(&(m).data[o], i, s); \ } while (0) #define DEF_MEM_CHECKS0(name, shared, mem_type, ret_kw, return_type) \ @@ -352,8 +399,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { static inline t3 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ wasm_rt_memory_t* mem, u64 addr) { \ t1 result; \ - wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ - sizeof(t1)); \ + wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ + result = WASM_ADJUST_ENDIAN_##t1(result); \ t3 ret = (t3)(t2)result; \ force_read(ret); \ return ret; \ @@ -365,8 +412,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ u64 addr, t2 value) { \ t1 wrapped = (t1)value; \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ - sizeof(t1)); \ + wrapped = WASM_ADJUST_ENDIAN_##t1(wrapped); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ } \ DEF_MEM_CHECKS1(name, _, t1, , void, t2) @@ -732,7 +779,7 @@ static float wasm_sqrtf(float x) { static inline void memory_fill(wasm_rt_memory_t* mem, u64 d, u32 val, u64 n) { RANGE_CHECK(mem, d, n); - memset(MEM_ADDR(mem, d, n), val, n); + memset(&mem->data[d], val, n); } static inline void memory_copy(wasm_rt_memory_t* dest, @@ -742,7 +789,7 @@ static inline void memory_copy(wasm_rt_memory_t* dest, u64 n) { RANGE_CHECK(dest, dest_addr, n); RANGE_CHECK(src, src_addr, n); - memmove(MEM_ADDR(dest, dest_addr, n), MEM_ADDR(src, src_addr, n), n); + memmove(&dest->data[dest_addr], &src->data[src_addr], n); } static inline void memory_init(wasm_rt_memory_t* dest, @@ -886,6 +933,7 @@ DEFINE_TABLE_FILL(externref) wasm_rt_tailcallee_t* next) #endif + void wasm2c_test_instantiate(w2c_test* instance) { assert(wasm_rt_is_initialized()); } diff --git a/test/wasm2c/tail-calls.txt b/test/wasm2c/tail-calls.txt index 4033f5885c..2b9420858a 100644 --- a/test/wasm2c/tail-calls.txt +++ b/test/wasm2c/tail-calls.txt @@ -70,6 +70,27 @@ void wasm_tailcall_w2c_test_tailcaller(void **instance_ptr, void *tail_call_stac #endif /* WASM_H_GENERATED_ */ /* Automatically generated by wasm2c */ +#if WABT_BIG_ENDIAN +#if __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && \ + __has_builtin(__builtin_bswap64) +#define htole16 __builtin_bswap16 +#define htole32 __builtin_bswap32 +#define htole64 __builtin_bswap64 +#elif defined(__linux__) || defined(__CYGWIN__) +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif +#include +#elif defined(__APPLE__) +#include +#define htole16(value) OSSwapHostToLittleInt16(value) +#define htole32(value) OSSwapHostToLittleInt32(value) +#define htole64(value) OSSwapHostToLittleInt64(value) +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || \ + defined(__DragonFly__) +#include +#endif +#endif #include #include #include @@ -87,29 +108,28 @@ void wasm_tailcall_w2c_test_tailcaller(void **instance_ptr, void *tail_call_stac #include #endif -#include "wasm.h" +#if WABT_BIG_ENDIAN && !defined(htole16) +// Fallback for missing byteswap definitions +static inline uint16_t wasm2c_bswap16(uint16_t value) { + return (uint16_t)((value << 8) | (value >> 8)); +} -// Computes a pointer to an object of the given size in a little-endian memory. -// -// On a little-endian host, this is just &mem->data[addr] - the object's size is -// unused. On a big-endian host, it's &mem->data[mem->size - addr - n], where n -// is the object's size. -// -// Note that mem may be evaluated multiple times. -// -// Parameters: -// mem - The memory. -// addr - The address. -// n - The size of the object. -// -// Result: -// A pointer for an object of size n. -#if WABT_BIG_ENDIAN -#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n)) -#else -#define MEM_ADDR(mem, addr, n) &((mem)->data[addr]) +static inline uint32_t wasm2c_bswap32(uint32_t value) { + return ((value & 0x000000ffu) << 24) | ((value & 0x0000ff00u) << 8) | + ((value & 0x00ff0000u) >> 8) | ((value & 0xff000000u) >> 24); +} + +static inline uint64_t wasm2c_bswap64(uint64_t value) { + return ((uint64_t)wasm2c_bswap32((uint32_t)value) << 32) | + wasm2c_bswap32((uint32_t)(value >> 32)); +} + +#define htole16 wasm2c_bswap16 +#define htole32 wasm2c_bswap32 +#define htole64 wasm2c_bswap64 #endif +#include "wasm.h" // We can only use Segue for this module if it uses a single unshared, // default-page, 32-bit imported or exported memory. #if WASM_RT_USE_SEGUE && IS_SINGLE_UNSHARED_DEFAULT32_MEMORY @@ -123,7 +143,7 @@ void wasm_tailcall_w2c_test_tailcaller(void **instance_ptr, void *tail_call_stac #endif #if WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE && WASM_RT_USE_MMAP && \ - IS_SINGLE_UNSHARED_DEFAULT32_MEMORY && !WABT_BIG_ENDIAN + IS_SINGLE_UNSHARED_DEFAULT32_MEMORY #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 1 #else #define WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE 0 @@ -153,11 +173,11 @@ static inline void wasm_rt_segue_write_base(void* base) { wasm_rt_syscall_set_segue_base(base); } } -#define MEM_ADDR_MEMOP(mem, addr, n) ((uint8_t __seg_gs*)(uintptr_t)addr) +#define MEM_ADDR_MEMOP(mem, addr) ((uint8_t __seg_gs*)(uintptr_t)addr) #elif WASM_RT_USE_LOCAL_MEMORY_BASE_SIZE_FOR_THIS_MODULE -#define MEM_ADDR_MEMOP(mem, addr, n) (&wasm_rt_local_memory_base[(addr)]) +#define MEM_ADDR_MEMOP(mem, addr) (&wasm_rt_local_memory_base[(addr)]) #else -#define MEM_ADDR_MEMOP(mem, addr, n) MEM_ADDR(mem, addr, n) +#define MEM_ADDR_MEMOP(mem, addr) (&(mem)->data[addr]) #endif #define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) @@ -309,23 +329,50 @@ static inline uint64_t checked_add_u64(uint64_t a, uint64_t b) { "Either enable specify -DWASM_RT_NONCONFORMING_ALLOW_OOB_READ_ELIMINATION=1 during compilation or use -DWASM_RT_MEMCHECK_BOUNDS_CHECK=1 to use bounds check mode" #endif +#define WASM_ADJUST_ENDIAN_u8(value) (value) +#define WASM_ADJUST_ENDIAN_s8(value) (value) +#if WABT_BIG_ENDIAN +#define WASM_ADJUST_ENDIAN_u16 htole16 +#define WASM_ADJUST_ENDIAN_s16 htole16 +#define WASM_ADJUST_ENDIAN_u32 htole32 +#define WASM_ADJUST_ENDIAN_s32 htole32 +#define WASM_ADJUST_ENDIAN_u64 htole64 +static inline f32 WASM_ADJUST_ENDIAN_f32(f32 value) { + u32 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole32(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} + +static inline f64 WASM_ADJUST_ENDIAN_f64(f64 value) { + u64 bits; + wasm_rt_memcpy(&bits, &value, sizeof(bits)); + bits = htole64(bits); + wasm_rt_memcpy(&value, &bits, sizeof(value)); + return value; +} +#else +#define WASM_ADJUST_ENDIAN_u16(value) (value) +#define WASM_ADJUST_ENDIAN_s16(value) (value) +#define WASM_ADJUST_ENDIAN_u32(value) (value) +#define WASM_ADJUST_ENDIAN_s32(value) (value) +#define WASM_ADJUST_ENDIAN_u64(value) (value) +#define WASM_ADJUST_ENDIAN_f32(value) (value) +#define WASM_ADJUST_ENDIAN_f64(value) (value) +#endif + static inline void load_data(u8* dest, const u8* src, size_t n) { if (!n) { return; } -#if WABT_BIG_ENDIAN - for (size_t i = 0; i < n; i++) { - dest[i] = src[n - i - 1]; - } -#else wasm_rt_memcpy(dest, src, n); -#endif } -#define LOAD_DATA(m, o, i, s) \ - do { \ - RANGE_CHECK((&m), o, s); \ - load_data(MEM_ADDR(&m, o, s), i, s); \ +#define LOAD_DATA(m, o, i, s) \ + do { \ + RANGE_CHECK((&m), o, s); \ + load_data(&(m).data[o], i, s); \ } while (0) #define DEF_MEM_CHECKS0(name, shared, mem_type, ret_kw, return_type) \ @@ -381,8 +428,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { static inline t3 name##_unchecked(uint8_t* const wasm_rt_local_memory_base, \ wasm_rt_memory_t* mem, u64 addr) { \ t1 result; \ - wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ - sizeof(t1)); \ + wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ + result = WASM_ADJUST_ENDIAN_##t1(result); \ t3 ret = (t3)(t2)result; \ force_read(ret); \ return ret; \ @@ -394,8 +441,8 @@ static inline void load_data(u8* dest, const u8* src, size_t n) { uint8_t* const wasm_rt_local_memory_base, wasm_rt_memory_t* mem, \ u64 addr, t2 value) { \ t1 wrapped = (t1)value; \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ - sizeof(t1)); \ + wrapped = WASM_ADJUST_ENDIAN_##t1(wrapped); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ } \ DEF_MEM_CHECKS1(name, _, t1, , void, t2) @@ -761,7 +808,7 @@ static float wasm_sqrtf(float x) { static inline void memory_fill(wasm_rt_memory_t* mem, u64 d, u32 val, u64 n) { RANGE_CHECK(mem, d, n); - memset(MEM_ADDR(mem, d, n), val, n); + memset(&mem->data[d], val, n); } static inline void memory_copy(wasm_rt_memory_t* dest, @@ -771,7 +818,7 @@ static inline void memory_copy(wasm_rt_memory_t* dest, u64 n) { RANGE_CHECK(dest, dest_addr, n); RANGE_CHECK(src, src_addr, n); - memmove(MEM_ADDR(dest, dest_addr, n), MEM_ADDR(src, src_addr, n), n); + memmove(&dest->data[dest_addr], &src->data[src_addr], n); } static inline void memory_init(wasm_rt_memory_t* dest, @@ -915,6 +962,7 @@ DEFINE_TABLE_FILL(externref) wasm_rt_tailcallee_t* next) #endif + static void w2c_test_tailcaller_0(w2c_test*); static void wasm_tailcall_w2c_test_tailcaller_0(void **instance_ptr, void *tail_call_stack, wasm_rt_tailcallee_t *next); static struct wasm_multi_id w2c_test_infiniteloop(w2c_test*, u32, f64); diff --git a/wasm2c/benchmarks/dhrystone/main.c b/wasm2c/benchmarks/dhrystone/main.c index 80a6c561a4..b783746bea 100644 --- a/wasm2c/benchmarks/dhrystone/main.c +++ b/wasm2c/benchmarks/dhrystone/main.c @@ -6,6 +6,27 @@ #include "dhrystone.h" +#if WABT_BIG_ENDIAN +static inline uint16_t wasm2c_bswap16(uint16_t value) { + return (uint16_t)((value << 8) | (value >> 8)); +} + +static inline uint32_t wasm2c_bswap32(uint32_t value) { + return ((value & 0x000000ffu) << 24) | ((value & 0x0000ff00u) << 8) | + ((value & 0x00ff0000u) >> 8) | ((value & 0xff000000u) >> 24); +} + +static inline uint64_t wasm2c_bswap64(uint64_t value) { + return ((uint64_t)wasm2c_bswap32((uint32_t)value) << 32) | + wasm2c_bswap32((uint32_t)(value >> 32)); +} + +#define htole16 wasm2c_bswap16 +#define htole32 wasm2c_bswap32 +#define htole64 wasm2c_bswap64 +#endif + + struct w2c_wasi__snapshot__preview1 { wasm_rt_memory_t* w2c_memory; uvwasi_t* uvwasi; @@ -17,13 +38,7 @@ struct w2c_wasi__snapshot__preview1 { typedef uint32_t u32; typedef uint64_t u64; -#if WABT_BIG_ENDIAN -#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n)) -#else -#define MEM_ADDR(mem, addr, n) &((mem)->data[addr]) -#endif - -#define MEM_ADDR_MEMOP(mem, addr, n) MEM_ADDR(mem, addr, n) +#define MEM_ADDR_MEMOP(mem, addr) (&(mem)->data[addr]) #define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) @@ -33,11 +48,22 @@ typedef uint64_t u64; static inline void memory_fill(wasm_rt_memory_t* mem, u32 d, u32 val, u32 n) { RANGE_CHECK(mem, d, n); - memset(MEM_ADDR(mem, d, n), val, n); + memset(&mem->data[d], val, n); } #define MEMCHECK(mem, a, t) RANGE_CHECK(mem, a, sizeof(t)) +#define WASM_ADJUST_ENDIAN_u8(value) (value) +#if WABT_BIG_ENDIAN +#define WASM_ADJUST_ENDIAN_u16 htole16 +#define WASM_ADJUST_ENDIAN_u32 htole32 +#define WASM_ADJUST_ENDIAN_u64 htole64 +#else +#define WASM_ADJUST_ENDIAN_u16(value) (value) +#define WASM_ADJUST_ENDIAN_u32(value) (value) +#define WASM_ADJUST_ENDIAN_u64(value) (value) +#endif + #ifdef __GNUC__ #define FORCE_READ_INT(var) __asm__("" ::"r"(var)); #else @@ -48,8 +74,8 @@ static inline void memory_fill(wasm_rt_memory_t* mem, u32 d, u32 val, u32 n) { static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \ MEMCHECK(mem, addr, t1); \ t1 result; \ - wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), \ - sizeof(t1)); \ + wasm_rt_memcpy(&result, MEM_ADDR_MEMOP(mem, addr), sizeof(t1)); \ + result = WASM_ADJUST_ENDIAN_##t1(result); \ force_read(result); \ return (t3)(t2)result; \ } @@ -58,8 +84,8 @@ static inline void memory_fill(wasm_rt_memory_t* mem, u32 d, u32 val, u32 n) { static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) { \ MEMCHECK(mem, addr, t1); \ t1 wrapped = (t1)value; \ - wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, \ - sizeof(t1)); \ + wrapped = WASM_ADJUST_ENDIAN_##t1(wrapped); \ + wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr), &wrapped, sizeof(t1)); \ } DEFINE_LOAD(i8_load, u8, u8, u8, FORCE_READ_INT) @@ -106,7 +132,7 @@ u32 w2c_wasi__snapshot__preview1_fd_write( u32 wasi_iovs_i = iovs_offset + i * sizeof(uvwasi_size_t[2]); u32 buf_loc = i32_load(a->w2c_memory, wasi_iovs_i); u32 buf_len = i32_load(a->w2c_memory, wasi_iovs_i + sizeof(uvwasi_size_t)); - iovs[i].buf = MEM_ADDR(a->w2c_memory, buf_loc, buf_len); + iovs[i].buf = &a->w2c_memory->data[buf_loc]; iovs[i].buf_len = buf_len; } diff --git a/wasm2c/wasm-rt-mem-impl-helper.inc b/wasm2c/wasm-rt-mem-impl-helper.inc index 4e209ee55e..a39d40c461 100644 --- a/wasm2c/wasm-rt-mem-impl-helper.inc +++ b/wasm2c/wasm-rt-mem-impl-helper.inc @@ -88,18 +88,12 @@ void MEMORY_API_NAME(wasm_rt_allocate_memory)(MEMORY_TYPE* memory, os_print_last_error("os_mmap failed."); abort(); } - uint8_t* data_end = addr + mmap_size; -#if !WABT_BIG_ENDIAN int ret = os_mprotect(addr, byte_length); -#else - int ret = os_mprotect(data_end - byte_length, byte_length); -#endif if (ret != 0) { os_print_last_error("os_mprotect failed."); abort(); } memory->data = (MEMORY_CELL_TYPE)addr; - memory->data_end = (MEMORY_CELL_TYPE)data_end; return; } #endif @@ -108,7 +102,6 @@ void MEMORY_API_NAME(wasm_rt_allocate_memory)(MEMORY_TYPE* memory, if (byte_length != 0 && !memory->data) { abort(); } - memory->data_end = memory->data + byte_length; } // Returns 0 on success @@ -118,12 +111,7 @@ static int MEMORY_API_NAME(expand_data_allocation)(MEMORY_TYPE* memory, uint64_t delta_size) { #if WASM_RT_USE_MMAP if (MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) { -#if !WABT_BIG_ENDIAN return os_mprotect((void*)(memory->data + old_size), delta_size); -#else - return os_mprotect((void*)(memory->data_end - old_size - delta_size), - delta_size); -#endif } #endif @@ -131,15 +119,9 @@ static int MEMORY_API_NAME(expand_data_allocation)(MEMORY_TYPE* memory, if (new_data == NULL) { return -1; } -#if !WABT_BIG_ENDIAN memset((void*)(new_data + old_size), 0, delta_size); -#else - memmove((void*)(new_data + new_size - old_size), (void*)new_data, old_size); - memset((void*)new_data, 0, delta_size); -#endif memory->data = (MEMORY_CELL_TYPE)new_data; - memory->data_end = memory->data + new_size; return 0; } diff --git a/wasm2c/wasm-rt.h b/wasm2c/wasm-rt.h index 537c322345..fae48164fd 100644 --- a/wasm2c/wasm-rt.h +++ b/wasm2c/wasm-rt.h @@ -57,6 +57,19 @@ extern "C" { #endif #endif +// Check for known platforms that should be defining WABT_BIG_ENDIAN +#ifndef WABT_BIG_ENDIAN +#define WABT_BIG_ENDIAN 0 +#endif + +#if !WABT_BIG_ENDIAN && \ + ((defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ + defined(__BIG_ENDIAN__) || defined(__s390__) || defined(__s390x__) || \ + defined(__sparc__) || defined(__sparc)) +#error "Expected WABT_BIG_ENDIAN to be defined on big endian platforms" +#endif + /** * Many devices don't implement the C11 threads.h. We use CriticalSection APIs * for Windows and pthreads on other platforms where threads are not available. @@ -481,8 +494,6 @@ typedef void* wasm_rt_externref_t; typedef struct { /** The linear memory data, with a byte length of `size`. */ uint8_t* data; - /** The location after the the reserved space for the linear memory data. */ - uint8_t* data_end; /** The page size for this Memory object (always 64 KiB without the custom-page-sizes feature) */ uint32_t page_size; @@ -511,9 +522,6 @@ typedef struct { * volatile. */ _Atomic volatile uint8_t* data; - /** The location one byte after the reserved space for the linear memory data. - * This includes any reserved pages that are not yet allocated. */ - _Atomic volatile uint8_t* data_end; /** The page size for this Memory object (always 64 KiB without the custom-page-sizes feature) */ uint32_t page_size;