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
|
||||
*/
|
||||
|
||||
#if !defined(CONFIG_TCG_INTERPRETER) && defined(EMSCRIPTEN)
|
||||
#include "../../tcg/wasm32.h"
|
||||
#endif
|
||||
|
||||
tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
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,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
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,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
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,
|
||||
MemOpIdx oi, uintptr_t retaddr)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@@ -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);
|
||||
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,
|
||||
@@ -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);
|
||||
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,
|
||||
@@ -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);
|
||||
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,
|
||||
@@ -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);
|
||||
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,
|
||||
@@ -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);
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* remove any jumps to the TB */
|
||||
|
||||
@@ -110,6 +110,10 @@
|
||||
#include <sys/diskslice.h>
|
||||
#endif
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
/* OS X does not have O_DSYNC */
|
||||
#ifndef O_DSYNC
|
||||
#ifdef O_SYNC
|
||||
@@ -2002,6 +2006,13 @@ static int handle_aiocb_write_zeroes_unmap(void *opaque)
|
||||
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
|
||||
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)
|
||||
@@ -2015,6 +2026,7 @@ static off_t copy_file_range(int in_fd, off_t *in_off, int out_fd,
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* parse_zone - Fill a zone descriptor
|
||||
|
||||
@@ -340,7 +340,9 @@ int main(void) { return 0; }
|
||||
EOF
|
||||
}
|
||||
|
||||
if check_define __linux__ ; then
|
||||
if check_define __EMSCRIPTEN__ ; then
|
||||
host_os=linux
|
||||
elif check_define __linux__ ; then
|
||||
host_os=linux
|
||||
elif check_define _WIN32 ; then
|
||||
host_os=windows
|
||||
@@ -526,6 +528,10 @@ case "$cpu" in
|
||||
linux_arch=x86
|
||||
CPU_CFLAGS="-m64"
|
||||
;;
|
||||
wasm32)
|
||||
host_arch=wasm32
|
||||
CPU_CFLAGS="-m32"
|
||||
;;
|
||||
esac
|
||||
|
||||
# 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
|
||||
s->info.endian = BFD_ENDIAN_LITTLE;
|
||||
#endif
|
||||
#if defined(CONFIG_TCG_INTERPRETER)
|
||||
#if defined(CONFIG_TCG_INTERPRETER) || defined(EMSCRIPTEN)
|
||||
s->info.print_insn = print_insn_tci;
|
||||
#elif defined(__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);
|
||||
|
||||
/* 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;
|
||||
# define GETPC() tci_tb_ptr
|
||||
#else
|
||||
|
||||
@@ -75,7 +75,6 @@
|
||||
#else
|
||||
# define ATOMIC_REG_SIZE sizeof(void *)
|
||||
#endif
|
||||
|
||||
/* Weak atomic operations prevent the compiler moving other
|
||||
* loads/stores past the atomic operation load/store. However there is
|
||||
* no explicit memory barrier for the processor.
|
||||
@@ -91,7 +90,7 @@
|
||||
|
||||
#define qatomic_read(ptr) \
|
||||
({ \
|
||||
qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \
|
||||
/*qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE);*/ \
|
||||
qatomic_read__nocheck(ptr); \
|
||||
})
|
||||
|
||||
@@ -99,7 +98,7 @@
|
||||
__atomic_store_n(ptr, i, __ATOMIC_RELAXED)
|
||||
|
||||
#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); \
|
||||
} while(0)
|
||||
|
||||
@@ -122,7 +121,7 @@
|
||||
*/
|
||||
#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; \
|
||||
qatomic_rcu_read__nocheck(ptr, &_val); \
|
||||
_val; \
|
||||
@@ -131,20 +130,20 @@
|
||||
qatomic_rcu_read_internal((ptr), MAKE_IDENTIFIER(_val))
|
||||
|
||||
#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); \
|
||||
} while(0)
|
||||
|
||||
#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; \
|
||||
__atomic_load(ptr, &_val, __ATOMIC_ACQUIRE); \
|
||||
_val; \
|
||||
})
|
||||
|
||||
#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); \
|
||||
} while(0)
|
||||
|
||||
@@ -156,7 +155,7 @@
|
||||
})
|
||||
|
||||
#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); \
|
||||
})
|
||||
|
||||
@@ -169,7 +168,7 @@
|
||||
})
|
||||
|
||||
#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); \
|
||||
})
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* 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)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* But libffi does not support __int128_t, and therefore cannot pass
|
||||
* 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 __attribute__((aligned(16))) Int128Aligned;
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ QEMU_EXTERN_C int daemon(int, int);
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef CONFIG_IOVEC
|
||||
#if defined(CONFIG_IOVEC) || defined(EMSCRIPTEN)
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
@@ -281,6 +281,7 @@ void QEMU_ERROR("code path is reachable")
|
||||
#ifndef WCOREDUMP
|
||||
#define WCOREDUMP(status) 0
|
||||
#endif
|
||||
#ifndef EMSCRIPTEN
|
||||
/*
|
||||
* 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
|
||||
@@ -296,6 +297,7 @@ void QEMU_ERROR("code path is reachable")
|
||||
#ifdef G_DISABLE_ASSERT
|
||||
#error building with G_DISABLE_ASSERT is not supported
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef OFF_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);
|
||||
|
||||
#ifndef CONFIG_IOVEC
|
||||
#if !defined(CONFIG_IOVEC) && !defined(EMSCRIPTEN)
|
||||
struct iovec {
|
||||
void *iov_base;
|
||||
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_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);
|
||||
#else
|
||||
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']
|
||||
supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux']
|
||||
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()
|
||||
|
||||
@@ -482,7 +482,7 @@ ucontext_probe = '''
|
||||
# On Windows the only valid backend is the Windows specific one.
|
||||
# For POSIX prefer ucontext, but it's not always possible. The fallback
|
||||
# is sigcontext.
|
||||
supported_backends = []
|
||||
supported_backends = ['fiber']
|
||||
if host_os == 'windows'
|
||||
supported_backends += ['windows']
|
||||
else
|
||||
@@ -884,6 +884,8 @@ if get_option('tcg').allowed()
|
||||
tcg_arch = 'i386'
|
||||
elif host_arch == 'ppc64'
|
||||
tcg_arch = 'ppc'
|
||||
elif host_arch == 'wasm32'
|
||||
tcg_arch = 'wasm32'
|
||||
endif
|
||||
add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch,
|
||||
language: all_languages)
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ option('fuzzing_engine', type : 'string', value : '',
|
||||
option('trace_file', type: 'string', value: 'trace',
|
||||
description: 'Trace file prefix for simple backend')
|
||||
option('coroutine_backend', type: 'combo',
|
||||
choices: ['ucontext', 'sigaltstack', 'windows', 'auto'],
|
||||
choices: ['ucontext', 'sigaltstack', 'windows', 'auto', 'fiber'],
|
||||
value: 'auto', description: 'coroutine backend to use')
|
||||
|
||||
# Everything else can be set via --enable/--disable-* option
|
||||
|
||||
@@ -148,11 +148,13 @@ static void change_process_uid(void)
|
||||
exit(1);
|
||||
}
|
||||
if (user_pwd) {
|
||||
#ifndef EMSCRIPTEN
|
||||
if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) {
|
||||
error_report("Failed to initgroups(\"%s\", %d)",
|
||||
user_pwd->pw_name, user_pwd->pw_gid);
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
if (setgroups(1, &user_gid) < 0) {
|
||||
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" ' [NORMAL]'
|
||||
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" ' package'
|
||||
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',
|
||||
))
|
||||
|
||||
cpu = host_machine.cpu_family()
|
||||
|
||||
if get_option('tcg_interpreter')
|
||||
libffi = dependency('libffi', version: '>=3.0', required: true,
|
||||
method: 'pkg-config')
|
||||
@@ -29,6 +31,10 @@ endif
|
||||
|
||||
tcg_ss = tcg_ss.apply({})
|
||||
|
||||
if cpu == 'wasm32'
|
||||
specific_ss.add(files('wasm32.c'))
|
||||
endif
|
||||
|
||||
libtcg_user = static_library('tcg_user',
|
||||
tcg_ss.sources() + genh,
|
||||
dependencies: tcg_ss.dependencies(),
|
||||
|
||||
+3
-3
@@ -568,7 +568,7 @@ static int alloc_code_gen_buffer_anon(size_t size, int prot,
|
||||
return prot;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_TCG_INTERPRETER
|
||||
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||
#ifdef CONFIG_POSIX
|
||||
#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)
|
||||
{
|
||||
#ifndef CONFIG_TCG_INTERPRETER
|
||||
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||
# ifdef CONFIG_DARWIN
|
||||
return alloc_code_gen_buffer_splitwx_vmremap(size, errp);
|
||||
# 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.
|
||||
*/
|
||||
need_prot = PROT_READ | PROT_WRITE;
|
||||
#ifndef CONFIG_TCG_INTERPRETER
|
||||
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||
if (tcg_splitwx_diff == 0) {
|
||||
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,
|
||||
const TCGArg 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
|
||||
static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
|
||||
TCGReg dst, TCGReg src);
|
||||
@@ -245,7 +249,7 @@ TCGv_env tcg_env;
|
||||
const void *tcg_code_gen_epilogue;
|
||||
uintptr_t tcg_splitwx_diff;
|
||||
|
||||
#ifndef CONFIG_TCG_INTERPRETER
|
||||
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||
tcg_prologue_fn *tcg_qemu_tb_exec;
|
||||
#endif
|
||||
|
||||
@@ -352,6 +356,9 @@ static void tcg_out_label(TCGContext *s, TCGLabel *l)
|
||||
tcg_debug_assert(!l->has_value);
|
||||
l->has_value = 1;
|
||||
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)
|
||||
@@ -420,6 +427,114 @@ tlb_mask_table_ofs(TCGContext *s, int which)
|
||||
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. */
|
||||
static G_NORETURN
|
||||
void tcg_raise_tb_overflow(TCGContext *s)
|
||||
@@ -937,7 +1052,7 @@ static TCGHelperInfo info_helper_st128_mmu = {
|
||||
| dh_typemask(ptr, 5) /* uintptr_t ra */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TCG_INTERPRETER
|
||||
#if defined(CONFIG_TCG_INTERPRETER)
|
||||
static ffi_type *typecode_to_ffi(int argmask)
|
||||
{
|
||||
/*
|
||||
@@ -1406,12 +1521,11 @@ void tcg_prologue_init(void)
|
||||
{
|
||||
TCGContext *s = tcg_ctx;
|
||||
size_t prologue_size;
|
||||
|
||||
s->code_ptr = s->code_gen_ptr;
|
||||
s->code_buf = s->code_gen_ptr;
|
||||
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);
|
||||
#endif
|
||||
|
||||
@@ -1434,7 +1548,7 @@ void tcg_prologue_init(void)
|
||||
prologue_size = tcg_current_code_size(s);
|
||||
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),
|
||||
(uintptr_t)s->code_buf, prologue_size);
|
||||
#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.
|
||||
* 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);
|
||||
}
|
||||
|
||||
#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,
|
||||
bool load_sign,
|
||||
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->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
|
||||
QSIMPLEQ_INIT(&s->ldst_labels);
|
||||
#endif
|
||||
@@ -6286,13 +6559,85 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
|
||||
return -2;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_TCG_INTERPRETER
|
||||
#if !defined(CONFIG_TCG_INTERPRETER) && !defined(EMSCRIPTEN)
|
||||
/* flush instruction cache */
|
||||
flush_idcache_range((uintptr_t)tcg_splitwx_to_rx(s->code_buf),
|
||||
(uintptr_t)s->code_buf,
|
||||
tcg_ptr_byte_diff(s->code_ptr, s->code_buf));
|
||||
#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);
|
||||
}
|
||||
|
||||
|
||||
+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.
|
||||
*/
|
||||
|
||||
#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. */
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_TCG_INTERPRETER)
|
||||
#elif defined(CONFIG_TCG_INTERPRETER) || defined(EMSCRIPTEN)
|
||||
|
||||
Int128 int128_divu(Int128 a_s, Int128 b_s)
|
||||
{
|
||||
|
||||
@@ -250,6 +250,11 @@ void *qemu_ram_mmap(int fd,
|
||||
uint32_t qemu_map_flags,
|
||||
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);
|
||||
size_t offset, total;
|
||||
void *ptr, *guardptr;
|
||||
@@ -292,6 +297,7 @@ void *qemu_ram_mmap(int fd,
|
||||
}
|
||||
|
||||
return ptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_ram_munmap(int fd, void *ptr, size_t size)
|
||||
|
||||
Reference in New Issue
Block a user