Add support to the x86 backend for generating code compatible with Google
authorElijah Taylor <elijahtaylor@google.com>
Mon, 9 Aug 2010 15:41:51 +0000 (17:41 +0200)
committerZoltan Varga <vargaz@gmail.com>
Mon, 9 Aug 2010 15:41:51 +0000 (17:41 +0200)
Native Client codegen requirements.

16 files changed:
mono/mini/Makefile.am
mono/mini/aot-compiler.c
mono/mini/cpu-x86.md
mono/mini/driver.c
mono/mini/exceptions-x86.c
mono/mini/genmdesc.c
mono/mini/genmdesc.pl
mono/mini/image-writer.c
mono/mini/image-writer.h
mono/mini/method-to-ir.c
mono/mini/mini-posix.c
mono/mini/mini-x86.c
mono/mini/mini-x86.h
mono/mini/mini.c
mono/mini/mini.h
mono/mini/tramp-x86.c

index f4704b313d54b70c7a6273e1de4707ee582897e7..5bf3fe4375599a09afafd222a11c99213cf3cd1e 100644 (file)
@@ -369,6 +369,7 @@ test_sources =                      \
        basic-simd.cs
 
 regtests=basic.exe basic-float.exe basic-long.exe basic-calls.exe objects.exe arrays.exe basic-math.exe exceptions.exe iltests.exe devirtualization.exe generics.exe basic-simd.exe
+fsatests=basic.exe basic-float.exe basic-long.exe basic-calls.exe objects.exe arrays.exe basic-math.exe exceptions.exe devirtualization.exe basic-simd.exe
 
 if X86
 if MONO_DEBUGGER_SUPPORTED
@@ -542,14 +543,20 @@ TestDriver.dll: $(srcdir)/TestDriver.cs
 generics-variant-types.dll: generics-variant-types.il
        $(ILASM) -dll -output=$@ $<
 
+if NACL_CODEGEN
+GENMDESC_OPTS=--nacl
+else !NACL_CODEGEN
+GENMDESC_OPTS=
+endif !NACL_CODEGEN
+
 # we don't always use the perl impl because it's an additional
 # 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_PRG=perl $(srcdir)/genmdesc.pl $(arch_define) $(srcdir) $(GENMDESC_OPTS)
 else !CROSS_COMPILING
-GENMDESC_PRG=./genmdesc
+GENMDESC_PRG=./genmdesc $(GENMDESC_OPTS)
 endif !CROSS_COMPILING
 
 cpu-x86.h: cpu-x86.md genmdesc$(EXEEXT)
@@ -613,6 +620,20 @@ fullaotcheck: mono $(regtests)
        MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper --aot=full fullaot-tmp/* || exit 1
        for i in $(regtests); do echo $$i; MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper --full-aot fullaot-tmp/$$i --exclude '!FULLAOT' || exit 1; done
 
+fsacheck: mono $(fsatests) fsacheck.c generics.exe
+       rm -rf fsa-tmp
+       mkdir fsa-tmp
+       cp $(CLASS)/mscorlib.dll $(CLASS)/System.Core.dll $(CLASS)/System.dll $(CLASS)/Mono.Posix.dll $(CLASS)/System.Configuration.dll $(CLASS)/System.Security.dll $(CLASS)/System.Xml.dll $(CLASS)/Mono.Security.dll $(CLASS)/Mono.Simd.dll \
+       $(fsatests) generics-variant-types.dll TestDriver.dll fsa-tmp/
+       cp $(fsatests) fsa-tmp/
+       MONO_PATH=fsa-tmp $(top_builddir)/runtime/mono-wrapper --aot=full,static fsa-tmp/*.dll || exit 1
+       MONO_PATH=fsa-tmp $(top_builddir)/runtime/mono-wrapper --aot=full,static fsa-tmp/*.exe || exit 1
+       $(CC) -o $@.out -g -static $(VPATH)/fsacheck.c fsa-tmp/*.o \
+       -lmono-2.0 -lpthread -lm -ldl -lrt \
+       -DTARGET_X86 -L.libs -I${prefix}/include/mono-2.0 \
+       -I${prefix} -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
+       for i in $(fsatests); do echo $$i; MONO_PATH=fsa-tmp ./$@.out $$i || exit 1; done
+
 bench: mono test.exe
        time env $(RUNTIME) --ncompile $(count) --compile Test:$(mtest) test.exe
 
index 07e2c6c4c5d0dc3ad314c81c6722f5097afd627c..86ebb1dc28df93339857ebb631dc80d704447865 100644 (file)
@@ -68,7 +68,7 @@
 
 #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
 
-#if defined(__linux__)
+#if defined(__linux__) || defined(__native_client_codegen__)
 #define RODATA_SECT ".rodata"
 #else
 #define RODATA_SECT ".text"
@@ -330,6 +330,14 @@ emit_byte (MonoAotCompile *acfg, guint8 val)
        img_writer_emit_byte (acfg->w, val); 
 }
 
+#ifdef __native_client_codegen__
+static inline void
+emit_nacl_call_alignment (MonoAotCompile *acfg)
+{
+       img_writer_emit_nacl_call_alignment (acfg->w);
+}
+#endif
+
 static G_GNUC_UNUSED void
 emit_global_inner (MonoAotCompile *acfg, const char *name, gboolean func)
 {
@@ -460,6 +468,10 @@ encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
 #else
 #define AOT_FUNC_ALIGNMENT 16
 #endif
+#if defined(TARGET_X86) && defined(__native_client_codegen__)
+#undef AOT_FUNC_ALIGNMENT
+#define AOT_FUNC_ALIGNMENT 32
+#endif
  
 #if defined(TARGET_POWERPC64) && !defined(__mono_ilp32__)
 #define PPC_LD_OP "ld"
@@ -654,12 +666,26 @@ arch_emit_plt_entry (MonoAotCompile *acfg, int index)
 #if defined(TARGET_X86)
                guint32 offset = (acfg->plt_got_offset_base + index) * sizeof (gpointer);
 
+#ifdef __native_client_codegen__
+               const guint8 kSizeOfNaClJmp = 11;
+               guint8 bytes[kSizeOfNaClJmp];
+               guint8 *pbytes = &bytes[0];
+               
+               x86_jump_membase32 (pbytes, X86_EBX, offset);
+               emit_bytes (acfg, bytes, kSizeOfNaClJmp);
+               /* four bytes of data, used by mono_arch_patch_plt_entry              */
+               /* For Native Client, make this work with data embedded in push.      */
+               emit_byte (acfg, 0x68);  /* hide data in a push */
+               emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+               emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+#else
                /* jmp *<offset>(%ebx) */
                emit_byte (acfg, 0xff);
                emit_byte (acfg, 0xa3);
                emit_int32 (acfg, offset);
                /* Used by mono_aot_get_plt_info_offset */
                emit_int32 (acfg, acfg->plt_got_info_offsets [index]);
+#endif  /* __native_client_codegen__ */
 #elif defined(TARGET_AMD64)
                /*
                 * We can't emit jumps because they are 32 bits only so they can't be patched.
@@ -846,9 +872,16 @@ arch_emit_specific_trampoline (MonoAotCompile *acfg, int offset, int *tramp_size
        /* Branch to generic trampoline */
        x86_jump_reg (code, X86_ECX);
 
