TCG: add wasm backend
Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
This commit is contained in:
@@ -12,32 +12,52 @@
|
|||||||
* Load helpers for tcg-ldst.h
|
* Load helpers for tcg-ldst.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if !defined(CONFIG_TCG_INTERPRETER) && defined(EMSCRIPTEN)
|
||||||
|
#include "../../tcg/wasm32.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr,
|
tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr,
|
||||||
MemOpIdx oi, uintptr_t retaddr)
|
MemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8);
|
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8);
|
||||||
return do_ld1_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD);
|
tcg_target_ulong res = do_ld1_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
set_done_flag();
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcg_target_ulong helper_lduw_mmu(CPUArchState *env, uint64_t addr,
|
tcg_target_ulong helper_lduw_mmu(CPUArchState *env, uint64_t addr,
|
||||||
MemOpIdx oi, uintptr_t retaddr)
|
MemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16);
|
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16);
|
||||||
return do_ld2_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD);
|
tcg_target_ulong res = do_ld2_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
set_done_flag();
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
tcg_target_ulong helper_ldul_mmu(CPUArchState *env, uint64_t addr,
|
tcg_target_ulong helper_ldul_mmu(CPUArchState *env, uint64_t addr,
|
||||||
MemOpIdx oi, uintptr_t retaddr)
|
MemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32);
|
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32);
|
||||||
return do_ld4_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD);
|
tcg_target_ulong res = do_ld4_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
set_done_flag();
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t helper_ldq_mmu(CPUArchState *env, uint64_t addr,
|
uint64_t helper_ldq_mmu(CPUArchState *env, uint64_t addr,
|
||||||
MemOpIdx oi, uintptr_t retaddr)
|
MemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64);
|
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64);
|
||||||
return do_ld8_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD);
|
uint64_t res = do_ld8_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
set_done_flag();
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -67,7 +87,11 @@ Int128 helper_ld16_mmu(CPUArchState *env, uint64_t addr,
|
|||||||
MemOpIdx oi, uintptr_t retaddr)
|
MemOpIdx oi, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128);
|
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128);
|
||||||
return do_ld16_mmu(env_cpu(env), addr, oi, retaddr);
|
Int128 res = do_ld16_mmu(env_cpu(env), addr, oi, retaddr);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
set_done_flag();
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Int128 helper_ld_i128(CPUArchState *env, uint64_t addr, uint32_t oi)
|
Int128 helper_ld_i128(CPUArchState *env, uint64_t addr, uint32_t oi)
|
||||||
@@ -84,6 +108,9 @@ void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val,
|
|||||||
{
|
{
|
||||||
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8);
|
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8);
|
||||||
do_st1_mmu(env_cpu(env), addr, val, oi, ra);
|
do_st1_mmu(env_cpu(env), addr, val, oi, ra);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
set_done_flag();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val,
|
void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val,
|
||||||
@@ -91,6 +118,9 @@ void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val,
|
|||||||
{
|
{
|
||||||
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16);
|
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16);
|
||||||
do_st2_mmu(env_cpu(env), addr, val, oi, retaddr);
|
do_st2_mmu(env_cpu(env), addr, val, oi, retaddr);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
set_done_flag();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val,
|
void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val,
|
||||||
@@ -98,6 +128,9 @@ void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val,
|
|||||||
{
|
{
|
||||||
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32);
|
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32);
|
||||||
do_st4_mmu(env_cpu(env), addr, val, oi, retaddr);
|
do_st4_mmu(env_cpu(env), addr, val, oi, retaddr);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
set_done_flag();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val,
|
void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val,
|
||||||
@@ -105,6 +138,9 @@ void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val,
|
|||||||
{
|
{
|
||||||
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64);
|
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64);
|
||||||
do_st8_mmu(env_cpu(env), addr, val, oi, retaddr);
|
do_st8_mmu(env_cpu(env), addr, val, oi, retaddr);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
set_done_flag();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val,
|
void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val,
|
||||||
@@ -112,11 +148,17 @@ void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val,
|
|||||||
{
|
{
|
||||||
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128);
|
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128);
|
||||||
do_st16_mmu(env_cpu(env), addr, val, oi, retaddr);
|
do_st16_mmu(env_cpu(env), addr, val, oi, retaddr);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
set_done_flag();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi)
|
void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi)
|
||||||
{
|
{
|
||||||
helper_st16_mmu(env, addr, val, oi, GETPC());
|
helper_st16_mmu(env, addr, val, oi, GETPC());
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
set_done_flag();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -854,7 +854,11 @@ static inline void tb_remove_from_jmp_list(TranslationBlock *orig, int n_orig)
|
|||||||
void tb_reset_jump(TranslationBlock *tb, int n)
|
void tb_reset_jump(TranslationBlock *tb, int n)
|
||||||
{
|
{
|
||||||
uintptr_t addr = (uintptr_t)(tb->tc.ptr + tb->jmp_reset_offset[n]);
|
uintptr_t addr = (uintptr_t)(tb->tc.ptr + tb->jmp_reset_offset[n]);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
tb_set_jmp_target(tb, n, 0);
|
||||||
|
#else
|
||||||
tb_set_jmp_target(tb, n, addr);
|
tb_set_jmp_target(tb, n, addr);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove any jumps to the TB */
|
/* remove any jumps to the TB */
|
||||||
|
|||||||
@@ -110,6 +110,10 @@
|
|||||||
#include <sys/diskslice.h>
|
#include <sys/diskslice.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* OS X does not have O_DSYNC */
|
/* OS X does not have O_DSYNC */
|
||||||
#ifndef O_DSYNC
|
#ifndef O_DSYNC
|
||||||
#ifdef O_SYNC
|
#ifdef O_SYNC
|
||||||
@@ -2002,6 +2006,13 @@ static int handle_aiocb_write_zeroes_unmap(void *opaque)
|
|||||||
return handle_aiocb_write_zeroes(aiocb);
|
return handle_aiocb_write_zeroes(aiocb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
ssize_t copy_file_range(int a, off_t * b, int, off_t * c, size_t d, unsigned e)
|
||||||
|
{
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
#ifndef HAVE_COPY_FILE_RANGE
|
#ifndef HAVE_COPY_FILE_RANGE
|
||||||
static off_t copy_file_range(int in_fd, off_t *in_off, int out_fd,
|
static off_t copy_file_range(int in_fd, off_t *in_off, int out_fd,
|
||||||
off_t *out_off, size_t len, unsigned int flags)
|
off_t *out_off, size_t len, unsigned int flags)
|
||||||
@@ -2015,6 +2026,7 @@ static off_t copy_file_range(int in_fd, off_t *in_off, int out_fd,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* parse_zone - Fill a zone descriptor
|
* parse_zone - Fill a zone descriptor
|
||||||
|
|||||||
@@ -340,7 +340,9 @@ int main(void) { return 0; }
|
|||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
if check_define __linux__ ; then
|
if check_define __EMSCRIPTEN__ ; then
|
||||||
|
host_os=linux
|
||||||
|
elif check_define __linux__ ; then
|
||||||
host_os=linux
|
host_os=linux
|
||||||
elif check_define _WIN32 ; then
|
elif check_define _WIN32 ; then
|
||||||
host_os=windows
|
host_os=windows
|
||||||
@@ -526,6 +528,10 @@ case "$cpu" in
|
|||||||
linux_arch=x86
|
linux_arch=x86
|
||||||
CPU_CFLAGS="-m64"
|
CPU_CFLAGS="-m64"
|
||||||
;;
|
;;
|
||||||
|
wasm32)
|
||||||
|
host_arch=wasm32
|
||||||
|
CPU_CFLAGS="-m32"
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Now we have our CPU_CFLAGS we can check if we are targeting a 32 or
|
# Now we have our CPU_CFLAGS we can check if we are targeting a 32 or
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@ static void initialize_debug_host(CPUDebug *s)
|
|||||||
#else
|
#else
|
||||||
s->info.endian = BFD_ENDIAN_LITTLE;
|
s->info.endian = BFD_ENDIAN_LITTLE;
|
||||||
#endif
|
#endif
|
||||||
#if defined(CONFIG_TCG_INTERPRETER)
|
#if defined(CONFIG_TCG_INTERPRETER) || defined(EMSCRIPTEN)
|
||||||
s->info.print_insn = print_insn_tci;
|
s->info.print_insn = print_insn_tci;
|
||||||
#elif defined(__i386__)
|
#elif defined(__i386__)
|
||||||
s->info.mach = bfd_mach_i386_i386;
|
s->info.mach = bfd_mach_i386_i386;
|
||||||
|
|||||||
@@ -453,7 +453,7 @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last);
|
|||||||
void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr);
|
void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr);
|
||||||
|
|
||||||
/* GETPC is the true target of the return instruction that we'll execute. */
|
/* GETPC is the true target of the return instruction that we'll execute. */
|
||||||
#if defined(CONFIG_TCG_INTERPRETER)
|
#if defined(CONFIG_TCG_INTERPRETER) || defined(EMSCRIPTEN)
|
||||||
extern __thread uintptr_t tci_tb_ptr;
|
extern __thread uintptr_t tci_tb_ptr;
|
||||||
# define GETPC() tci_tb_ptr
|
# define GETPC() tci_tb_ptr
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -75,7 +75,6 @@
|
|||||||
#else
|
#else
|
||||||
# define ATOMIC_REG_SIZE sizeof(void *)
|
# define ATOMIC_REG_SIZE sizeof(void *)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Weak atomic operations prevent the compiler moving other
|
/* Weak atomic operations prevent the compiler moving other
|
||||||
* loads/stores past the atomic operation load/store. However there is
|
* loads/stores past the atomic operation load/store. However there is
|
||||||
* no explicit memory barrier for the processor.
|
* no explicit memory barrier for the processor.
|
||||||
@@ -91,7 +90,7 @@
|
|||||||
|
|
||||||
#define qatomic_read(ptr) \
|
#define qatomic_read(ptr) \
|
||||||
({ \
|
({ \
|
||||||
qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \
|
/*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \
|
||||||
qatomic_read__nocheck(ptr); \
|
qatomic_read__nocheck(ptr); \
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -99,7 +98,7 @@
|
|||||||
__atomic_store_n(ptr, i, __ATOMIC_RELAXED)
|
__atomic_store_n(ptr, i, __ATOMIC_RELAXED)
|
||||||
|
|
||||||
#define qatomic_set(ptr, i) do { \
|
#define qatomic_set(ptr, i) do { \
|
||||||
qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \
|
/*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \
|
||||||
qatomic_set__nocheck(ptr, i); \
|
qatomic_set__nocheck(ptr, i); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
@@ -122,7 +121,7 @@
|
|||||||
*/
|
*/
|
||||||
#define qatomic_rcu_read_internal(ptr, _val) \
|
#define qatomic_rcu_read_internal(ptr, _val) \
|
||||||
({ \
|
({ \
|
||||||
qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \
|
/*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \
|
||||||
typeof_strip_qual(*ptr) _val; \
|
typeof_strip_qual(*ptr) _val; \
|
||||||
qatomic_rcu_read__nocheck(ptr, &_val); \
|
qatomic_rcu_read__nocheck(ptr, &_val); \
|
||||||
_val; \
|
_val; \
|
||||||
@@ -131,20 +130,20 @@
|
|||||||
qatomic_rcu_read_internal((ptr), MAKE_IDENTIFIER(_val))
|
qatomic_rcu_read_internal((ptr), MAKE_IDENTIFIER(_val))
|
||||||
|
|
||||||
#define qatomic_rcu_set(ptr, i) do { \
|
#define qatomic_rcu_set(ptr, i) do { \
|
||||||
qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \
|
/*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \
|
||||||
__atomic_store_n(ptr, i, __ATOMIC_RELEASE); \
|
__atomic_store_n(ptr, i, __ATOMIC_RELEASE); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#define qatomic_load_acquire(ptr) \
|
#define qatomic_load_acquire(ptr) \
|
||||||
({ \
|
({ \
|
||||||
qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \
|
/*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \
|
||||||
typeof_strip_qual(*ptr) _val; \
|
typeof_strip_qual(*ptr) _val; \
|
||||||
__atomic_load(ptr, &_val, __ATOMIC_ACQUIRE); \
|
__atomic_load(ptr, &_val, __ATOMIC_ACQUIRE); \
|
||||||
_val; \
|
_val; \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define qatomic_store_release(ptr, i) do { \
|
#define qatomic_store_release(ptr, i) do { \
|
||||||
qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \
|
/*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \
|
||||||
__atomic_store_n(ptr, i, __ATOMIC_RELEASE); \
|
__atomic_store_n(ptr, i, __ATOMIC_RELEASE); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
@@ -156,7 +155,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
#define qatomic_xchg(ptr, i) ({ \
|
#define qatomic_xchg(ptr, i) ({ \
|
||||||
qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \
|
/*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \
|
||||||
qatomic_xchg__nocheck(ptr, i); \
|
qatomic_xchg__nocheck(ptr, i); \
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -169,7 +168,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
#define qatomic_cmpxchg(ptr, old, new) ({ \
|
#define qatomic_cmpxchg(ptr, old, new) ({ \
|
||||||
qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \
|
/*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \
|
||||||
qatomic_cmpxchg__nocheck(ptr, old, new); \
|
qatomic_cmpxchg__nocheck(ptr, old, new); \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
* mappings of the same physical page(s).
|
* mappings of the same physical page(s).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__) || defined(__s390__)
|
#if defined(__i386__) || defined(__x86_64__) || defined(__s390__) || defined(EMSCRIPTEN)
|
||||||
|
|
||||||
static inline void flush_idcache_range(uintptr_t rx, uintptr_t rw, size_t len)
|
static inline void flush_idcache_range(uintptr_t rx, uintptr_t rw, size_t len)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
* But libffi does not support __int128_t, and therefore cannot pass
|
* But libffi does not support __int128_t, and therefore cannot pass
|
||||||
* or return values of this type, force use of the Int128 struct.
|
* or return values of this type, force use of the Int128 struct.
|
||||||
*/
|
*/
|
||||||
#if defined(CONFIG_INT128) && !defined(CONFIG_TCG_INTERPRETER)
|
#if defined(CONFIG_INT128) && !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||||
typedef __int128_t Int128;
|
typedef __int128_t Int128;
|
||||||
typedef __int128_t __attribute__((aligned(16))) Int128Aligned;
|
typedef __int128_t __attribute__((aligned(16))) Int128Aligned;
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ QEMU_EXTERN_C int daemon(int, int);
|
|||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#ifdef CONFIG_IOVEC
|
#if defined(CONFIG_IOVEC) || defined(EMSCRIPTEN)
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -281,6 +281,7 @@ void QEMU_ERROR("code path is reachable")
|
|||||||
#ifndef WCOREDUMP
|
#ifndef WCOREDUMP
|
||||||
#define WCOREDUMP(status) 0
|
#define WCOREDUMP(status) 0
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef EMSCRIPTEN
|
||||||
/*
|
/*
|
||||||
* We have a lot of unaudited code that may fail in strange ways, or
|
* We have a lot of unaudited code that may fail in strange ways, or
|
||||||
* even be a security risk during migration, if you disable assertions
|
* even be a security risk during migration, if you disable assertions
|
||||||
@@ -296,6 +297,7 @@ void QEMU_ERROR("code path is reachable")
|
|||||||
#ifdef G_DISABLE_ASSERT
|
#ifdef G_DISABLE_ASSERT
|
||||||
#error building with G_DISABLE_ASSERT is not supported
|
#error building with G_DISABLE_ASSERT is not supported
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef OFF_MAX
|
#ifndef OFF_MAX
|
||||||
#define OFF_MAX (sizeof (off_t) == 8 ? INT64_MAX : INT32_MAX)
|
#define OFF_MAX (sizeof (off_t) == 8 ? INT64_MAX : INT32_MAX)
|
||||||
@@ -630,7 +632,7 @@ bool qemu_write_pidfile(const char *pidfile, Error **errp);
|
|||||||
|
|
||||||
int qemu_get_thread_id(void);
|
int qemu_get_thread_id(void);
|
||||||
|
|
||||||
#ifndef CONFIG_IOVEC
|
#if !defined(CONFIG_IOVEC) && !defined(EMSCRIPTEN)
|
||||||
struct iovec {
|
struct iovec {
|
||||||
void *iov_base;
|
void *iov_base;
|
||||||
size_t iov_len;
|
size_t iov_len;
|
||||||
|
|||||||
+1
-1
@@ -1010,7 +1010,7 @@ static inline size_t tcg_current_code_size(TCGContext *s)
|
|||||||
#define TB_EXIT_IDXMAX 1
|
#define TB_EXIT_IDXMAX 1
|
||||||
#define TB_EXIT_REQUESTED 3
|
#define TB_EXIT_REQUESTED 3
|
||||||
|
|
||||||
#ifdef CONFIG_TCG_INTERPRETER
|
#if defined(CONFIG_TCG_INTERPRETER) || defined(EMSCRIPTEN)
|
||||||
uintptr_t tcg_qemu_tb_exec(CPUArchState *env, const void *tb_ptr);
|
uintptr_t tcg_qemu_tb_exec(CPUArchState *env, const void *tb_ptr);
|
||||||
#else
|
#else
|
||||||
typedef uintptr_t tcg_prologue_fn(CPUArchState *env, const void *tb_ptr);
|
typedef uintptr_t tcg_prologue_fn(CPUArchState *env, const void *tb_ptr);
|
||||||
|
|||||||
+4
-2
@@ -47,7 +47,7 @@ qapi_trace_events = []
|
|||||||
bsd_oses = ['gnu/kfreebsd', 'freebsd', 'netbsd', 'openbsd', 'dragonfly', 'darwin']
|
bsd_oses = ['gnu/kfreebsd', 'freebsd', 'netbsd', 'openbsd', 'dragonfly', 'darwin']
|
||||||
supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux']
|
supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux']
|
||||||
supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv32', 'riscv64', 'x86', 'x86_64',
|
supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv32', 'riscv64', 'x86', 'x86_64',
|
||||||
'arm', 'aarch64', 'loongarch64', 'mips', 'mips64', 'sparc64']
|
'arm', 'aarch64', 'loongarch64', 'mips', 'mips64', 'sparc64', 'wasm32']
|
||||||
|
|
||||||
cpu = host_machine.cpu_family()
|
cpu = host_machine.cpu_family()
|
||||||
|
|
||||||
@@ -482,7 +482,7 @@ ucontext_probe = '''
|
|||||||
# On Windows the only valid backend is the Windows specific one.
|
# On Windows the only valid backend is the Windows specific one.
|
||||||
# For POSIX prefer ucontext, but it's not always possible. The fallback
|
# For POSIX prefer ucontext, but it's not always possible. The fallback
|
||||||
# is sigcontext.
|
# is sigcontext.
|
||||||
supported_backends = []
|
supported_backends = ['fiber']
|
||||||
if host_os == 'windows'
|
if host_os == 'windows'
|
||||||
supported_backends += ['windows']
|
supported_backends += ['windows']
|
||||||
else
|
else
|
||||||
@@ -884,6 +884,8 @@ if get_option('tcg').allowed()
|
|||||||
tcg_arch = 'i386'
|
tcg_arch = 'i386'
|
||||||
elif host_arch == 'ppc64'
|
elif host_arch == 'ppc64'
|
||||||
tcg_arch = 'ppc'
|
tcg_arch = 'ppc'
|
||||||
|
elif host_arch == 'wasm32'
|
||||||
|
tcg_arch = 'wasm32'
|
||||||
endif
|
endif
|
||||||
add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch,
|
add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch,
|
||||||
language: all_languages)
|
language: all_languages)
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ option('fuzzing_engine', type : 'string', value : '',
|
|||||||
option('trace_file', type: 'string', value: 'trace',
|
option('trace_file', type: 'string', value: 'trace',
|
||||||
description: 'Trace file prefix for simple backend')
|
description: 'Trace file prefix for simple backend')
|
||||||
option('coroutine_backend', type: 'combo',
|
option('coroutine_backend', type: 'combo',
|
||||||
choices: ['ucontext', 'sigaltstack', 'windows', 'auto'],
|
choices: ['ucontext', 'sigaltstack', 'windows', 'auto', 'fiber'],
|
||||||
value: 'auto', description: 'coroutine backend to use')
|
value: 'auto', description: 'coroutine backend to use')
|
||||||
|
|
||||||
# Everything else can be set via --enable/--disable-* option
|
# Everything else can be set via --enable/--disable-* option
|
||||||
|
|||||||
@@ -148,11 +148,13 @@ static void change_process_uid(void)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (user_pwd) {
|
if (user_pwd) {
|
||||||
|
#ifndef EMSCRIPTEN
|
||||||
if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) {
|
if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) {
|
||||||
error_report("Failed to initgroups(\"%s\", %d)",
|
error_report("Failed to initgroups(\"%s\", %d)",
|
||||||
user_pwd->pw_name, user_pwd->pw_gid);
|
user_pwd->pw_name, user_pwd->pw_gid);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
if (setgroups(1, &user_gid) < 0) {
|
if (setgroups(1, &user_gid) < 0) {
|
||||||
error_report("Failed to setgroups(1, [%d])",
|
error_report("Failed to setgroups(1, [%d])",
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ meson_options_help() {
|
|||||||
printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string'
|
printf "%s\n" ' --tls-priority=VALUE Default TLS protocol/cipher priority string'
|
||||||
printf "%s\n" ' [NORMAL]'
|
printf "%s\n" ' [NORMAL]'
|
||||||
printf "%s\n" ' --with-coroutine=CHOICE coroutine backend to use (choices:'
|
printf "%s\n" ' --with-coroutine=CHOICE coroutine backend to use (choices:'
|
||||||
printf "%s\n" ' auto/sigaltstack/ucontext/windows)'
|
printf "%s\n" ' auto/fiber/sigaltstack/ucontext/windows)'
|
||||||
printf "%s\n" ' --with-pkgversion=VALUE use specified string as sub-version of the'
|
printf "%s\n" ' --with-pkgversion=VALUE use specified string as sub-version of the'
|
||||||
printf "%s\n" ' package'
|
printf "%s\n" ' package'
|
||||||
printf "%s\n" ' --with-suffix=VALUE Suffix for QEMU data/modules/config directories'
|
printf "%s\n" ' --with-suffix=VALUE Suffix for QEMU data/modules/config directories'
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ tcg_ss.add(files(
|
|||||||
'tcg-op-vec.c',
|
'tcg-op-vec.c',
|
||||||
))
|
))
|
||||||
|
|
||||||
|
cpu = host_machine.cpu_family()
|
||||||
|
|
||||||
if get_option('tcg_interpreter')
|
if get_option('tcg_interpreter')
|
||||||
libffi = dependency('libffi', version: '>=3.0', required: true,
|
libffi = dependency('libffi', version: '>=3.0', required: true,
|
||||||
method: 'pkg-config')
|
method: 'pkg-config')
|
||||||
@@ -29,6 +31,10 @@ endif
|
|||||||
|
|
||||||
tcg_ss = tcg_ss.apply({})
|
tcg_ss = tcg_ss.apply({})
|
||||||
|
|
||||||
|
if cpu == 'wasm32'
|
||||||
|
specific_ss.add(files('wasm32.c'))
|
||||||
|
endif
|
||||||
|
|
||||||
libtcg_user = static_library('tcg_user',
|
libtcg_user = static_library('tcg_user',
|
||||||
tcg_ss.sources() + genh,
|
tcg_ss.sources() + genh,
|
||||||
dependencies: tcg_ss.dependencies(),
|
dependencies: tcg_ss.dependencies(),
|
||||||
|
|||||||
+3
-3
@@ -568,7 +568,7 @@ static int alloc_code_gen_buffer_anon(size_t size, int prot,
|
|||||||
return prot;
|
return prot;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_TCG_INTERPRETER
|
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||||
#ifdef CONFIG_POSIX
|
#ifdef CONFIG_POSIX
|
||||||
#include "qemu/memfd.h"
|
#include "qemu/memfd.h"
|
||||||
|
|
||||||
@@ -670,7 +670,7 @@ static int alloc_code_gen_buffer_splitwx_vmremap(size_t size, Error **errp)
|
|||||||
|
|
||||||
static int alloc_code_gen_buffer_splitwx(size_t size, Error **errp)
|
static int alloc_code_gen_buffer_splitwx(size_t size, Error **errp)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_TCG_INTERPRETER
|
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||||
# ifdef CONFIG_DARWIN
|
# ifdef CONFIG_DARWIN
|
||||||
return alloc_code_gen_buffer_splitwx_vmremap(size, errp);
|
return alloc_code_gen_buffer_splitwx_vmremap(size, errp);
|
||||||
# endif
|
# endif
|
||||||
@@ -816,7 +816,7 @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus)
|
|||||||
* Work with the page protections set up with the initial mapping.
|
* Work with the page protections set up with the initial mapping.
|
||||||
*/
|
*/
|
||||||
need_prot = PROT_READ | PROT_WRITE;
|
need_prot = PROT_READ | PROT_WRITE;
|
||||||
#ifndef CONFIG_TCG_INTERPRETER
|
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||||
if (tcg_splitwx_diff == 0) {
|
if (tcg_splitwx_diff == 0) {
|
||||||
need_prot |= host_prot_read_exec();
|
need_prot |= host_prot_read_exec();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,10 @@ static void tcg_out_goto_tb(TCGContext *s, int which);
|
|||||||
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||||
const TCGArg args[TCG_MAX_OP_ARGS],
|
const TCGArg args[TCG_MAX_OP_ARGS],
|
||||||
const int const_args[TCG_MAX_OP_ARGS]);
|
const int const_args[TCG_MAX_OP_ARGS]);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
static void tcg_out_label_cb(TCGContext *s, TCGLabel *l);
|
||||||
|
static void tcg_out_init();
|
||||||
|
#endif
|
||||||
#if TCG_TARGET_MAYBE_vec
|
#if TCG_TARGET_MAYBE_vec
|
||||||
static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
|
static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
|
||||||
TCGReg dst, TCGReg src);
|
TCGReg dst, TCGReg src);
|
||||||
@@ -245,7 +249,7 @@ TCGv_env tcg_env;
|
|||||||
const void *tcg_code_gen_epilogue;
|
const void *tcg_code_gen_epilogue;
|
||||||
uintptr_t tcg_splitwx_diff;
|
uintptr_t tcg_splitwx_diff;
|
||||||
|
|
||||||
#ifndef CONFIG_TCG_INTERPRETER
|
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||||
tcg_prologue_fn *tcg_qemu_tb_exec;
|
tcg_prologue_fn *tcg_qemu_tb_exec;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -352,6 +356,9 @@ static void tcg_out_label(TCGContext *s, TCGLabel *l)
|
|||||||
tcg_debug_assert(!l->has_value);
|
tcg_debug_assert(!l->has_value);
|
||||||
l->has_value = 1;
|
l->has_value = 1;
|
||||||
l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
|
l->u.value_ptr = tcg_splitwx_to_rx(s->code_ptr);
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
tcg_out_label_cb(s, l);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TCGLabel *gen_new_label(void)
|
TCGLabel *gen_new_label(void)
|
||||||
@@ -420,6 +427,114 @@ tlb_mask_table_ofs(TCGContext *s, int which)
|
|||||||
sizeof(CPUNegativeOffsetState));
|
sizeof(CPUNegativeOffsetState));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
|
||||||
|
#define LABEL_MAX 200
|
||||||
|
|
||||||
|
struct label_placeholder {
|
||||||
|
int label;
|
||||||
|
uintptr_t ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct label_context {
|
||||||
|
int block_idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WASM_NUM_HELPER_FUNCS_MAX 200
|
||||||
|
#define WASM_HELPER_ADDED_TYPES_SECTION_MAX 200
|
||||||
|
__thread uint32_t num_helper_funcs;
|
||||||
|
__thread uint32_t target_helper_funcs[WASM_NUM_HELPER_FUNCS_MAX];
|
||||||
|
__thread uint8_t target_helper_types[WASM_HELPER_ADDED_TYPES_SECTION_MAX];
|
||||||
|
__thread int target_helper_types_pos;
|
||||||
|
__thread int wasm_block_idx;
|
||||||
|
__thread struct label_placeholder block_ptr_placeholder[LABEL_MAX];
|
||||||
|
__thread int block_ptr_placeholder_idx_pos;
|
||||||
|
__thread int label_to_block[LABEL_MAX];
|
||||||
|
|
||||||
|
static int wasm_block_current_idx(TCGContext *s)
|
||||||
|
{
|
||||||
|
return wasm_block_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wasm_alloc_block_idx(TCGContext *s)
|
||||||
|
{
|
||||||
|
return ++wasm_block_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fill_uint32_leb128(uintptr_t bi, uint32_t v) {
|
||||||
|
uint8_t *b = (uint8_t *)bi;
|
||||||
|
uint32_t low7 = 0x7f;
|
||||||
|
// assuems higher bit already written as placeholders
|
||||||
|
do {
|
||||||
|
*b |= v & low7;
|
||||||
|
v >>= 7;
|
||||||
|
b++;
|
||||||
|
} while (v != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_uint32_leb128(uintptr_t bi, uint32_t v) {
|
||||||
|
uint8_t *b = (uint8_t *)bi;
|
||||||
|
uint32_t low7 = 0x7f;
|
||||||
|
do {
|
||||||
|
*b = (uint8_t)(v & low7);
|
||||||
|
v >>= 7;
|
||||||
|
if (v != 0)
|
||||||
|
*b |= 0x80;
|
||||||
|
b++;
|
||||||
|
} while (v != 0);
|
||||||
|
|
||||||
|
return (int)((uintptr_t)b - (uintptr_t)bi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t * wasm_get_helper_types_begin(TCGContext *s)
|
||||||
|
{
|
||||||
|
return &(target_helper_types[target_helper_types_pos]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wasm_add_helper_types_pos(TCGContext *s, int i)
|
||||||
|
{
|
||||||
|
target_helper_types_pos += i;
|
||||||
|
tcg_debug_assert(target_helper_types_pos <= WASM_HELPER_ADDED_TYPES_SECTION_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wasm_register_helper_alloc_num(TCGContext *s)
|
||||||
|
{
|
||||||
|
tcg_debug_assert(num_helper_funcs <= WASM_NUM_HELPER_FUNCS_MAX);
|
||||||
|
return num_helper_funcs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wasm_register_helper(TCGContext *s, int idx_on_tb, int helper_idx_on_qemu)
|
||||||
|
{
|
||||||
|
tcg_debug_assert(idx_on_tb <= WASM_NUM_HELPER_FUNCS_MAX);
|
||||||
|
target_helper_funcs[idx_on_tb] = helper_idx_on_qemu;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_wasm_helper_idx(TCGContext *s, int helper_idx_on_qemu)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < num_helper_funcs; i++) {
|
||||||
|
if (target_helper_funcs[i] == helper_idx_on_qemu) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wasm_add_label_context(TCGContext *s, int label, int block)
|
||||||
|
{
|
||||||
|
tcg_debug_assert(label <= LABEL_MAX);
|
||||||
|
label_to_block[label] = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wasm_add_label_block_ptr_placeholder(TCGContext *s, int label)
|
||||||
|
{
|
||||||
|
int i = block_ptr_placeholder_idx_pos++;
|
||||||
|
tcg_debug_assert(i <= LABEL_MAX);
|
||||||
|
block_ptr_placeholder[i].label = label;
|
||||||
|
block_ptr_placeholder[i].ptr = (uintptr_t)s->code_ptr;;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Signal overflow, starting over with fewer guest insns. */
|
/* Signal overflow, starting over with fewer guest insns. */
|
||||||
static G_NORETURN
|
static G_NORETURN
|
||||||
void tcg_raise_tb_overflow(TCGContext *s)
|
void tcg_raise_tb_overflow(TCGContext *s)
|
||||||
@@ -937,7 +1052,7 @@ static TCGHelperInfo info_helper_st128_mmu = {
|
|||||||
| dh_typemask(ptr, 5) /* uintptr_t ra */
|
| dh_typemask(ptr, 5) /* uintptr_t ra */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_TCG_INTERPRETER
|
#if defined(CONFIG_TCG_INTERPRETER)
|
||||||
static ffi_type *typecode_to_ffi(int argmask)
|
static ffi_type *typecode_to_ffi(int argmask)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -1406,12 +1521,11 @@ void tcg_prologue_init(void)
|
|||||||
{
|
{
|
||||||
TCGContext *s = tcg_ctx;
|
TCGContext *s = tcg_ctx;
|
||||||
size_t prologue_size;
|
size_t prologue_size;
|
||||||
|
|
||||||
s->code_ptr = s->code_gen_ptr;
|
s->code_ptr = s->code_gen_ptr;
|
||||||
s->code_buf = s->code_gen_ptr;
|
s->code_buf = s->code_gen_ptr;
|
||||||
s->data_gen_ptr = NULL;
|
s->data_gen_ptr = NULL;
|
||||||
|
|
||||||
#ifndef CONFIG_TCG_INTERPRETER
|
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||||
tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
|
tcg_qemu_tb_exec = (tcg_prologue_fn *)tcg_splitwx_to_rx(s->code_ptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1434,7 +1548,7 @@ void tcg_prologue_init(void)
|
|||||||
prologue_size = tcg_current_code_size(s);
|
prologue_size = tcg_current_code_size(s);
|
||||||
perf_report_prologue(s->code_gen_ptr, prologue_size);
|
perf_report_prologue(s->code_gen_ptr, prologue_size);
|
||||||
|
|
||||||
#ifndef CONFIG_TCG_INTERPRETER
|
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||||
flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
|
flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
|
||||||
(uintptr_t)s->code_buf, prologue_size);
|
(uintptr_t)s->code_buf, prologue_size);
|
||||||
#endif
|
#endif
|
||||||
@@ -1471,7 +1585,7 @@ void tcg_prologue_init(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_TCG_INTERPRETER
|
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||||
/*
|
/*
|
||||||
* Assert that goto_ptr is implemented completely, setting an epilogue.
|
* Assert that goto_ptr is implemented completely, setting an epilogue.
|
||||||
* For tci, we use NULL as the signal to return from the interpreter,
|
* For tci, we use NULL as the signal to return from the interpreter,
|
||||||
@@ -5904,6 +6018,151 @@ static void tcg_out_ld_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
|
|||||||
tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
|
tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
|
||||||
|
static const uint8_t mod_header_a[] = {
|
||||||
|
0x0, 0x61, 0x73, 0x6d, // magic
|
||||||
|
0x01, 0x0, 0x0, 0x0, // version
|
||||||
|
// type section
|
||||||
|
0x01, 0x80, 0x80, 0x80, 0x80, 0x00,
|
||||||
|
0x80, 0x80, 0x80, 0x80, 0x00,
|
||||||
|
0x60,
|
||||||
|
0x01, 0x7f,
|
||||||
|
0x01, 0x7f,
|
||||||
|
|
||||||
|
};
|
||||||
|
static const uint8_t mod_header_b[] = {
|
||||||
|
// import section
|
||||||
|
0x02, 0x80, 0x80, 0x80, 0x80, 0x00,
|
||||||
|
0x80, 0x80, 0x80, 0x80, 0x00,
|
||||||
|
0x03, 0x65, 0x6e, 0x76,
|
||||||
|
0x06, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72,
|
||||||
|
0x02, 0x03, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t mod_header_c[] = {
|
||||||
|
// function section
|
||||||
|
0x03, 2, 1, 0x00,
|
||||||
|
// global section
|
||||||
|
0x06, 0x7e,
|
||||||
|
25,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
0x7e, 0x01, 0x42, 0x00, 0x0b,
|
||||||
|
// export section
|
||||||
|
0x07, 13,
|
||||||
|
1,
|
||||||
|
0x05, 0x73, 0x74, 0x61, 0x72, 0x74,
|
||||||
|
0x00, 0x80, 0x80, 0x80, 0x80, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t mod_header_d[] = {
|
||||||
|
0x0a, 0x80, 0x80, 0x80, 0x80, 0x00,
|
||||||
|
0x80, 0x80, 0x80, 0x80, 0x00,
|
||||||
|
0x80, 0x80, 0x80, 0x80, 0x00,
|
||||||
|
|
||||||
|
0x2, 0x2, 0x7f, 0x5, 0x7e,
|
||||||
|
|
||||||
|
// initialize the instance
|
||||||
|
0x20, 0x0, // local.get $ctx
|
||||||
|
0x28, 0, DO_INIT_OFF, // i32.load do_init_ptr
|
||||||
|
0x41, 0, // i32.const 0
|
||||||
|
0x47, // i32.ne
|
||||||
|
0x04, 0x40, // if
|
||||||
|
|
||||||
|
0x23, 14, // global.get $env
|
||||||
|
0x50, // i64.eqz
|
||||||
|
0x04, 0x40, // if
|
||||||
|
// fundamental variables
|
||||||
|
0x20, 0x0, // local.get $ctx
|
||||||
|
0x28, 0, ENV_OFF, // i32.load env
|
||||||
|
0xad, // extend
|
||||||
|
0x24, 14, // global.set $14
|
||||||
|
0x20, 0x0, // local.get $ctx
|
||||||
|
0x28, 0, STACK_OFF, // i32.load stack
|
||||||
|
0xad, // extend
|
||||||
|
0x24, 15, // global.set $15
|
||||||
|
0x0b, // end
|
||||||
|
|
||||||
|
0x20, 0x0, // local.get $ctx
|
||||||
|
0x41, 0x00, // i32.const 0
|
||||||
|
0x36, 0x00, DO_INIT_OFF, // i32.store do_init
|
||||||
|
0x42, 0x00, // i64.const 0
|
||||||
|
0x24, 24, // global.set $block_ptr
|
||||||
|
0x0b, // end
|
||||||
|
|
||||||
|
0x03, 0x40, // loop
|
||||||
|
0x23, 24, // global.get $block_ptr
|
||||||
|
0x50, // i64.eqz
|
||||||
|
0x04, 0x40, // if
|
||||||
|
};
|
||||||
|
|
||||||
|
static void write_wasm_type_section_size(TCGContext *s, void *header_a_ptr, uint32_t added) {
|
||||||
|
uint32_t type_section_size = added + 10;
|
||||||
|
fill_uint32_leb128((uintptr_t)header_a_ptr + 9, type_section_size);
|
||||||
|
fill_uint32_leb128((uintptr_t)header_a_ptr + 14, num_helper_funcs + 1);
|
||||||
|
}
|
||||||
|
static void write_wasm_memory_size(TCGContext *s, void *header_b_ptr) {
|
||||||
|
fill_uint32_leb128((uintptr_t)header_b_ptr + 25, (uint32_t)(~0) / 65536);
|
||||||
|
}
|
||||||
|
static void write_wasm_import_section_size(TCGContext *s, void *header_b_ptr, uint32_t added, uint32_t num_imported_funcs) {
|
||||||
|
uint32_t import_section_size = 35 + added - 11;
|
||||||
|
fill_uint32_leb128((uintptr_t)header_b_ptr + 1, import_section_size);
|
||||||
|
fill_uint32_leb128((uintptr_t)header_b_ptr + 6, num_imported_funcs + 1/*buffer+helpers...*/);
|
||||||
|
}
|
||||||
|
static void write_wasm_export_section_size(TCGContext *s, void *header_c_ptr, uint32_t startidx) {
|
||||||
|
fill_uint32_leb128((uintptr_t)header_c_ptr + 142, startidx);
|
||||||
|
}
|
||||||
|
static void write_wasm_code_size(TCGContext *s, void *header_d_ptr, int code_size, int code_nums) {
|
||||||
|
code_size = code_size + 66;
|
||||||
|
fill_uint32_leb128((uintptr_t)header_d_ptr + 1, code_size);
|
||||||
|
fill_uint32_leb128((uintptr_t)header_d_ptr + 6, code_nums);
|
||||||
|
fill_uint32_leb128((uintptr_t)header_d_ptr + 11, code_size - 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *tcg_out_import_entry(TCGContext *s, uint8_t* wasm_blob_ptr, int i, int typeidx)
|
||||||
|
{
|
||||||
|
*wasm_blob_ptr++ = 6; // helper
|
||||||
|
*wasm_blob_ptr++ = 0x68;
|
||||||
|
*wasm_blob_ptr++ = 0x65;
|
||||||
|
*wasm_blob_ptr++ = 0x6c;
|
||||||
|
*wasm_blob_ptr++ = 0x70;
|
||||||
|
*wasm_blob_ptr++ = 0x65;
|
||||||
|
*wasm_blob_ptr++ = 0x72;
|
||||||
|
char buf[100];
|
||||||
|
int n = snprintf(buf, sizeof(buf), "%d", i);
|
||||||
|
wasm_blob_ptr += write_uint32_leb128((uintptr_t)wasm_blob_ptr, n);
|
||||||
|
memcpy(wasm_blob_ptr, buf, n);
|
||||||
|
wasm_blob_ptr += n;
|
||||||
|
*wasm_blob_ptr++ = 0x00; //type(0)
|
||||||
|
*wasm_blob_ptr++ = typeidx; //typeidx
|
||||||
|
return wasm_blob_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst,
|
static void tcg_out_ld_helper_ret(TCGContext *s, const TCGLabelQemuLdst *ldst,
|
||||||
bool load_sign,
|
bool load_sign,
|
||||||
const TCGLdstHelperParam *parm)
|
const TCGLdstHelperParam *parm)
|
||||||
@@ -6185,6 +6444,20 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
|
|||||||
s->code_ptr = s->code_buf;
|
s->code_ptr = s->code_buf;
|
||||||
s->data_gen_ptr = NULL;
|
s->data_gen_ptr = NULL;
|
||||||
|
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
tcg_out_init();
|
||||||
|
num_helper_funcs = 0;
|
||||||
|
wasm_block_idx = 0;
|
||||||
|
block_ptr_placeholder_idx_pos = 0;
|
||||||
|
target_helper_types_pos = 0;
|
||||||
|
memset(label_to_block, -1, LABEL_MAX);
|
||||||
|
memset(target_helper_funcs, -1, WASM_NUM_HELPER_FUNCS_MAX);
|
||||||
|
|
||||||
|
s->code_ptr += 4; // placeholder for export vector offset
|
||||||
|
uint8_t *code_begin = s->code_ptr;
|
||||||
|
s->code_ptr += 4; // placeholder for size
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef TCG_TARGET_NEED_LDST_LABELS
|
#ifdef TCG_TARGET_NEED_LDST_LABELS
|
||||||
QSIMPLEQ_INIT(&s->ldst_labels);
|
QSIMPLEQ_INIT(&s->ldst_labels);
|
||||||
#endif
|
#endif
|
||||||
@@ -6286,13 +6559,85 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
|
|||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_TCG_INTERPRETER
|
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||||
/* flush instruction cache */
|
/* flush instruction cache */
|
||||||
flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
|
flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
|
||||||
(uintptr_t)s->code_buf,
|
(uintptr_t)s->code_buf,
|
||||||
tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
|
tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER)
|
||||||
|
tcg_out8(s, 0x0b); //end if
|
||||||
|
tcg_out8(s, 0x0b); //end loop
|
||||||
|
tcg_out8(s, 0x0); // unreachable
|
||||||
|
tcg_out8(s, 0x0b); //end func
|
||||||
|
|
||||||
|
// fill blocks
|
||||||
|
for (int i = 0; i < block_ptr_placeholder_idx_pos; i++) {
|
||||||
|
int label = block_ptr_placeholder[i].label;
|
||||||
|
int ph = block_ptr_placeholder[i].ptr;
|
||||||
|
int blk = label_to_block[label];
|
||||||
|
tcg_debug_assert(blk >= 0);
|
||||||
|
fill_uint32_leb128(ph, blk);
|
||||||
|
}
|
||||||
|
|
||||||
|
int code_size = (uint32_t)((uintptr_t)s->code_ptr - (uintptr_t)code_begin - 4);
|
||||||
|
*(uint32_t *)code_begin = code_size;
|
||||||
|
|
||||||
|
// write header
|
||||||
|
uint8_t *wasm_blob_ptr = s->code_ptr;
|
||||||
|
uint8_t *wasm_blob_ptr_base = s->code_ptr;
|
||||||
|
wasm_blob_ptr += 4; // placeholder for size
|
||||||
|
|
||||||
|
uint8_t *header_a_base = wasm_blob_ptr;
|
||||||
|
memcpy(wasm_blob_ptr, mod_header_a, sizeof(mod_header_a));
|
||||||
|
wasm_blob_ptr += sizeof(mod_header_a);
|
||||||
|
memcpy(wasm_blob_ptr, target_helper_types, target_helper_types_pos);
|
||||||
|
wasm_blob_ptr += target_helper_types_pos;
|
||||||
|
write_wasm_type_section_size(s, header_a_base, target_helper_types_pos);
|
||||||
|
uint8_t *header_b_base = wasm_blob_ptr;
|
||||||
|
memcpy(wasm_blob_ptr, mod_header_b, sizeof(mod_header_b));
|
||||||
|
wasm_blob_ptr += sizeof(mod_header_b);
|
||||||
|
uint8_t *header_b_adding_base = wasm_blob_ptr;
|
||||||
|
for (int i = 0; i < num_helper_funcs; i++) {
|
||||||
|
wasm_blob_ptr = tcg_out_import_entry(s, wasm_blob_ptr, i, i+1/*type0=start,1=helpers...*/);
|
||||||
|
}
|
||||||
|
write_wasm_import_section_size(s, header_b_base, (uint32_t)wasm_blob_ptr - (uint32_t)header_b_adding_base, num_helper_funcs);
|
||||||
|
write_wasm_memory_size(s, header_b_base);
|
||||||
|
uint8_t *header_c_base = wasm_blob_ptr;
|
||||||
|
memcpy(wasm_blob_ptr, mod_header_c, sizeof(mod_header_c));
|
||||||
|
wasm_blob_ptr += sizeof(mod_header_c);
|
||||||
|
write_wasm_export_section_size(s, header_c_base, num_helper_funcs);
|
||||||
|
uint8_t *header_d_ptr = wasm_blob_ptr;
|
||||||
|
memcpy(wasm_blob_ptr, mod_header_d, sizeof(mod_header_d));
|
||||||
|
wasm_blob_ptr += sizeof(mod_header_d);
|
||||||
|
write_wasm_code_size(s, header_d_ptr, code_size, 1);
|
||||||
|
|
||||||
|
// write header size
|
||||||
|
*(uint32_t *)wasm_blob_ptr_base = wasm_blob_ptr - wasm_blob_ptr_base - 4;
|
||||||
|
s->code_ptr = wasm_blob_ptr;
|
||||||
|
|
||||||
|
// record importing helper functions
|
||||||
|
uint32_t *size_base = (uint32_t*)s->code_ptr;
|
||||||
|
s->code_ptr += 4;
|
||||||
|
memcpy(s->code_ptr, target_helper_funcs, num_helper_funcs * 4);
|
||||||
|
s->code_ptr += num_helper_funcs * 4;
|
||||||
|
*size_base = num_helper_funcs * 4;
|
||||||
|
|
||||||
|
// init exporting functions with zeros
|
||||||
|
size_base = (uint32_t*)s->code_ptr;
|
||||||
|
s->code_ptr += 4;
|
||||||
|
*(uint32_t*)(s->code_buf) = (uint32_t)(s->code_ptr - s->code_buf);
|
||||||
|
int export_size = get_core_nums() * 4;
|
||||||
|
memset(s->code_ptr, 0, export_size);
|
||||||
|
s->code_ptr += export_size;
|
||||||
|
*size_base = export_size;
|
||||||
|
|
||||||
|
if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return tcg_current_code_size(s);
|
return tcg_current_code_size(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+172
@@ -0,0 +1,172 @@
|
|||||||
|
#if !defined(CONFIG_TCG_INTERPRETER) && defined(EMSCRIPTEN)
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "exec/cpu_ldst.h"
|
||||||
|
#include "tcg/tcg-op.h"
|
||||||
|
#include "tcg/tcg-ldst.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <emscripten.h>
|
||||||
|
#include <emscripten/threading.h>
|
||||||
|
#include "wasm32.h"
|
||||||
|
|
||||||
|
__thread uintptr_t tci_tb_ptr;
|
||||||
|
|
||||||
|
/* Disassemble TCI bytecode. */
|
||||||
|
int print_insn_tci(bfd_vma addr, disassemble_info *info)
|
||||||
|
{
|
||||||
|
return 0; //nop
|
||||||
|
}
|
||||||
|
|
||||||
|
EM_JS(int, instantiate_wasm, (int cur_core_num, int all_cores_num, int wasm_body_begin, int wasm_body_size, int wasm_header_begin, int wasm_header_size, int import_vec_begin, int import_vec_size, int export_vec_begin, int export_vec_size, int *to_remove_ptr, int *to_remove_num), {
|
||||||
|
const memory_v = new DataView(HEAP8.buffer);
|
||||||
|
var wasm = new Uint8Array(wasm_header_size + wasm_body_size);
|
||||||
|
wasm.set(HEAP8.subarray(wasm_header_begin, wasm_header_begin + wasm_header_size));
|
||||||
|
wasm.set(HEAP8.subarray(wasm_body_begin, wasm_body_begin + wasm_body_size), wasm_header_size);
|
||||||
|
const mod = new WebAssembly.Module(wasm);
|
||||||
|
var helper = {};
|
||||||
|
for (var i = 0; i < import_vec_size / 4; i++) {
|
||||||
|
helper[i] = wasmTable.get(memory_v.getInt32(import_vec_begin + i * 4, true));
|
||||||
|
}
|
||||||
|
const inst = new WebAssembly.Instance(mod, {
|
||||||
|
"env": {
|
||||||
|
"buffer": wasmMemory,
|
||||||
|
},
|
||||||
|
"helper": helper,
|
||||||
|
});
|
||||||
|
var ptr = export_vec_begin + 4 * cur_core_num;
|
||||||
|
const fidx = addFunction(inst.exports.start, 'ii');
|
||||||
|
memory_v.setUint32(ptr, fidx, true);
|
||||||
|
ptr += 4 * all_cores_num;
|
||||||
|
|
||||||
|
const remove_n = memory_v.getInt32(to_remove_num, true);
|
||||||
|
if (remove_n > 500) {
|
||||||
|
for (var i = 0; i < remove_n * 4; i += 4) {
|
||||||
|
removeFunction(memory_v.getInt32(to_remove_ptr + i, true));
|
||||||
|
}
|
||||||
|
memory_v.setInt32(to_remove_num, 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fidx;
|
||||||
|
});
|
||||||
|
|
||||||
|
#define TO_REMOVE_INSTANCE_SIZE 50000
|
||||||
|
__thread static int to_remove_instance[TO_REMOVE_INSTANCE_SIZE];
|
||||||
|
__thread static int to_remove_instance_idx = 0;
|
||||||
|
|
||||||
|
#define ACTIVE_TBS_MAX 60000
|
||||||
|
#define REMOVE_TBS_NUM 10000
|
||||||
|
__thread static int active_tbs[ACTIVE_TBS_MAX];
|
||||||
|
__thread static int active_tbs_begin = 0;
|
||||||
|
__thread static int active_tbs_end = 0;
|
||||||
|
__thread static int active_tbs_lim;
|
||||||
|
__thread static int active_tbs_rmv;
|
||||||
|
|
||||||
|
static int active_tbs_len()
|
||||||
|
{
|
||||||
|
if (active_tbs_begin == active_tbs_end) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (active_tbs_begin < active_tbs_end) {
|
||||||
|
return active_tbs_end - active_tbs_begin;
|
||||||
|
}
|
||||||
|
if (active_tbs_begin > active_tbs_end) {
|
||||||
|
return (active_tbs_lim - active_tbs_begin) + active_tbs_end;
|
||||||
|
}
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prepare_wasm(void *tb_ptr, int cur_core_num, int all_cores_num)
|
||||||
|
{
|
||||||
|
uint32_t code_size = *(uint32_t*)((uint32_t)tb_ptr + 4);
|
||||||
|
uint32_t code_begin = (uint32_t)tb_ptr + 4 + 4;
|
||||||
|
uint32_t header_size = *(uint32_t*)(code_begin + code_size);
|
||||||
|
uint32_t header_begin = code_begin + code_size + 4;
|
||||||
|
uint32_t import_vec_size = *(uint32_t*)(header_begin + header_size);
|
||||||
|
uint32_t import_vec_begin = header_begin + header_size + 4;
|
||||||
|
uint32_t export_vec_size = *(uint32_t*)(import_vec_begin + import_vec_size);
|
||||||
|
uint32_t export_vec_begin = import_vec_begin + import_vec_size + 4;
|
||||||
|
|
||||||
|
if (active_tbs_len() == (active_tbs_lim-1)) {
|
||||||
|
int idx = active_tbs_begin;
|
||||||
|
for (int i = 0; i < active_tbs_rmv; i++) {
|
||||||
|
uint8_t *p = (uint8_t*)active_tbs[idx];
|
||||||
|
int f = *(uint32_t*)((uint8_t*)p + *(uint32_t*)p + cur_core_num * 4);
|
||||||
|
*(uint32_t*)((uint8_t*)p + *(uint32_t*)p + cur_core_num * 4) = 0;
|
||||||
|
to_remove_instance[to_remove_instance_idx++] = f;
|
||||||
|
idx++;
|
||||||
|
if (idx >= active_tbs_lim) {
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
active_tbs_begin = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fidx = instantiate_wasm(cur_core_num, all_cores_num, code_begin, code_size, header_begin, header_size, import_vec_begin, import_vec_size, export_vec_begin, export_vec_size, to_remove_instance, &to_remove_instance_idx);
|
||||||
|
active_tbs[active_tbs_end++] = (int)tb_ptr;
|
||||||
|
if (active_tbs_end >= active_tbs_lim) {
|
||||||
|
active_tbs_end = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__thread struct wasmContext ctx = {
|
||||||
|
.tb_ptr = 0,
|
||||||
|
.stack = NULL,
|
||||||
|
/* .func_ptr = 0, */
|
||||||
|
/* .next_func_ptr = 0, */
|
||||||
|
.do_init = 1,
|
||||||
|
.stack128 = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
void set_done_flag()
|
||||||
|
{
|
||||||
|
ctx.done_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_unwinding_flag()
|
||||||
|
{
|
||||||
|
ctx.unwinding = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef uint32_t (*wasm_func_ptr)(struct wasmContext*);
|
||||||
|
|
||||||
|
__thread bool initdone = false;
|
||||||
|
__thread int cur_core_num = -1;
|
||||||
|
__thread int all_cores_num = -1;
|
||||||
|
int cur_core_num_max = 0;
|
||||||
|
|
||||||
|
int get_core_nums()
|
||||||
|
{
|
||||||
|
return emscripten_num_logical_cores();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern unsigned int tcg_max_ctxs;
|
||||||
|
|
||||||
|
uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, const void *v_tb_ptr)
|
||||||
|
{
|
||||||
|
if (!initdone) {
|
||||||
|
active_tbs_lim = ACTIVE_TBS_MAX / tcg_max_ctxs;
|
||||||
|
active_tbs_rmv = REMOVE_TBS_NUM / tcg_max_ctxs;
|
||||||
|
cur_core_num = qatomic_fetch_inc(&cur_core_num_max);
|
||||||
|
all_cores_num = get_core_nums();
|
||||||
|
ctx.stack = (uint64_t*)malloc((TCG_STATIC_CALL_ARGS_SIZE + TCG_STATIC_FRAME_SIZE) / sizeof(uint64_t));
|
||||||
|
ctx.stack128 = (uint64_t*)malloc((TCG_STATIC_CALL_ARGS_SIZE + TCG_STATIC_FRAME_SIZE) / sizeof(uint64_t));
|
||||||
|
initdone = true;
|
||||||
|
}
|
||||||
|
ctx.env = env;
|
||||||
|
ctx.tb_ptr = (uint32_t*)v_tb_ptr;
|
||||||
|
ctx.do_init = 1;
|
||||||
|
ctx.tci_tb_ptr = (uint32_t*)&tci_tb_ptr;
|
||||||
|
uint32_t prev_tb_ptr = 0;
|
||||||
|
while (true) {
|
||||||
|
int tb_entry_ptr = (uint32_t)ctx.tb_ptr + *(uint32_t*)ctx.tb_ptr + cur_core_num * 4;
|
||||||
|
if (*(uint32_t*)tb_entry_ptr == 0) {
|
||||||
|
prepare_wasm(ctx.tb_ptr, cur_core_num, all_cores_num);
|
||||||
|
}
|
||||||
|
uint32_t res = ((wasm_func_ptr)(*(uint32_t*)tb_entry_ptr))(&ctx);
|
||||||
|
if ((uint32_t)ctx.tb_ptr == 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef TCG_WASM32_H
|
||||||
|
#define TCG_WASM32_H
|
||||||
|
|
||||||
|
struct wasmContext {
|
||||||
|
// 0
|
||||||
|
CPUArchState *env;
|
||||||
|
// 4
|
||||||
|
uint64_t *stack;
|
||||||
|
// 8
|
||||||
|
uint32_t *tb_ptr;
|
||||||
|
// 12
|
||||||
|
uint32_t *tci_tb_ptr;
|
||||||
|
// 16
|
||||||
|
uint32_t do_init;
|
||||||
|
// 20
|
||||||
|
uint32_t done_flag;
|
||||||
|
// 24
|
||||||
|
uint64_t *stack128;
|
||||||
|
// 28
|
||||||
|
uint32_t unwinding;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ENV_OFF 0
|
||||||
|
#define STACK_OFF 4
|
||||||
|
#define TB_PTR_OFF 8
|
||||||
|
#define HELPER_RET_TB_PTR_OFF 12
|
||||||
|
#define DO_INIT_OFF 16
|
||||||
|
#define DONE_FLAG_OFF 20
|
||||||
|
#define STACK128_OFF 24
|
||||||
|
#define UNWINDING_OFF 28
|
||||||
|
|
||||||
|
void set_done_flag();
|
||||||
|
|
||||||
|
void set_unwinding_flag();
|
||||||
|
|
||||||
|
int get_core_nums();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* C_On_Im(...) defines a constraint set with <n> outputs and <m> inputs.
|
||||||
|
* Each operand should be a sequence of constraint letters as defined by
|
||||||
|
* tcg-target-con-str.h; the constraint combination is inclusive or.
|
||||||
|
*/
|
||||||
|
C_O0_I1(r)
|
||||||
|
C_O0_I2(r, r)
|
||||||
|
C_O0_I3(r, r, r)
|
||||||
|
C_O0_I4(r, r, r, r)
|
||||||
|
C_O1_I1(r, r)
|
||||||
|
C_O1_I2(r, r, r)
|
||||||
|
C_O1_I4(r, r, r, r, r)
|
||||||
|
C_O2_I1(r, r, r)
|
||||||
|
C_O2_I2(r, r, r, r)
|
||||||
|
C_O2_I4(r, r, r, r, r, r)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/*
|
||||||
|
* Define constraint letters for register sets:
|
||||||
|
* REGS(letter, register_mask)
|
||||||
|
*/
|
||||||
|
REGS('r', MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS))
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef TCG_TARGET_REG_BITS_H
|
||||||
|
#define TCG_TARGET_REG_BITS_H
|
||||||
|
|
||||||
|
#define TCG_TARGET_REG_BITS 64
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* Tiny Code Generator for QEMU
|
||||||
|
*
|
||||||
|
* Copyright (c) 2009, 2011 Stefan Weil
|
||||||
|
*
|
||||||
|
* Based on tci/tcg-target.h
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TCG_TARGET_H
|
||||||
|
#define TCG_TARGET_H
|
||||||
|
|
||||||
|
#define TCG_TARGET_INSN_UNIT_SIZE 1
|
||||||
|
#define TCG_TARGET_TLB_DISPLACEMENT_BITS 32
|
||||||
|
#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
|
||||||
|
|
||||||
|
/* Optional instructions. */
|
||||||
|
|
||||||
|
#define TCG_TARGET_HAS_bswap16_i32 1
|
||||||
|
#define TCG_TARGET_HAS_bswap32_i32 1
|
||||||
|
#define TCG_TARGET_HAS_div_i32 1
|
||||||
|
#define TCG_TARGET_HAS_rem_i32 1
|
||||||
|
#define TCG_TARGET_HAS_ext8s_i32 1
|
||||||
|
#define TCG_TARGET_HAS_ext16s_i32 1
|
||||||
|
#define TCG_TARGET_HAS_ext8u_i32 1
|
||||||
|
#define TCG_TARGET_HAS_ext16u_i32 1
|
||||||
|
#define TCG_TARGET_HAS_andc_i32 1
|
||||||
|
#define TCG_TARGET_HAS_deposit_i32 1
|
||||||
|
#define TCG_TARGET_HAS_extract_i32 1
|
||||||
|
#define TCG_TARGET_HAS_sextract_i32 1
|
||||||
|
#define TCG_TARGET_HAS_extract2_i32 1
|
||||||
|
#define TCG_TARGET_HAS_eqv_i32 1
|
||||||
|
#define TCG_TARGET_HAS_nand_i32 1
|
||||||
|
#define TCG_TARGET_HAS_nor_i32 1
|
||||||
|
#define TCG_TARGET_HAS_clz_i32 1
|
||||||
|
#define TCG_TARGET_HAS_ctz_i32 1
|
||||||
|
#define TCG_TARGET_HAS_ctpop_i32 1
|
||||||
|
#define TCG_TARGET_HAS_neg_i32 1
|
||||||
|
#define TCG_TARGET_HAS_not_i32 1
|
||||||
|
#define TCG_TARGET_HAS_orc_i32 1
|
||||||
|
#define TCG_TARGET_HAS_rot_i32 1
|
||||||
|
#define TCG_TARGET_HAS_movcond_i32 1
|
||||||
|
#define TCG_TARGET_HAS_muls2_i32 1
|
||||||
|
#define TCG_TARGET_HAS_muluh_i32 1
|
||||||
|
#define TCG_TARGET_HAS_mulsh_i32 1
|
||||||
|
#define TCG_TARGET_HAS_qemu_st8_i32 0
|
||||||
|
#define TCG_TARGET_HAS_mulu2_i32 1
|
||||||
|
#define TCG_TARGET_HAS_add2_i32 1
|
||||||
|
#define TCG_TARGET_HAS_sub2_i32 1
|
||||||
|
|
||||||
|
#define TCG_TARGET_HAS_bswap16_i64 1
|
||||||
|
#define TCG_TARGET_HAS_bswap32_i64 1
|
||||||
|
#define TCG_TARGET_HAS_bswap64_i64 1
|
||||||
|
#define TCG_TARGET_HAS_div_i64 1
|
||||||
|
#define TCG_TARGET_HAS_rem_i64 1
|
||||||
|
#define TCG_TARGET_HAS_ext8s_i64 1
|
||||||
|
#define TCG_TARGET_HAS_ext16s_i64 1
|
||||||
|
#define TCG_TARGET_HAS_ext8u_i64 1
|
||||||
|
#define TCG_TARGET_HAS_ext16u_i64 1
|
||||||
|
#define TCG_TARGET_HAS_ext32u_i64 1
|
||||||
|
#define TCG_TARGET_HAS_ext32s_i64 1
|
||||||
|
#define TCG_TARGET_HAS_andc_i64 1
|
||||||
|
#define TCG_TARGET_HAS_deposit_i64 1
|
||||||
|
#define TCG_TARGET_HAS_extract_i64 1
|
||||||
|
#define TCG_TARGET_HAS_sextract_i64 1
|
||||||
|
#define TCG_TARGET_HAS_extract2_i64 1
|
||||||
|
#define TCG_TARGET_HAS_extrl_i64_i32 1
|
||||||
|
#define TCG_TARGET_HAS_extrh_i64_i32 1
|
||||||
|
#define TCG_TARGET_HAS_eqv_i64 1
|
||||||
|
#define TCG_TARGET_HAS_nand_i64 1
|
||||||
|
#define TCG_TARGET_HAS_nor_i64 1
|
||||||
|
#define TCG_TARGET_HAS_clz_i64 1
|
||||||
|
#define TCG_TARGET_HAS_ctz_i64 1
|
||||||
|
#define TCG_TARGET_HAS_ctpop_i64 1
|
||||||
|
#define TCG_TARGET_HAS_neg_i64 1
|
||||||
|
#define TCG_TARGET_HAS_not_i64 1
|
||||||
|
#define TCG_TARGET_HAS_orc_i64 1
|
||||||
|
#define TCG_TARGET_HAS_rot_i64 1
|
||||||
|
#define TCG_TARGET_HAS_movcond_i64 1
|
||||||
|
#define TCG_TARGET_HAS_muls2_i64 0
|
||||||
|
#define TCG_TARGET_HAS_mulu2_i64 0
|
||||||
|
#define TCG_TARGET_HAS_muluh_i64 0
|
||||||
|
#define TCG_TARGET_HAS_mulsh_i64 0
|
||||||
|
#define TCG_TARGET_HAS_qemu_st8_i64 0
|
||||||
|
#define TCG_TARGET_HAS_add2_i64 1
|
||||||
|
#define TCG_TARGET_HAS_sub2_i64 1
|
||||||
|
|
||||||
|
#define TCG_TARGET_HAS_qemu_ldst_i128 0
|
||||||
|
|
||||||
|
/* Number of registers available. */
|
||||||
|
#define TCG_TARGET_NB_REGS 24
|
||||||
|
|
||||||
|
/* List of registers which are used by TCG. */
|
||||||
|
typedef enum {
|
||||||
|
TCG_REG_R0 = 0,
|
||||||
|
TCG_REG_R1,
|
||||||
|
TCG_REG_R2,
|
||||||
|
TCG_REG_R3,
|
||||||
|
TCG_REG_R4,
|
||||||
|
TCG_REG_R5,
|
||||||
|
TCG_REG_R6,
|
||||||
|
TCG_REG_R7,
|
||||||
|
TCG_REG_R8,
|
||||||
|
TCG_REG_R9,
|
||||||
|
TCG_REG_R10,
|
||||||
|
TCG_REG_R11,
|
||||||
|
TCG_REG_R12,
|
||||||
|
TCG_REG_R13,
|
||||||
|
TCG_REG_R14,
|
||||||
|
TCG_REG_R15,
|
||||||
|
|
||||||
|
// Arguments
|
||||||
|
TCG_REG_A0,
|
||||||
|
TCG_REG_A1,
|
||||||
|
TCG_REG_A2,
|
||||||
|
TCG_REG_A3,
|
||||||
|
TCG_REG_A4,
|
||||||
|
TCG_REG_A5,
|
||||||
|
TCG_REG_A6,
|
||||||
|
TCG_REG_A7,
|
||||||
|
|
||||||
|
TCG_REG_TMP = TCG_REG_R13,
|
||||||
|
TCG_AREG0 = TCG_REG_R14,
|
||||||
|
TCG_REG_CALL_STACK = TCG_REG_R15,
|
||||||
|
} TCGReg;
|
||||||
|
|
||||||
|
/* Used for function call generation. */
|
||||||
|
#define TCG_TARGET_CALL_STACK_OFFSET 0
|
||||||
|
#define TCG_TARGET_STACK_ALIGN 8
|
||||||
|
#define TCG_TARGET_CALL_ARG_I32 TCG_CALL_ARG_NORMAL
|
||||||
|
#define TCG_TARGET_CALL_ARG_I64 TCG_CALL_ARG_NORMAL
|
||||||
|
#define TCG_TARGET_CALL_ARG_I128 TCG_CALL_ARG_NORMAL
|
||||||
|
#define TCG_TARGET_CALL_RET_I128 TCG_CALL_RET_NORMAL
|
||||||
|
|
||||||
|
#define HAVE_TCG_QEMU_TB_EXEC
|
||||||
|
|
||||||
|
#define TCG_TARGET_DEFAULT_MO (0)
|
||||||
|
|
||||||
|
#define TCG_TARGET_HAS_MEMORY_BSWAP 0
|
||||||
|
|
||||||
|
#endif /* TCG_TARGET_H */
|
||||||
+1
-1
@@ -225,7 +225,7 @@ static void __attribute__((constructor)) init_cache_info(void)
|
|||||||
* Architecture (+ OS) specific cache flushing mechanisms.
|
* Architecture (+ OS) specific cache flushing mechanisms.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(__i386__) || defined(__x86_64__) || defined(__s390__)
|
#if defined(__i386__) || defined(__x86_64__) || defined(__s390__) || defined(EMSCRIPTEN)
|
||||||
|
|
||||||
/* Caches are coherent and do not require flushing; symbol inline. */
|
/* Caches are coherent and do not require flushing; symbol inline. */
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* emscripten fiber coroutine initialization code
|
||||||
|
* based on coroutine-ucontext.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
|
||||||
|
* Copyright (C) 2011 Kevin Wolf <kwolf@redhat.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.0 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/coroutine_int.h"
|
||||||
|
#include "qemu/coroutine-tls.h"
|
||||||
|
|
||||||
|
#include <emscripten/fiber.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Coroutine base;
|
||||||
|
|
||||||
|
void *asyncify_stack;
|
||||||
|
size_t asyncify_stack_size;
|
||||||
|
|
||||||
|
CoroutineAction action;
|
||||||
|
|
||||||
|
emscripten_fiber_t fiber;
|
||||||
|
} CoroutineEmscripten;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Per-thread coroutine bookkeeping
|
||||||
|
*/
|
||||||
|
QEMU_DEFINE_STATIC_CO_TLS(Coroutine *, current);
|
||||||
|
QEMU_DEFINE_STATIC_CO_TLS(CoroutineEmscripten *, leader);
|
||||||
|
size_t leader_asyncify_stack_size = COROUTINE_STACK_SIZE;
|
||||||
|
|
||||||
|
static void coroutine_trampoline(void *co_)
|
||||||
|
{
|
||||||
|
Coroutine *co = co_;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
co->entry(co->entry_arg);
|
||||||
|
qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Coroutine *qemu_coroutine_new(void)
|
||||||
|
{
|
||||||
|
CoroutineEmscripten *co;
|
||||||
|
|
||||||
|
co = g_malloc0(sizeof(*co));
|
||||||
|
|
||||||
|
size_t stack_size = COROUTINE_STACK_SIZE;
|
||||||
|
char *stack = qemu_alloc_stack(&stack_size);
|
||||||
|
|
||||||
|
co->asyncify_stack_size = COROUTINE_STACK_SIZE;
|
||||||
|
co->asyncify_stack = g_malloc0(co->asyncify_stack_size);
|
||||||
|
emscripten_fiber_init(&co->fiber, coroutine_trampoline, &co->base,
|
||||||
|
stack, stack_size, co->asyncify_stack, co->asyncify_stack_size);
|
||||||
|
|
||||||
|
return &co->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qemu_coroutine_delete(Coroutine *co_)
|
||||||
|
{
|
||||||
|
CoroutineEmscripten *co = DO_UPCAST(CoroutineEmscripten, base, co_);
|
||||||
|
|
||||||
|
g_free(co->asyncify_stack);
|
||||||
|
g_free(co);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "../tcg/wasm32.h"
|
||||||
|
|
||||||
|
CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
|
||||||
|
CoroutineAction action)
|
||||||
|
{
|
||||||
|
CoroutineEmscripten *from = DO_UPCAST(CoroutineEmscripten, base, from_);
|
||||||
|
CoroutineEmscripten *to = DO_UPCAST(CoroutineEmscripten, base, to_);
|
||||||
|
|
||||||
|
set_unwinding_flag();
|
||||||
|
|
||||||
|
set_current(to_);
|
||||||
|
to->action = action;
|
||||||
|
emscripten_fiber_swap(&from->fiber, &to->fiber);
|
||||||
|
return from->action;
|
||||||
|
}
|
||||||
|
|
||||||
|
Coroutine *qemu_coroutine_self(void)
|
||||||
|
{
|
||||||
|
Coroutine *self = get_current();
|
||||||
|
|
||||||
|
if (!self) {
|
||||||
|
CoroutineEmscripten *leaderp = get_leader();
|
||||||
|
if (!leaderp) {
|
||||||
|
leaderp = g_malloc0(sizeof(*leaderp));
|
||||||
|
leaderp->asyncify_stack = g_malloc0(leader_asyncify_stack_size);
|
||||||
|
leaderp->asyncify_stack_size = leader_asyncify_stack_size;
|
||||||
|
emscripten_fiber_init_from_current_context(&leaderp->fiber, leaderp->asyncify_stack, leaderp->asyncify_stack_size);
|
||||||
|
set_leader(leaderp);
|
||||||
|
}
|
||||||
|
self = &leaderp->base;
|
||||||
|
set_current(self);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool qemu_in_coroutine(void)
|
||||||
|
{
|
||||||
|
Coroutine *self = get_current();
|
||||||
|
|
||||||
|
return self && self->caller;
|
||||||
|
}
|
||||||
+1
-1
@@ -144,7 +144,7 @@ Int128 int128_rems(Int128 a, Int128 b)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(CONFIG_TCG_INTERPRETER)
|
#elif defined(CONFIG_TCG_INTERPRETER) || defined(EMSCRIPTEN)
|
||||||
|
|
||||||
Int128 int128_divu(Int128 a_s, Int128 b_s)
|
Int128 int128_divu(Int128 a_s, Int128 b_s)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -250,6 +250,11 @@ void *qemu_ram_mmap(int fd,
|
|||||||
uint32_t qemu_map_flags,
|
uint32_t qemu_map_flags,
|
||||||
off_t map_offset)
|
off_t map_offset)
|
||||||
{
|
{
|
||||||
|
#if defined(EMSCRIPTEN)
|
||||||
|
void *ptr;
|
||||||
|
ptr = mmap_activate(0, size + align, fd, qemu_map_flags, map_offset);
|
||||||
|
return (void *)QEMU_ALIGN_UP((uintptr_t)ptr, align);
|
||||||
|
#else
|
||||||
const size_t guard_pagesize = mmap_guard_pagesize(fd);
|
const size_t guard_pagesize = mmap_guard_pagesize(fd);
|
||||||
size_t offset, total;
|
size_t offset, total;
|
||||||
void *ptr, *guardptr;
|
void *ptr, *guardptr;
|
||||||
@@ -292,6 +297,7 @@ void *qemu_ram_mmap(int fd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_ram_munmap(int fd, void *ptr, size_t size)
|
void qemu_ram_munmap(int fd, void *ptr, size_t size)
|
||||||
|
|||||||
Reference in New Issue
Block a user