From a9107951a7a742d8652d81e08e4b7c01375ea6d6 Mon Sep 17 00:00:00 2001 From: Rodrigo Kumpera Date: Tue, 22 Aug 2017 16:24:53 -0700 Subject: [PATCH] [mini] Add skeleton WebAssembly mini backend. It's not functional and some code needs to be shuffled to better places. The wasm backend is inspired on the x86 one with a few key differences: 1) It assumes a different aot runtime will be used to deal with all the weirdness of wasm. In particular, it can run under MONO_AOT_MODE_INTERP_LLVMONLY without an actual working AOT compiler. 2) It's the only non-ISA based backend, so lots of weird things. Like, no registers or addressable stack - for realsies. --- configure.ac | 1 + mono/mini/Makefile.am.in | 24 +++- mono/mini/aot-runtime-wasm.c | 88 ++++++++++++ mono/mini/aot-runtime.c | 4 + mono/mini/cpu-wasm.md | 0 mono/mini/exceptions-wasm.c | 34 +++++ mono/mini/genmdesc.pl | 6 +- mono/mini/mini-arch.h | 2 + mono/mini/mini-wasm.c | 265 +++++++++++++++++++++++++++++++++++ mono/mini/mini-wasm.h | 50 +++++++ mono/mini/tramp-wasm.c | 54 +++++++ 11 files changed, 525 insertions(+), 3 deletions(-) create mode 100644 mono/mini/aot-runtime-wasm.c create mode 100644 mono/mini/cpu-wasm.md create mode 100644 mono/mini/exceptions-wasm.c mode change 100644 => 100755 mono/mini/genmdesc.pl create mode 100644 mono/mini/mini-wasm.c create mode 100644 mono/mini/mini-wasm.h create mode 100644 mono/mini/tramp-wasm.c diff --git a/configure.ac b/configure.ac index c3000129cfc..5112665a15e 100644 --- a/configure.ac +++ b/configure.ac @@ -4340,6 +4340,7 @@ AM_CONDITIONAL(POWERPC64, test x$TARGET = xPOWERPC64) AM_CONDITIONAL(ARM, test x$TARGET = xARM) AM_CONDITIONAL(ARM64, test x$TARGET = xARM64) AM_CONDITIONAL(S390X, test x$TARGET = xS390X) +AM_CONDITIONAL(WASM, test x$TARGET = xWASM) AM_CONDITIONAL(HOST_X86, test x$HOST = xX86) AM_CONDITIONAL(HOST_AMD64, test x$HOST = xAMD64) AM_CONDITIONAL(HOST_ARM, test x$HOST = xARM) diff --git a/mono/mini/Makefile.am.in b/mono/mini/Makefile.am.in index e33441b6d35..28fb9ee5b8d 100755 --- a/mono/mini/Makefile.am.in +++ b/mono/mini/Makefile.am.in @@ -312,6 +312,12 @@ genmdesc_LDADD = \ $(GLIB_LIBS) \ $(LIBICONV) +wasm_sources = \ + mini-wasm.c \ + mini-wasm.h \ + exceptions-wasm.c \ + tramp-wasm.c + x86_sources = \ mini-x86.c \ mini-x86.h \ @@ -456,6 +462,7 @@ common_sources = \ aot-compiler.h \ aot-compiler.c \ aot-runtime.c \ + aot-runtime-wasm.c \ graph.c \ mini-codegen.c \ mini-exceptions.c \ @@ -541,6 +548,12 @@ endif regtests = $(filter-out $(regtests_DISABLED),$(regtests_UNIVERSAL)) +if WASM +arch_sources = $(wasm_sources) +arch_built=cpu-wasm.h +arch_define=__wasm__ +endif + if X86 arch_sources = $(x86_sources) arch_built=cpu-x86.h @@ -687,12 +700,20 @@ GENMDESC_OPTS= # build dependency for the poor windows users # $(arch_define) is the preprocessor symbol that enables all the opcodes # for the specific platform in mini-ops.h + if CROSS_COMPILING GENMDESC_PRG=perl $(srcdir)/genmdesc.pl $(arch_define) $(srcdir) $(GENMDESC_OPTS) -else !CROSS_COMPILING +else +if WASM +GENMDESC_PRG=perl $(srcdir)/genmdesc.pl $(arch_define) $(srcdir) $(GENMDESC_OPTS) +else GENMDESC_PRG=./genmdesc $(GENMDESC_OPTS) +endif endif !CROSS_COMPILING +cpu-wasm.h: cpu-wasm.md genmdesc$(EXEEXT) + $(GENMDESC_PRG) cpu-wasm.h wasm_desc $(srcdir)/cpu-wasm.md + cpu-x86.h: cpu-x86.md genmdesc$(EXEEXT) $(GENMDESC_PRG) cpu-x86.h x86_desc $(srcdir)/cpu-x86.md @@ -882,6 +903,7 @@ EXTRA_DIST = TestDriver.cs \ TestHelpers.cs \ genmdesc.pl \ $(test_sources) \ + $(wasm_sources) cpu-wasm.md \ $(x86_sources) cpu-x86.md \ $(amd64_sources) cpu-amd64.md \ $(ppc_sources) cpu-ppc.md cpu-ppc64.md \ diff --git a/mono/mini/aot-runtime-wasm.c b/mono/mini/aot-runtime-wasm.c new file mode 100644 index 00000000000..7025fa8173d --- /dev/null +++ b/mono/mini/aot-runtime-wasm.c @@ -0,0 +1,88 @@ +/** + * \file + * WASM AOT runtime + */ + +#include "config.h" + +#include + +#include "mini.h" +#include "interp/interp.h" + +#ifdef TARGET_WASM + +static void +wasm_restore_context (void) +{ + g_error ("wasm_restore_context"); +} + +static void +wasm_call_filter (void) +{ + g_error ("wasm_call_filter"); +} + +static void +wasm_throw_exception (void) +{ + g_error ("wasm_throw_exception"); +} + +static void +wasm_rethrow_exception (void) +{ + g_error ("wasm_rethrow_exception"); +} + +static void +wasm_throw_corlib_exception (void) +{ + g_error ("wasm_throw_corlib_exception"); +} + +static void +wasm_enter_icall_trampoline (void *target_func, InterpMethodArguments *margs) +{ + g_error ("wasm_enter_icall_trampoline"); + +} + +gpointer +mono_aot_get_trampoline_full (const char *name, MonoTrampInfo **out_tinfo) +{ + gpointer code = NULL; + + if (!strcmp (name, "restore_context")) + code = wasm_restore_context; + else if (!strcmp (name, "call_filter")) + code = wasm_call_filter; + else if (!strcmp (name, "throw_exception")) + code = wasm_throw_exception; + else if (!strcmp (name, "rethrow_exception")) + code = wasm_rethrow_exception; + else if (!strcmp (name, "throw_corlib_exception")) + code = wasm_throw_corlib_exception; + else if (!strcmp (name, "enter_icall_trampoline")) + code = wasm_enter_icall_trampoline; + + g_assert (code); + + if (out_tinfo) { + MonoTrampInfo *tinfo = g_new0 (MonoTrampInfo, 1); + tinfo->code = code; + tinfo->code_size = 1; + tinfo->name = g_strdup (name); + tinfo->ji = NULL; + tinfo->unwind_ops = NULL; + tinfo->uw_info = NULL; + tinfo->uw_info_len = 0; + tinfo->owns_uw_info = FALSE; + + *out_tinfo = tinfo; + } + + return code; +} +#endif \ No newline at end of file diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index d6c2486414f..4e86a5a3f32 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -5143,6 +5143,8 @@ no_trampolines (void) g_assert_not_reached (); } + +#ifndef TARGET_WASM /* * Return the trampoline identified by NAME from the mscorlib AOT file. * On ppc64, this returns a function descriptor. @@ -5159,6 +5161,8 @@ mono_aot_get_trampoline_full (const char *name, MonoTrampInfo **out_tinfo) return mono_create_ftnptr_malloc ((guint8 *)load_function_full (amodule, name, out_tinfo)); } +#endif + gpointer mono_aot_get_trampoline (const char *name) diff --git a/mono/mini/cpu-wasm.md b/mono/mini/cpu-wasm.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/mono/mini/exceptions-wasm.c b/mono/mini/exceptions-wasm.c new file mode 100644 index 00000000000..63e72b0cd1f --- /dev/null +++ b/mono/mini/exceptions-wasm.c @@ -0,0 +1,34 @@ +#include "mini.h" + + +gpointer +mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) +{ + g_error ("mono_arch_get_call_filter"); + return NULL; +} + +gpointer +mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) +{ + g_error ("mono_arch_get_restore_context"); + return NULL; +} + +gboolean +mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, + MonoJitInfo *ji, MonoContext *ctx, + MonoContext *new_ctx, MonoLMF **lmf, + mgreg_t **save_locations, + StackFrameInfo *frame) +{ + g_error ("mono_arch_unwind_frame"); + return FALSE; +} + +gpointer +mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) +{ + g_error ("mono_arch_get_throw_corlib_exception"); + return NULL; +} \ No newline at end of file diff --git a/mono/mini/genmdesc.pl b/mono/mini/genmdesc.pl old mode 100644 new mode 100755 index 8c8e7eac640..ae49ecba9f2 --- a/mono/mini/genmdesc.pl +++ b/mono/mini/genmdesc.pl @@ -20,7 +20,7 @@ sub INST_MAX () {return 6;} # this must include all the #defines used in mini-ops.h my @defines = qw (__i386__ __x86_64__ __ppc__ __powerpc__ __ppc64__ __arm__ - __sparc__ sparc __s390__ s390 __alpha__ __mips__ __aarch64__); + __sparc__ sparc __s390__ s390 __alpha__ __mips__ __aarch64__ __wasm__); my %table =(); my %template_table =(); my @opcodes = (); @@ -88,7 +88,9 @@ sub load_opcodes if ($arch =~ "__aarch64__") { $arch_define = "TARGET_ARM64"; } - + if ($arch =~ "__wasm__") { + $arch_define = "TARGET_WASM"; + } parse_file ($arch_define, "$srcdir/mini-ops.h"); return; $cpp .= " -D$arch_define $srcdir/mini-ops.h|"; diff --git a/mono/mini/mini-arch.h b/mono/mini/mini-arch.h index eb50de0f5e4..c49ed5a41d5 100644 --- a/mono/mini/mini-arch.h +++ b/mono/mini/mini-arch.h @@ -25,6 +25,8 @@ #include "mini-arm64.h" #elif defined(__mips__) #include "mini-mips.h" +#elif TARGET_WASM +#include "mini-wasm.h" #else #error add arch specific include file in mini-arch.h #endif diff --git a/mono/mini/mini-wasm.c b/mono/mini/mini-wasm.c new file mode 100644 index 00000000000..acf71e89773 --- /dev/null +++ b/mono/mini/mini-wasm.c @@ -0,0 +1,265 @@ +#include "mini.h" + + +gpointer +mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code) +{ + g_error ("mono_arch_get_this_arg_from_call"); +} + +gpointer +mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg) +{ + g_error ("mono_arch_get_delegate_virtual_invoke_impl"); +} + + +void +mono_arch_cpu_init (void) +{ + // printf ("mono_arch_cpu_init\n"); +} + +void +mono_arch_finish_init (void) +{ + // printf ("mono_arch_finish_init\n"); +} + +void +mono_arch_init (void) +{ + // printf ("mono_arch_init\n"); +} + +void +mono_arch_cleanup (void) +{ +} + +void +mono_arch_register_lowlevel_calls (void) +{ +} + +void +mono_arch_flush_register_windows (void) +{ +} + +void +mono_arch_free_jit_tls_data (MonoJitTlsData *tls) +{ +} + + +MonoMethod* +mono_arch_find_imt_method (mgreg_t *regs, guint8 *code) +{ + g_error ("mono_arch_find_static_call_vtable"); + return (MonoMethod*) regs [MONO_ARCH_IMT_REG]; +} + +MonoVTable* +mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code) +{ + g_error ("mono_arch_find_static_call_vtable"); + return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG]; +} + +gpointer +mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp) +{ + g_error ("mono_arch_build_imt_trampoline"); +} + +guint32 +mono_arch_cpu_enumerate_simd_versions (void) +{ + return 0; +} + +guint32 +mono_arch_cpu_optimizations (guint32 *exclude_mask) +{ + return 0; +} + +GSList* +mono_arch_get_delegate_invoke_impls (void) +{ + g_error ("mono_arch_get_delegate_invoke_impls"); + return NULL; +} + +gpointer +mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target) +{ + g_error ("mono_arch_get_delegate_invoke_impl"); + return NULL; +} + +mgreg_t +mono_arch_context_get_int_reg (MonoContext *ctx, int reg) +{ + g_error ("mono_arch_context_get_int_reg"); + return 0; +} + +int +mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info) +{ + g_error ("mono_arch_get_argument_info"); + return 0; + +} + +void +mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf) +{ + ext->lmf.previous_lmf = (gsize)prev_lmf; + /* Mark that this is a MonoLMFExt */ + ext->lmf.previous_lmf = (gsize)(gpointer)(((gssize)ext->lmf.previous_lmf) | 2); +} + + + +void +mono_runtime_setup_stat_profiler (void) +{ + g_error ("mono_runtime_setup_stat_profiler"); +} + + +void +mono_runtime_shutdown_stat_profiler (void) +{ + g_error ("mono_runtime_shutdown_stat_profiler"); +} + + +gboolean +MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal) +{ + g_error ("mono_chain_signal"); + + return FALSE; +} + +void +mono_runtime_install_handlers (void) +{ +} + +void +mono_runtime_cleanup_handlers (void) +{ +} + +gboolean +mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info) +{ + g_error ("WASM systems don't support mono_thread_state_init_from_handle"); + return FALSE; +} + + +/* +The following functions don't belong here, but are due to laziness. +*/ + +//w32file-wasm.c +gboolean +mono_w32file_get_volume_information (const gunichar2 *path, gunichar2 *volumename, gint volumesize, gint *outserial, gint *maxcomp, gint *fsflags, gunichar2 *fsbuffer, gint fsbuffersize) +{ + g_error ("mono_w32file_get_volume_information"); +} + + +//llvm builtin's that we should not have used in the first place +gpointer +llvm_returnaddress (void) +{ + g_error ("llvm_returnaddress"); + return NULL; +} + +void +llvm_eh_unwind_init (void) +{ + g_error ("llvm_eh_unwind_init"); +} + + +//libc / libpthread missing bits from musl or shit we didn't detect :facepalm: +int pthread_getschedparam (pthread_t thread, int *policy, struct sched_param *param) +{ + g_error ("pthread_getschedparam"); + return 0; +} + +int +pthread_attr_getstacksize (const pthread_attr_t *restrict attr, size_t *restrict stacksize) +{ + return 65536; //wasm page size +} + +int +pthread_sigmask (int how, const sigset_t * restrict set, sigset_t * restrict oset) +{ + return 0; +} + + +int +sigsuspend(const sigset_t *sigmask) +{ + g_error ("sigsuspend"); + return 0; +} + +int +getdtablesize (void) +{ + return 256; //random constant that is the fd limit +} + +void * +getgrnam (const char *name) +{ + return NULL; +} + +void * +getgrgid (gid_t gid) +{ + return NULL; +} + +int +inotify_init (void) +{ + g_error ("inotify_init"); +} + +int +inotify_rm_watch (int fd, int wd) +{ + g_error ("inotify_rm_watch"); + return 0; +} + +int +inotify_add_watch (int fd, const char *pathname, uint32_t mask) +{ + g_error ("inotify_add_watch"); + return 0; +} + +int +sem_timedwait (sem_t *sem, const struct timespec *abs_timeout) +{ + g_error ("sem_timedwait"); + return 0; + +} diff --git a/mono/mini/mini-wasm.h b/mono/mini/mini-wasm.h new file mode 100644 index 00000000000..8205dc1b561 --- /dev/null +++ b/mono/mini/mini-wasm.h @@ -0,0 +1,50 @@ +#ifndef __MONO_MINI_WASM_H__ +#define __MONO_MINI_WASM_H__ + +#include +#include + +#define MONO_ARCH_CPU_SPEC mono_wasm_desc + +#define MONO_ARCH_HAVE_INIT_LMF_EXT 1 + +#define MONO_MAX_IREGS 1 +#define MONO_MAX_FREGS 1 + +#define WASM_REG_0 0 + + +struct MonoLMF { + /* + * If the second lowest bit is set to 1, then this is a MonoLMFExt structure, and + * the other fields are not valid. + */ + gpointer previous_lmf; + gpointer lmf_addr; + + /* This is only set in trampoline LMF frames */ + MonoMethod *method; + + gboolean top_entry; +}; + +typedef struct { + int dummy; +} MonoCompileArch; + +#define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf) do { (lmf)->top_entry = TRUE; } while (0) + +#define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->llvm_exc_reg = (gsize)exc; } while (0) + +#define MONO_INIT_CONTEXT_FROM_FUNC(ctx,start_func) do { \ + MONO_CONTEXT_SET_IP ((ctx), (start_func)); \ + MONO_CONTEXT_SET_BP ((ctx), (0)); \ + MONO_CONTEXT_SET_SP ((ctx), (0)); \ + } while (0) + + +#define MONO_ARCH_VTABLE_REG WASM_REG_0 +#define MONO_ARCH_IMT_REG WASM_REG_0 +#define MONO_ARCH_RGCTX_REG WASM_REG_0 + +#endif /* __MONO_MINI_WASM_H__ */ diff --git a/mono/mini/tramp-wasm.c b/mono/mini/tramp-wasm.c new file mode 100644 index 00000000000..50447fbae56 --- /dev/null +++ b/mono/mini/tramp-wasm.c @@ -0,0 +1,54 @@ +#include "mini.h" + + +gpointer +mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len) +{ + g_error ("mono_arch_create_specific_trampoline"); +} + +guchar* +mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot) +{ + g_error ("mono_arch_create_generic_trampoline"); +} + +gpointer +mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot) +{ + g_error ("mono_arch_create_rgctx_lazy_fetch_trampoline"); +} + +void +mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr) +{ + g_error ("mono_arch_patch_plt_entry"); +} + +gpointer +mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info) +{ + printf ("mono_arch_get_enter_icall_trampoline"); + g_assert (0); + return NULL; +} + +void +mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr) +{ + g_error ("mono_arch_patch_callsite"); +} + +gpointer +mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) +{ + g_error ("mono_arch_get_unbox_trampoline"); + return NULL; +} + +gpointer +mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr) +{ + g_error ("mono_arch_get_static_rgctx_trampoline"); + return NULL; +} \ No newline at end of file -- 2.25.1