+#ifdef __native_client_codegen__
+       {
+               /* emit nops to next 32 byte alignment */
+               int a = (~kNaClAlignmentMask) & ((code - buf) + kNaClAlignment - 1);
+               while (code < (buf + a)) x86_nop(code);
+       }
+#endif
        emit_bytes (acfg, buf, code - buf);
 
-       *tramp_size = 17;
+       *tramp_size = NACL_SIZE(17, kNaClAlignment);
        g_assert (code - buf == *tramp_size);
 #else
        g_assert_not_reached ();
@@ -1028,9 +1061,17 @@ arch_emit_static_rgctx_trampoline (MonoAotCompile *acfg, int offset, int *tramp_
        /* Branch to the target address */
        x86_jump_membase (code, X86_ECX, (offset + 1) * sizeof (gpointer));
 
+#ifdef __native_client_codegen__
+       {
+               /* emit nops to next 32 byte alignment */
+               int a = (~kNaClAlignmentMask) & ((code - buf) + kNaClAlignment - 1);
+               while (code < (buf + a)) x86_nop(code);
+       }
+#endif
+
        emit_bytes (acfg, buf, code - buf);
 
-       *tramp_size = 15;
+       *tramp_size = NACL_SIZE (15, kNaClAlignment);
        g_assert (code - buf == *tramp_size);
 #else
        g_assert_not_reached ();
@@ -1099,9 +1140,17 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
        *tramp_size = code - buf + 7;
 #elif defined(TARGET_X86)
        guint8 *buf, *code;
+#ifdef __native_client_codegen__
+       guint8 *buf_alloc;
+#endif
        guint8 *labels [3];
 
+#ifdef __native_client_codegen__
+       buf_alloc = g_malloc (256 + kNaClAlignment);
+       code = buf = ((guint)buf_alloc + kNaClAlignment) & ~kNaClAlignmentMask;
+#else
        code = buf = g_malloc (256);
+#endif
 
        /* Allocate a temporary stack slot */
        x86_push_reg (code, X86_EAX);
@@ -1143,6 +1192,13 @@ arch_emit_imt_thunk (MonoAotCompile *acfg, int offset, int *tramp_size)
        mono_x86_patch (labels [1], code);
        x86_breakpoint (code);
 
+#ifdef __native_client_codegen__
+       {
+               /* emit nops to next 32 byte alignment */
+               int a = (~kNaClAlignmentMask) & ((code - buf) + kNaClAlignment - 1);
+               while (code < (buf + a)) x86_nop(code);
+       }
+#endif
        emit_bytes (acfg, buf, code - buf);
        
        *tramp_size = code - buf;
@@ -3806,13 +3862,17 @@ emit_trampoline (MonoAotCompile *acfg, int got_offset, MonoTrampInfo *info)
        ji = info->ji;
        unwind_ops = info->unwind_ops;
 
+#ifdef __native_client_codegen__
+       mono_nacl_fix_patches (code, ji);
+#endif
+
        /* Emit code */
 
        sprintf (start_symbol, "%s", name);
 
        emit_section_change (acfg, ".text", 0);
        emit_global (acfg, start_symbol, TRUE);
-       emit_alignment (acfg, 16);
+       emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
        emit_label (acfg, start_symbol);
 
        sprintf (symbol, "%snamed_%s", acfg->temp_prefix, name);
@@ -4011,7 +4071,7 @@ emit_trampolines (MonoAotCompile *acfg)
                        }
 
                        emit_global (acfg, symbol, TRUE);
-                       emit_alignment (acfg, 16);
+                       emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
                        emit_label (acfg, symbol);
 
                        acfg->trampoline_got_offset_base [ntype] = tramp_got_offset;
@@ -4035,6 +4095,10 @@ emit_trampolines (MonoAotCompile *acfg)
                                default:
                                        g_assert_not_reached ();
                                }
+#ifdef __native_client_codegen__
+                               /* align to avoid 32-byte boundary crossings */
+                               emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+#endif
 
                                if (!acfg->trampoline_size [ntype]) {
                                        g_assert (tramp_size);
@@ -4811,6 +4875,9 @@ emit_code (MonoAotCompile *acfg)
                        }
 
                        emit_section_change (acfg, ".text", 0);
+#ifdef __native_client_codegen__
+                       emit_alignment (acfg, AOT_FUNC_ALIGNMENT);
+#endif
                        emit_global (acfg, symbol, TRUE);
                        emit_label (acfg, symbol);
 
@@ -5683,7 +5750,7 @@ emit_globals (MonoAotCompile *acfg)
                 * Emit a global symbol which can be passed by an embedding app to
                 * mono_aot_register_module ().
                 */
-#if defined(__MACH__)
+#if defined(__MACH__) && !defined(__native_client_codegen__)
                sprintf (symbol, "_mono_aot_module_%s_info", acfg->image->assembly->aname.name);
 #else
                sprintf (symbol, "mono_aot_module_%s_info", acfg->image->assembly->aname.name);
@@ -5949,6 +6016,12 @@ compile_asm (MonoAotCompile *acfg)
 #define AS_OPTIONS ""
 #endif
 
+#ifdef __native_client_codegen__
+#define AS_NAME "nacl-as"
+#else
+#define AS_NAME "as"
+#endif
+
 #ifndef LD_OPTIONS
 #define LD_OPTIONS ""
 #endif
@@ -5974,7 +6047,7 @@ compile_asm (MonoAotCompile *acfg)
        } else {
                objfile = g_strdup_printf ("%s.o", acfg->tmpfname);
        }
-       command = g_strdup_printf ("%sas %s %s -o %s", tool_prefix, AS_OPTIONS, acfg->tmpfname, objfile);
+       command = g_strdup_printf ("%s%s %s %s -o %s", tool_prefix, AS_NAME, AS_OPTIONS, acfg->tmpfname, objfile);
        printf ("Executing the native assembler: %s\n", command);
        if (system (command) != 0) {
                g_free (command);
index 1bf85881928b64d361914b9c30ee36843c5d3401..f68950561a908025a05a6b233e37c42c5a17240e 100644 (file)
 # See the code in mini-x86.c for more details on how the specifiers are used.
 #
 break: len:1
-jmp: len:32
+jmp: len:32 clob:c
 call: dest:a clob:c len:17
 br: len:5
 seq_point: len:16
 
-int_beq: len:6 nacl:28
+int_beq: len:6
 int_bge: len:6
 int_bgt: len:6
 int_ble: len:6
@@ -117,8 +117,8 @@ int_mul_ovf_un: dest:i src1:i src2:i len:16
 throw: src1:i len:13
 rethrow: src1:i len:13
 start_handler: len:16
-endfinally: len:16
-endfilter: src1:a len:16
+endfinally: len:16 nacl:21
+endfilter: src1:a len:16 nacl:21
 
 ckfinite: dest:f src1:f len:32
 ceq: dest:y len:6
@@ -134,18 +134,18 @@ oparglist: src1:b len:10
 checkthis: src1:b len:3
 voidcall: len:17 clob:c
 voidcall_reg: src1:i len:11 clob:c
-voidcall_membase: src1:b len:16 clob:c
+voidcall_membase: src1:b len:16 nacl:17 clob:c
 fcall: dest:f len:17 clob:c
 fcall_reg: dest:f src1:i len:11 clob:c
-fcall_membase: dest:f src1:b len:16 clob:c
+fcall_membase: dest:f src1:b len:16 nacl:17 clob:c
 lcall: dest:l len:17 clob:c
 lcall_reg: dest:l src1:i len:11 clob:c
-lcall_membase: dest:l src1:b len:16 clob:c
+lcall_membase: dest:l src1:b len:16 nacl:17 clob:c
 vcall: len:17 clob:c
 vcall_reg: src1:i len:11 clob:c
-vcall_membase: src1:b len:16 clob:c
-call_reg: dest:a src1:i len:11 clob:c
-call_membase: dest:a src1:b len:16 clob:c
+vcall_membase: src1:b len:16 nacl:17 clob:c
+call_reg: dest:a src1:i len:11 nacl:14 clob:c
+call_membase: dest:a src1:b len:16 nacl:18 clob:c
 iconst: dest:i len:5
 r4const: dest:f len:15
 r8const: dest:f len:16
@@ -284,7 +284,7 @@ subcc: dest:i src1:i src2:i len:2 clob:1
 adc_imm: dest:i src1:i len:6 clob:1
 sbb: dest:i src1:i src2:i len:2 clob:1
 sbb_imm: dest:i src1:i len:6 clob:1
-br_reg: src1:i len:2
+br_reg: src1:i len:2 nacl:5
 sin: dest:f src1:f len:6
 cos: dest:f src1:f len:6
 abs: dest:f src1:f len:2
@@ -386,7 +386,7 @@ loadu2_mem: dest:i len:9
 
 vcall2: len:17 clob:c
 vcall2_reg: src1:i len:11 clob:c
-vcall2_membase: src1:b len:16 clob:c
+vcall2_membase: src1:b len:16 nacl:17 clob:c
 
 localloc_imm: dest:i len:120
 
index 345acf79650ace9deadde37eba2d9ecef63abc82..988f737c62b7803fce0dbbdb88f1d651774bccba 100644 (file)
@@ -114,6 +114,9 @@ opt_funcs [sizeof (int) * 8] = {
        NULL
 };
 
+#ifdef __native_client_codegen__
+extern guint8 nacl_align_byte;
+#endif
 
 #define DEFAULT_OPTIMIZATIONS (        \
        MONO_OPT_PEEPHOLE |     \
@@ -1118,6 +1121,9 @@ mini_usage (void)
                "    --trace[=EXPR]         Enable tracing, use --help-trace for details\n"
                "    --jitmap               Output a jit method map to /tmp/perf-PID.map\n"
                "    --help-devel           Shows more options available to developers\n"
+#ifdef __native_client_codegen__
+               "    --nacl-align-mask-off  Turn off Native Client 32-byte alignment mask (for debug only)\n"
+#endif
                "\n"
                "Runtime:\n"
                "    --config FILE          Loads FILE as the Mono config\n"
@@ -1627,12 +1633,23 @@ mono_main (int argc, char* argv[])
 #endif
                } else if (strcmp (argv [i], "--nollvm") == 0){
                        mono_use_llvm = FALSE;
+#ifdef __native_client_codegen__
+               } else if (strcmp (argv [i], "--nacl-align-mask-off") == 0){
+                       nacl_align_byte = 0xff; 
+#endif
                } else {
                        fprintf (stderr, "Unknown command line option: '%s'\n", argv [i]);
                        return 1;
                }
        }
 
+#ifdef __native_client_codegen__
+       if (getenv ("MONO_NACL_ALIGN_MASK_OFF"))
+       {
+               nacl_align_byte = 0xff;
+       }
+#endif
+
        if (!argv [i]) {
                mini_usage ();
                return 1;
index f3ebe864e9aa631f1e9864ddd206b5d0cddedc3e..e0d75e6aa1208e9d1691562093d187642a844f42 100644 (file)
@@ -324,9 +324,14 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
        guint8 *code;
        MonoJumpInfo *ji = NULL;
        GSList *unwind_ops = NULL;
+#ifdef __native_client_codegen__
+       guint kMaxCodeSize = 128;
+#else
+       guint kMaxCodeSize = 64;
+#endif  /* __native_client_codegen__ */
 
        /* call_filter (MonoContext *ctx, unsigned long eip) */
-       start = code = mono_global_codeman_reserve (64);
+       start = code = mono_global_codeman_reserve (kMaxCodeSize);
 
        x86_push_reg (code, X86_EBP);
        x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
@@ -374,7 +379,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
        if (info)
                *info = mono_tramp_info_create (g_strdup_printf ("call_filter"), start, code - start, ji, unwind_ops);
 
-       g_assert ((code - start) < 64);
+       g_assert ((code - start) < kMaxCodeSize);
        return start;
 }
 
@@ -492,8 +497,12 @@ get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolea
        int i, stack_size, stack_offset, arg_offsets [5], regs_offset;
        MonoJumpInfo *ji = NULL;
        GSList *unwind_ops = NULL;
-
-       start = code = mono_global_codeman_reserve (128);
+#ifdef __native_client_codegen__
+       guint kMaxCodeSize = 256;
+#else
+       guint kMaxCodeSize = 128;
+#endif
+       start = code = mono_global_codeman_reserve (kMaxCodeSize);
 
        stack_size = 128;
 
@@ -599,7 +608,7 @@ get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolea
        }
        x86_breakpoint (code);
 
-       g_assert ((code - start) < 128);
+       g_assert ((code - start) < kMaxCodeSize);
 
        if (info)
                *info = mono_tramp_info_create (g_strdup (name), start, code - start, ji, unwind_ops);
@@ -628,7 +637,7 @@ mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
 gpointer 
 mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
 {
-       return get_throw_trampoline ("rethow_exception", TRUE, FALSE, FALSE, FALSE, FALSE, info, aot);
+       return get_throw_trampoline ("rethrow_exception", TRUE, FALSE, FALSE, FALSE, FALSE, info, aot);
 }
 
 /**
@@ -848,6 +857,18 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
 void
 mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
 {
+#if defined (__native_client__)
+       printf("WARNING: mono_arch_sigctx_to_monoctx() called!\n");
+       mctx->eax = 0xDEADBEEF;
+       mctx->ebx = 0xDEADBEEF;
+       mctx->ecx = 0xDEADBEEF;
+       mctx->edx = 0xDEADBEEF;
+       mctx->ebp = 0xDEADBEEF;
+       mctx->esp = 0xDEADBEEF;
+       mctx->esi = 0xDEADBEEF;
+       mctx->edi = 0xDEADBEEF;
+       mctx->eip = 0xDEADBEEF;
+#else
 #ifdef MONO_ARCH_USE_SIGACTION
        ucontext_t *ctx = (ucontext_t*)sigctx;
        
@@ -873,11 +894,15 @@ mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
        mctx->edi = ctx->SC_EDI;
        mctx->eip = ctx->SC_EIP;
 #endif
+#endif /* if defined(__native_client__) */
 }
 
 void
 mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
 {
+#if defined(__native_client__)
+       printf("WARNING: mono_arch_monoctx_to_sigctx() called!\n");
+#else
 #ifdef MONO_ARCH_USE_SIGACTION
        ucontext_t *ctx = (ucontext_t*)sigctx;
 
@@ -903,18 +928,24 @@ mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
        ctx->SC_EDI = mctx->edi;
        ctx->SC_EIP = mctx->eip;
 #endif
+#endif /* __native_client__ */
 }      
 
 gpointer
 mono_arch_ip_from_context (void *sigctx)
 {
+#if defined(__native_client__)
+       printf("WARNING: mono_arch_ip_from_context() called!\n");
+       return (NULL);
+#else
 #ifdef MONO_ARCH_USE_SIGACTION
        ucontext_t *ctx = (ucontext_t*)sigctx;
        return (gpointer)UCONTEXT_REG_EIP (ctx);
 #else
        struct sigcontext *ctx = sigctx;
        return (gpointer)ctx->SC_EIP;
-#endif 
+#endif
+#endif /* __native_client__ */
 }
 
 /*
@@ -1166,6 +1197,9 @@ mono_tasklets_arch_restore (void)
        static guint8* saved = NULL;
        guint8 *code, *start;
 
+#ifdef __native_client_codegen__
+       g_print("mono_tasklets_arch_restore needs to be aligned for Native Client\n");
+#endif
        if (saved)
                return (MonoContinuationRestore)saved;
        code = start = mono_global_codeman_reserve (48);
index 02e07bde6d5faffe88bb506b14c9dfdb185b31be..0c942afabafd3a8f47fb18c3352781254e16c441 100644 (file)
@@ -43,7 +43,7 @@ typedef struct {
        char spec [MONO_INST_MAX];
 } OpDesc;
 
-static int nacl;
+static int nacl = 0;
 static GHashTable *table;
 static GHashTable *template_table;
 
@@ -75,6 +75,8 @@ load_file (const char *name) {
        line = 0;
        while ((str = fgets (buf, sizeof (buf), f))) {
                gboolean is_template = FALSE;
+               gboolean nacl_length_set = FALSE;
+
                ++line;
                eat_whitespace (str);
                if (!str [0])
@@ -132,14 +134,20 @@ load_file (const char *name) {
                                p += 7;
                                */
                        } else if (strncmp (p, "len:", 4) == 0) {
+                               unsigned long size;
                                p += 4;
-                               desc->spec [MONO_INST_LEN] += strtoul (p, &p, 10);
-                       } else if (strncmp (p, "nacl:", 5) == 0){
+                               size = strtoul (p, &p, 10);
+                               if (!nacl_length_set) {
+                                       desc->spec [MONO_INST_LEN] = size;
+                               }
+                       } else if (strncmp (p, "nacl:", 5) == 0) {
                                unsigned long size;
                                p += 5;
                                size = strtoul (p, &p, 10);
-                               if (nacl)
-                                       desc->spec [MONO_INST_LEN] += size;
+                               if (nacl) {
+                                       desc->spec [MONO_INST_LEN] = size;
+                                       nacl_length_set = TRUE;
+                               }
                        } else if (strncmp (p, "template:", 9) == 0) {
                                char *tname;
                                int i;
@@ -298,7 +306,7 @@ main (int argc, char* argv [])
                return 1;
        } else {
                int i = 3;
-               if (strcmp (argv [1], "--nacl") == 0){
+               if (strcmp (argv [1], "--nacl") == 0) {
                        nacl = 1;
                        i++;
                }
index 2444d9be18c263e0904e1ab2b7260d196a3c7731..7d66e31d76193fdc3cc213a23c7cbd5cd60987c2 100644 (file)
@@ -13,6 +13,8 @@ sub INST_SRC2  () {return 2;}
 sub INST_SRC3  () {return 3;}
 sub INST_LEN   () {return 4;}
 sub INST_CLOB  () {return 5;}
+# making INST_NACL the same as INST_MAX is not a mistake,
+# INST_NACL writes over INST_LEN, it's not its own field
 sub INST_NACL  () {return 6;}
 sub INST_MAX   () {return 6;}
 
@@ -23,6 +25,8 @@ my %table =();
 my %template_table =();
 my @opcodes = ();
 
+my $nacl = 0;
+
 sub parse_file
 {
        my ($define, $file) = @_;
@@ -167,21 +171,22 @@ sub build_spec {
        my $res = "";
        my $n = 0;
        for (my $i = 0; $i < @vals; ++$i) {
+               next if $i == INST_NACL;
                if (defined $vals [$i]) {
                        if ($i == INST_LEN) {
                                $n = $vals [$i];
-                               if (defined $vals [INST_NACL]){
-                                   $n += $vals [INST_NACL];
+                               if ((defined $vals [INST_NACL]) and $nacl == 1){
+                                   $n = $vals [INST_NACL];
                                }
                                $res .= sprintf ("\\x%x\" \"", + $n);
-                       } elsif ($i != INST_NACL) {
+                       } else {
                                if ($vals [$i] =~ /^[a-zA-Z0-9]$/) {
                                        $res .= $vals [$i];
                                } else {
                                        $res .= sprintf ("\\x%x\" \"", $vals [$i]);
                                }
                        }
-               } elsif ($i != INST_NACL) {
+               } else {
                        $res .= "\\x0\" \"";
                }
        }
@@ -221,12 +226,17 @@ sub build_table {
 }
 
 sub usage {
-       die "genmdesc.pl arch srcdir output name desc [desc2 ...]\n";
+       die "genmdesc.pl arch srcdir [--nacl] output name desc [desc2 ...]\n";
 }
 
 my $arch = shift || usage ();
 my $srcdir = shift || usage ();
 my $output = shift || usage ();
+if ($output eq "--nacl")
+{
+  $nacl = 1;  
+  $output = shift || usage();
+}
 my $name = shift || usage ();
 usage () unless @ARGV;
 my @files = @ARGV;
index 25b5cf6fad36ddc4251c0dab158e8ed7a4b29734..ff7e3d8d6f6c30801d6aa74a8b02f6471c360a22 100644 (file)
@@ -53,7 +53,7 @@
  * TARGET_ASM_GAS == GNU assembler
  */
 #if !defined(TARGET_ASM_APPLE) && !defined(TARGET_ASM_GAS)
-#ifdef __MACH__
+#if defined(__MACH__) && !defined(__native_client_codegen__)
 #define TARGET_ASM_APPLE
 #else
 #define TARGET_ASM_GAS
@@ -313,6 +313,11 @@ bin_writer_emit_ensure_buffer (BinSection *section, int size)
                while (new_size <= new_offset)
                        new_size *= 2;
                data = g_malloc0 (new_size);
+#ifdef __native_client_codegen__
+               /* for Native Client, fill empty space with HLT instruction */
+               /* instead of 00.                                           */
+               memset(data, 0xf4, new_size);
+#endif         
                memcpy (data, section->data, section->data_len);
                g_free (section->data);
                section->data = data;
@@ -355,6 +360,22 @@ bin_writer_emit_alignment (MonoImageWriter *acfg, int size)
        }
 }
 
+#ifdef __native_client_codegen__
+static void
+bin_writer_emit_nacl_call_alignment (MonoImageWriter *acfg) {
+  int offset = acfg->cur_section->cur_offset;
+  int padding = kNaClAlignment - (offset & kNaClAlignmentMask) - kNaClLengthOfCallImm;
+  guint8 padc = '\x90';
+
+  if (padding < 0) padding += kNaClAlignment;
+
+  while (padding > 0) {
+    bin_writer_emit_bytes(acfg, &padc, 1);
+    padding -= 1;
+  }
+}
+#endif  /* __native_client_codegen__ */
+
 static void
 bin_writer_emit_pointer_unaligned (MonoImageWriter *acfg, const char *target)
 {
@@ -1635,6 +1656,20 @@ asm_writer_emit_alignment (MonoImageWriter *acfg, int size)
 #endif
 }
 
+#ifdef __native_client_codegen__
+static void
+asm_writer_emit_nacl_call_alignment (MonoImageWriter *acfg) {
+  int padding = kNaClAlignment - kNaClLengthOfCallImm;
+  guint8 padc = '\x90';
+
+  fprintf (acfg->fp, "\n\t.align %d", kNaClAlignment);
+  while (padding > 0) {
+    fprintf (acfg->fp, "\n\t.byte %d", padc);
+    padding -= 1;
+  }
+}
+#endif  /* __native_client_codegen__ */
+
 static void
 asm_writer_emit_pointer_unaligned (MonoImageWriter *acfg, const char *target)
 {
@@ -1917,6 +1952,20 @@ img_writer_emit_alignment (MonoImageWriter *acfg, int size)
 #endif
 }
 
+#ifdef __native_client_codegen__
+void
+img_writer_emit_nacl_call_alignment (MonoImageWriter *acfg) {
+#ifdef USE_BIN_WRITER
+       if (acfg->use_bin_writer)
+               bin_writer_emit_nacl_call_alignment (acfg);
+       else
+               asm_writer_emit_nacl_call_alignment (acfg);
+#else
+       g_assert_not_reached();
+#endif
+}
+#endif  /* __native_client_codegen__ */
+
 void
 img_writer_emit_pointer_unaligned (MonoImageWriter *acfg, const char *target)
 {
index 6ad0067157464d1045964213d6631a402aebf2fa..720b95f97ada9c3572ac91578d350d7978234989 100644 (file)
@@ -62,6 +62,10 @@ void img_writer_emit_line (MonoImageWriter *w) MONO_INTERNAL;
 
 void img_writer_emit_alignment (MonoImageWriter *w, int size) MONO_INTERNAL;
 
+#ifdef __native_client_codegen__
+void img_writer_emit_nacl_call_alignment (MonoImageWriter *w) MONO_INTERNAL;
+#endif
+
 void img_writer_emit_pointer_unaligned (MonoImageWriter *w, const char *target) MONO_INTERNAL;
 
 void img_writer_emit_pointer (MonoImageWriter *w, const char *target) MONO_INTERNAL;
index bb8985c298fd2693a49b729f5eec831542711dce..2cda2a8b0f532303312cab2d2bdbee80f0ec89a2 100644 (file)
@@ -5446,6 +5446,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                cfg->bb_exit = end_bblock;
                end_bblock->cil_code = NULL;
                end_bblock->cil_length = 0;
+               end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
                g_assert (cfg->num_bblocks == 2);
 
                arg_array = cfg->args;
@@ -7051,11 +7052,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        target = ip + n * sizeof (guint32);
 
                        GET_BBLOCK (cfg, default_bblock, target);
+                       default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
 
                        targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
                        for (i = 0; i < n; ++i) {
                                GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
                                targets [i] = tblock;
+                               targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
                                ip += 4;
                        }
 
index ff0dfca92b77231e4a191a4733a2054b1f919c90..53f8e3a88b1750062545db421dac82c76a065fce 100644 (file)
 
 #include "jit-icalls.h"
 
+#if defined(__native_client__)
+
+void
+mono_runtime_setup_stat_profiler (void)
+{
+       printf("WARNING: mono_runtime_setup_stat_profiler() called!\n");
+}
+
+
+void
+mono_runtime_shutdown_stat_profiler (void)
+{
+}
+
+
+gboolean
+SIG_HANDLER_SIGNATURE (mono_chain_signal)
+{
+       return FALSE;
+}
+
+void
+mono_runtime_install_handlers (void)
+{
+}
+
+void
+mono_runtime_shutdown_handlers (void)
+{
+}
+
+void
+mono_runtime_cleanup_handlers (void)
+{
+}
+
+
+
+#else
+
 static GHashTable *mono_saved_signal_handlers = NULL;
 
 static gpointer
@@ -620,3 +660,5 @@ mono_gdb_render_native_backtraces ()
        return TRUE;
 }
 #endif
+#endif /* __native_client__ */
+
index ee7b48c611a718b50620d6e3e96c2e864fec5404..c981b6520d607b8078e36b1f96474eb37d385905 100644 (file)
@@ -65,6 +65,65 @@ static CRITICAL_SECTION mini_arch_mutex;
 MonoBreakpointInfo
 mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
 
+static gpointer
+mono_realloc_native_code (MonoCompile *cfg)
+{
+#ifdef __native_client_codegen__
+       guint old_padding;
+       gpointer native_code;
+       guint alignment_check;
+
+       /* Save the old alignment offset so we can re-align after the realloc. */
+       old_padding = (guint)(cfg->native_code - cfg->native_code_alloc);
+
+       cfg->native_code_alloc = g_realloc (cfg->native_code_alloc, 
+                                                                               cfg->code_size + kNaClAlignment);
+
+       /* Align native_code to next nearest kNaClAlignment byte. */
+       native_code = (guint)cfg->native_code_alloc + kNaClAlignment;
+       native_code = (guint)native_code & ~kNaClAlignmentMask;
+
+       /* Shift the data to be 32-byte aligned again. */
+       memmove (native_code, cfg->native_code_alloc + old_padding, cfg->code_size);
+
+       alignment_check = (guint)native_code & kNaClAlignmentMask;
+       g_assert (alignment_check == 0);
+       return native_code;
+#else
+       return g_realloc (cfg->native_code, cfg->code_size);
+#endif
+}
+
+#ifdef __native_client_codegen__
+
+/* mono_arch_nacl_pad: Add pad bytes of alignment instructions at code,       */
+/* Check that alignment doesn't cross an alignment boundary.        */
+guint8 *
+mono_arch_nacl_pad (guint8 *code, int pad)
+{
+       const int kMaxPadding = 7;    /* see x86-codegen.h: x86_padding() */
+
+       if (pad == 0) return code;
+       /* assertion: alignment cannot cross a block boundary */
+       g_assert(((uintptr_t)code & (~kNaClAlignmentMask)) ==
+                        (((uintptr_t)code + pad - 1) & (~kNaClAlignmentMask)));
+       while (pad >= kMaxPadding) {
+               x86_padding (code, kMaxPadding);
+               pad -= kMaxPadding;
+       }
+       if (pad != 0) x86_padding (code, pad);
+       return code;
+}
+
+guint8 *
+mono_arch_nacl_skip_nops (guint8 *code)
+{
+       x86_skip_nops (code);
+       return code;
+}
+
+#endif /* __native_client_codegen__ */
+
 /*
  * The code generated for sequence points reads from this location, which is
  * made read-only when single stepping is enabled.
@@ -617,6 +676,14 @@ typedef void (*CpuidFunc) (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_ed
 static int 
 cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx)
 {
+#if defined(__native_client__)
+       /* Taken from below, the bug listed in the comment is */
+       /* only valid for non-static cases.                   */
+       __asm__ __volatile__ ("cpuid"
+               : "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
+               : "a" (id));
+       return 1;
+#else
        int have_cpuid = 0;
 #ifndef _MSC_VER
        __asm__  __volatile__ (
@@ -671,6 +738,7 @@ cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx)
                return 1;
        }
        return 0;
+#endif
 }
 
 /*
@@ -724,6 +792,7 @@ mono_arch_cleanup (void)
 guint32
 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
 {
+#if !defined(__native_client__)
        int eax, ebx, ecx, edx;
        guint32 opts = 0;
        
@@ -755,6 +824,9 @@ mono_arch_cpu_optimizazions (guint32 *exclude_mask)
 #endif
        }
        return opts;
+#else
+       return MONO_OPT_CMOV | MONO_OPT_FCMOV | MONO_OPT_SSE2;
+#endif
 }
 
 /*
@@ -2211,6 +2283,11 @@ x86_pop_reg (code, X86_ECX); \
 x86_pop_reg (code, X86_EDX); \
 x86_pop_reg (code, X86_EAX);
 
+/* REAL_PRINT_REG does not appear to be used, and was not adapted to work with Native Client. */
+#ifdef __native__client_codegen__
+#define REAL_PRINT_REG(text, reg) g_assert_not_reached()
+#endif
+
 /* benchmark and set based on cpu */
 #define LOOP_ALIGNMENT 8
 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
@@ -2237,7 +2314,23 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        bb->native_offset = cfg->code_len;
                }
        }
-
+#ifdef __native_client_codegen__
+       {
+               /* For Native Client, all indirect call/jump targets must be   */
+               /* 32-byte aligned.  Exception handler blocks are jumped to    */
+               /* indirectly as well.                                         */
+               gboolean bb_needs_alignment = (bb->flags & BB_INDIRECT_JUMP_TARGET) ||
+                       (bb->flags & BB_EXCEPTION_HANDLER);
+
+               /* if ((cfg->code_len & kNaClAlignmentMask) != 0) { */
+               if ( bb_needs_alignment && ((cfg->code_len & kNaClAlignmentMask) != 0)) {
+            int pad = kNaClAlignment - (cfg->code_len & kNaClAlignmentMask);
+            if (pad != kNaClAlignment) code = mono_arch_nacl_pad(code, pad);
+            cfg->code_len += pad;
+            bb->native_offset = cfg->code_len;
+               }
+       }
+#endif  /* __native_client_codegen__ */
        if (cfg->verbose_level > 2)
                g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
 
@@ -2262,9 +2355,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
 
-               if (G_UNLIKELY (offset > (cfg->code_size - max_len - 16))) {
+#define EXTRA_CODE_SPACE (NACL_SIZE (16, 16 + kNaClAlignment))
+
+               if (G_UNLIKELY (offset > (cfg->code_size - max_len - EXTRA_CODE_SPACE))) {
                        cfg->code_size *= 2;
-                       cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
+                       cfg->native_code = mono_realloc_native_code(cfg);
                        code = cfg->native_code + offset;
                        mono_jit_stats.code_reallocs++;
                }
@@ -4463,9 +4558,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                }
 
                if (G_UNLIKELY ((code - cfg->native_code - offset) > max_len)) {
+#ifndef __native_client_codegen__
                        g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
-                                  mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
+                                          mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
                        g_assert_not_reached ();
+#endif  /* __native_client_codegen__ */
                }
               
                cpos += max_len;
@@ -4548,13 +4645,30 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        int alloc_size, pos, max_offset, i, cfa_offset;
        guint8 *code;
        gboolean need_stack_frame;
+#ifdef __native_client_codegen__
+       guint alignment_check;
+#endif
 
        cfg->code_size = MAX (cfg->header->code_size * 4, 10240);
 
        if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
                cfg->code_size += 512;
 
+#ifdef __native_client_codegen__
+       /* native_code_alloc is not 32-byte aligned, native_code is. */
+       cfg->native_code_alloc = g_malloc (cfg->code_size + kNaClAlignment);
+
+       /* Align native_code to next nearest kNaclAlignment byte. */
+       cfg->native_code = (guint)cfg->native_code_alloc + kNaClAlignment; 
+       cfg->native_code = (guint)cfg->native_code & ~kNaClAlignmentMask;
+       
+       code = cfg->native_code;
+
+       alignment_check = (guint)cfg->native_code & kNaClAlignmentMask;
+       g_assert(alignment_check == 0);
+#else
        code = cfg->native_code = g_malloc (cfg->code_size);
+#endif
 
        /* Offset between RSP and the CFA */
        cfa_offset = 0;
@@ -4741,7 +4855,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                if (G_UNLIKELY (required_code_size >= (cfg->code_size - offset))) {
                        while (required_code_size >= (cfg->code_size - offset))
                                cfg->code_size *= 2;
-                       cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
+                       cfg->native_code = mono_realloc_native_code(cfg);
                        code = cfg->native_code + offset;
                        mono_jit_stats.code_reallocs++;
                }
@@ -4787,11 +4901,23 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        /* max alignment for loops */
                        if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
                                max_offset += LOOP_ALIGNMENT;
-
+#ifdef __native_client_codegen__
+                       /* max alignment for native client */
+                       max_offset += kNaClAlignment;
+#endif
                        MONO_BB_FOR_EACH_INS (bb, ins) {
                                if (ins->opcode == OP_LABEL)
                                        ins->inst_c1 = max_offset;
-                               
+#ifdef __native_client_codegen__
+                               {
+                                       int space_in_block = kNaClAlignment -
+                                               ((max_offset + cfg->code_len) & kNaClAlignmentMask);
+                                       int max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
+                                       if (space_in_block < max_len && max_len < kNaClAlignment) {
+                                               max_offset += space_in_block;
+                                       }
+                               }
+#endif  /* __native_client_codegen__ */
                                max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
                        }
                }
@@ -4846,7 +4972,7 @@ mono_arch_emit_epilog (MonoCompile *cfg)
 
        while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
                cfg->code_size *= 2;
-               cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
+               cfg->native_code = mono_realloc_native_code(cfg);
                mono_jit_stats.code_reallocs++;
        }
 
@@ -5027,7 +5153,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
 
        while (cfg->code_len + code_size > (cfg->code_size - 16)) {
                cfg->code_size *= 2;
-               cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
+               cfg->native_code = mono_realloc_native_code(cfg);
                mono_jit_stats.code_reallocs++;
        }
 
@@ -5060,8 +5186,12 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                                guint32 size;
 
                                /* Compute size of code following the push <OFFSET> */
+#ifdef __native_client_codegen__
+                               code = mono_nacl_align (code);
+                               size = kNaClAlignment;
+#else
                                size = 5 + 5;
-
+#endif
                                /*This is aligned to 16 bytes by the callee. This way we save a few bytes here.*/
 
                                if ((code - cfg->native_code) - throw_ip < 126 - size) {
@@ -5176,8 +5306,16 @@ mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
 //[1 + 5] x86_jump_mem(inst,mem)
 
 #define CMP_SIZE 6
+#ifdef __native_client_codegen__
+/* These constants should be coming from cpu-x86.md            */
+/* I suspect the size calculation below is actually incorrect. */
+/* TODO: fix the calculation that uses these sizes.            */
+#define BR_SMALL_SIZE 16
+#define BR_LARGE_SIZE 12
+#else
 #define BR_SMALL_SIZE 2
 #define BR_LARGE_SIZE 5
+#endif  /* __native_client_codegen__ */
 #define JUMP_IMM_SIZE 6
 #define ENABLE_WRONG_METHOD_CHECK 0
 #define DEBUG_IMT 0
@@ -5202,6 +5340,9 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
        int size = 0;
        guint8 *code, *start;
 
+#ifdef __native_client_codegen__
+       /* g_print("mono_arch_build_imt_thunk needs to be aligned.\n"); */
+#endif
        for (i = 0; i < count; ++i) {
                MonoIMTCheckItem *item = imt_entries [i];
                if (item->is_equals) {
@@ -5555,8 +5696,12 @@ get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *cod
        } else {
                int i = 0;
                /* 8 for mov_reg and jump, plus 8 for each parameter */
+#ifdef __native_client_codegen__
+               /* TODO: calculate this size correctly */
+               int code_reserve = 13 + (param_count * 8) + 2 * kNaClAlignment;
+#else
                int code_reserve = 8 + (param_count * 8);
-
+#endif  /* __native_client_codegen__ */
                /*
                 * The stack contains:
                 * <args in reverse order>
index 8e712e3375435c2c3210d8f85584b2e9cd035895..b4657b1920f13875b646db3a4548a607682fdc06 100644 (file)
@@ -55,6 +55,16 @@ struct sigcontext {
 #define MONO_ARCH_USE_SIGACTION
 #endif
 
+#if defined(__native_client__)
+#undef MONO_ARCH_USE_SIGACTION
+#endif
+
+#if defined(__native_client_codegen__) || defined(__native_client__)
+#define NACL_SIZE(a, b) (b)
+#else
+#define NACL_SIZE(a, b) (a)
+#endif
+
 #ifndef HOST_WIN32
 
 #ifdef HAVE_WORKING_SIGALTSTACK
@@ -286,7 +296,7 @@ typedef struct {
 
 #define MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS 1
 
-#if !defined(__APPLE__)
+#if !defined(__APPLE__) || defined(__native_client_codegen__)
 #define MONO_ARCH_AOT_SUPPORTED 1
 #endif
 
index 10e0942f5c934990ea9e082bb14b2b49941e2dba..aabd00b2697f2fa3e73bf0429dcc9f7561e4c114 100644 (file)
@@ -81,6 +81,11 @@ MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
 MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL;
 MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL;
 
+#ifdef __native_client_codegen__
+/* Default alignment for Native Client is 32-byte. */
+guint8 nacl_align_byte = 0xe0;
+#endif
+
 static guint32 default_opt = 0;
 static gboolean default_opt_set = FALSE;
 
@@ -157,6 +162,82 @@ gboolean disable_vtypes_in_regs = FALSE;
 
 gboolean mono_dont_free_global_codeman;
 
+#ifdef __native_client_codegen__
+
+/* Prevent instructions from straddling a 32-byte alignment boundary.   */
+/* Instructions longer than 32 bytes must be aligned internally.        */
+/* IN: pcode, instlen                                                   */
+/* OUT: pcode                                                           */
+void mono_nacl_align_inst(guint8 **pcode, int instlen) {
+  int space_in_block;
+
+  space_in_block = kNaClAlignment - ((uintptr_t)(*pcode) & kNaClAlignmentMask);
+
+  if (G_UNLIKELY (instlen >= kNaClAlignment)) {
+    g_assert_not_reached();
+  } else if (instlen > space_in_block) {
+    *pcode = mono_arch_nacl_pad(*pcode, space_in_block);
+  }
+}
+
+/* Move emitted call sequence to the end of a kNaClAlignment-byte block.  */
+/* IN: start    pointer to start of call sequence                         */
+/* IN: pcode    pointer to end of call sequence (current "IP")            */
+/* OUT: start   pointer to the start of the call sequence after padding   */
+/* OUT: pcode   pointer to the end of the call sequence after padding     */
+void mono_nacl_align_call(guint8 **start, guint8 **pcode) {
+  const size_t MAX_NACL_CALL_LENGTH = kNaClAlignment;
+  guint8 copy_of_call[MAX_NACL_CALL_LENGTH];
+  guint8 *temp;
+
+  const size_t length = (size_t)((*pcode)-(*start));
+  g_assert(length < MAX_NACL_CALL_LENGTH);
+
+  memcpy(copy_of_call, *start, length);
+  temp = mono_nacl_pad_call(*start, (guint8)length);
+  memcpy(temp, copy_of_call, length);
+  (*start) = temp;
+  (*pcode) = temp + length;
+}
+
+/* mono_nacl_pad_call(): Insert padding for Native Client call instructions */
+/*    code     pointer to buffer for emitting code                          */
+/*    ilength  length of call instruction                                   */
+guint8 *mono_nacl_pad_call(guint8 *code, guint8 ilength) {
+  int freeSpaceInBlock = kNaClAlignment - ((uintptr_t)code & kNaClAlignmentMask);
+  int padding = freeSpaceInBlock - ilength;
+
+  if (padding < 0) {
+    /* There isn't enough space in this block for the instruction. */
+    /* Fill this block and start a new one.                        */
+    code = mono_arch_nacl_pad(code, freeSpaceInBlock);
+    freeSpaceInBlock = kNaClAlignment;
+    padding = freeSpaceInBlock - ilength;
+  }
+  g_assert(ilength > 0);
+  g_assert(padding >= 0);
+  g_assert(padding < kNaClAlignment);
+  if (0 == padding) return code;
+  return mono_arch_nacl_pad(code, padding);
+}
+
+guint8 *mono_nacl_align(guint8 *code) {
+  int padding = kNaClAlignment - ((uintptr_t)code & kNaClAlignmentMask);
+  if (padding != kNaClAlignment) code = mono_arch_nacl_pad(code, padding);
+  return code;
+}
+
+void mono_nacl_fix_patches(const guint8 *code, MonoJumpInfo *ji)
+{
+  MonoJumpInfo *patch_info;
+  for (patch_info = ji; patch_info; patch_info = patch_info->next) {
+    unsigned char *ip = patch_info->ip.i + code;
+    ip = mono_arch_nacl_skip_nops(ip);
+    patch_info->ip.i = ip - code;
+  }
+}
+#endif  /* __native_client_codegen__ */
+
 gboolean
 mono_running_on_valgrind (void)
 {
@@ -3330,7 +3411,17 @@ mono_codegen (MonoCompile *cfg)
        }
 
        memcpy (code, cfg->native_code, cfg->code_len);
+#ifdef __native_client_codegen__
+       if (cfg->native_code_alloc) {
+               g_free (cfg->native_code_alloc);
+               cfg->native_code_alloc = 0;
+       }
+       else if (cfg->native_code) {
+               g_free (cfg->native_code);
+       }
+#else
        g_free (cfg->native_code);
+#endif
        cfg->native_code = code;
        code = cfg->native_code + cfg->code_len;
   
@@ -3369,6 +3460,10 @@ if (valgrind_register){
        mono_arch_save_unwind_info (cfg);
 #endif
        
+#ifdef __native_client_codegen__
+       mono_nacl_fix_patches (cfg->native_code, cfg->patch_info);
+#endif
+
        mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
 
        if (cfg->method->dynamic) {
@@ -5664,7 +5759,7 @@ mini_init (const char *filename, const char *runtime_version)
 
        MONO_PROBE_VES_INIT_BEGIN ();
 
-#ifdef __linux__
+#if defined(__linux__) && !defined(__native_client__)
        if (access ("/proc/self/maps", F_OK) != 0) {
                g_print ("Mono requires /proc to be mounted.\n");
                exit (1);
index 6e6c29b18417c3c89b29114beac96d7d751a82d6..58eadbb441888a164b4075ac720d5ce8f2537902 100644 (file)
@@ -562,11 +562,13 @@ struct MonoBasicBlock {
 
 /* BBlock flags */
 enum {
-       BB_VISITED            = 1 << 0,
-       BB_REACHABLE          = 1 << 1,
-       BB_EXCEPTION_DEAD_OBJ = 1 << 2,
-       BB_EXCEPTION_UNSAFE   = 1 << 3,
-       BB_EXCEPTION_HANDLER  = 1 << 4
+       BB_VISITED              = 1 << 0,
+       BB_REACHABLE            = 1 << 1,
+       BB_EXCEPTION_DEAD_OBJ   = 1 << 2,
+       BB_EXCEPTION_UNSAFE     = 1 << 3,
+       BB_EXCEPTION_HANDLER    = 1 << 4,
+       /* for Native Client, mark the blocks that can be jumped to indirectly */
+       BB_INDIRECT_JUMP_TARGET = 1 << 5 
 };
 
 typedef struct MonoMemcpyArgs {
@@ -1070,6 +1072,11 @@ typedef struct {
        MonoGenericSharingContext *generic_sharing_context;
 
        unsigned char   *cil_start;
+#ifdef __native_client_codegen__
+       /* this alloc is not aligned, native_code */
+       /* is the 32-byte aligned version of this */
+       unsigned char   *native_code_alloc;
+#endif
        unsigned char   *native_code;
        guint            code_size;
        guint            code_len;
@@ -1589,6 +1596,19 @@ gint32    mono_linterval_get_intersect_pos  (MonoLiveInterval *i1, MonoLiveInter
 void      mono_linterval_split              (MonoCompile *cfg, MonoLiveInterval *interval, MonoLiveInterval **i1, MonoLiveInterval **i2, int pos) MONO_INTERNAL;
 void      mono_liveness_handle_exception_clauses (MonoCompile *cfg) MONO_INTERNAL;
 
+/* Native Client functions */
+#ifdef __native_client_codegen__
+void mono_nacl_align_inst(guint8 **pcode, int instlen);
+void mono_nacl_align_call(guint8 **start, guint8 **pcode);
+guint8 *mono_nacl_pad_call(guint8 *code, guint8 ilength);
+guint8 *mono_nacl_align(guint8 *code);
+void mono_nacl_fix_patches(const guint8 *code, MonoJumpInfo *ji);
+/* Defined for each arch */
+guint8 *mono_arch_nacl_pad(guint8 *code, int pad);
+guint8 *mono_arch_nacl_skip_nops(guint8 *code);
+
+#endif
+
 /* AOT */
 void      mono_aot_init                     (void) MONO_INTERNAL;
 gpointer  mono_aot_get_method               (MonoDomain *domain,
index c1e3009bd9410f68ca02a33b76863b6747aa6f88..93b0922d3e897708dc4e132eddd00d246ef58569 100644 (file)
@@ -144,12 +144,23 @@ mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *a
 
        /* Patch the jump table entry used by the plt entry */
 
+#if defined(__native_client_codegen__) || defined(__native_client__)
+       /* for both compiler and runtime      */
+       /* A PLT entry:                       */
+       /*        mov <DISP>(%ebx), %ecx      */
+       /*        and 0xffffffe0, %ecx        */
+       /*        jmp *%ecx                   */
+       g_assert (code [0] == 0x8b);
+       g_assert (code [1] == 0x8b);
+
+       offset = *(guint32*)(code + 2);
+#else
        /* A PLT entry: jmp *<DISP>(%ebx) */
        g_assert (code [0] == 0xff);
        g_assert (code [1] == 0xa3);
 
        offset = *(guint32*)(code + 2);
-
+#endif  /* __native_client_codegen__ */
        if (!got)
                got = (gpointer*)(gsize) regs [MONO_ARCH_GOT_REG];
        *(guint8**)((guint8*)got + offset) = addr;
@@ -158,20 +169,28 @@ mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *a
 static gpointer
 get_vcall_slot (guint8 *code, mgreg_t *regs, int *displacement)
 {
-       guint8 buf [8];
+       const int kBufSize = NACL_SIZE (8, 16);
+       guint8 buf [kBufSize];
        guint8 reg = 0;
        gint32 disp = 0;
 
-       mono_breakpoint_clean_code (NULL, code, 8, buf, sizeof (buf));
+       mono_breakpoint_clean_code (NULL, code, kBufSize, buf, sizeof (buf));
        code = buf + 8;
 
        *displacement = 0;
 
-       code -= 6;
-
        if ((code [0] == 0xff) && ((code [1] & 0x18) == 0x10) && ((code [1] >> 6) == 2)) {
                reg = code [1] & 0x07;
                disp = *((gint32*)(code + 2));
+#if defined(__native_client_codegen__) || defined(__native_client__)
+       } else if ((code[1] == 0x83) && (code[2] == 0xe1) && (code[4] == 0xff) &&
+                          (code[5] == 0xd1) && (code[-5] == 0x8b)) {
+               disp = *((gint32*)(code - 3));
+               reg = code[-4] & 0x07;
+       } else if ((code[-2] == 0x8b) && (code[1] == 0x83) && (code[4] == 0xff)) {
+               reg = code[-1] & 0x07;
+               disp = (signed char)code[0];
+#endif
        } else {
                g_assert_not_reached ();
                return NULL;
@@ -518,7 +537,7 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty
        
        tramp = mono_get_trampoline_code (tramp_type);
 
-       code = buf = mono_domain_code_reserve_align (domain, TRAMPOLINE_SIZE, 4);
+       code = buf = mono_domain_code_reserve_align (domain, TRAMPOLINE_SIZE, NACL_SIZE (4, kNaClAlignment));
 
        x86_push_imm (buf, arg1);
        x86_jump_code (buf, tramp);
@@ -559,7 +578,13 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info
                index -= size - 1;
        }
 
+#ifdef __native_client_codegen__
+       /* TODO: align for Native Client */
+       tramp_size = (aot ? 64 : 36) + 2 * kNaClAlignment +
+               6 * (depth + kNaClAlignment);
+#else
        tramp_size = (aot ? 64 : 36) + 6 * depth;
+#endif  /* __native_client_codegen__ */
 
        code = buf = mono_global_codeman_reserve (tramp_size);
 
@@ -672,7 +697,9 @@ mono_arch_create_generic_class_init_trampoline (MonoTrampInfo **info, gboolean a
        mono_arch_flush_icache (code, code - buf);
 
        g_assert (code - buf <= tramp_size);
-
+#ifdef __native_client_codegen__
+       g_assert (code - buf <= kNaClAlignment);
+#endif
        if (info)
                *info = mono_tramp_info_create (g_strdup_printf ("generic_class_init_trampoline"), buf, code - buf, ji, unwind_ops);
 
@@ -717,7 +744,7 @@ mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean aot)
        owner_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (owner_offset);
        nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
 
-       tramp_size = 64;
+       tramp_size = NACL_SIZE (64, 128);
 
        code = buf = mono_global_codeman_reserve (tramp_size);
 
@@ -833,7 +860,7 @@ mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot)
        nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
        entry_count_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (entry_count_offset);
 
-       tramp_size = 64;
+       tramp_size = NACL_SIZE (64, 128);
 
        code = buf = mono_global_codeman_reserve (tramp_size);
 
@@ -992,5 +1019,5 @@ mono_arch_get_call_target (guint8 *code)
 guint32
 mono_arch_get_plt_info_offset (guint8 *plt_entry, mgreg_t *regs, guint8 *code)
 {
-       return *(guint32*)(plt_entry + 6);
+       return *(guint32*)(plt_entry + NACL_SIZE (6, 12));
 }