Merge pull request #249 from pcc/xgetinputfocus
[mono.git] / mono / mini / mini-amd64.c
index 6d0aaf905126b0e983d5624775840c9cb1b9db88..3e926c59de292e1489303d02f9ff2d67a8cb753b 100644 (file)
@@ -10,6 +10,8 @@
  *   Zoltan Varga (vargaz@gmail.com)
  *
  * (C) 2003 Ximian, Inc.
+ * Copyright 2003-2011 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
  */
 #include "mini.h"
 #include <string.h>
 #include <mono/metadata/gc-internal.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-mmap.h>
+#include <mono/utils/mono-memory-model.h>
+#include <mono/utils/mono-tls.h>
 
 #include "trace.h"
 #include "ir-emit.h"
 #include "mini-amd64.h"
 #include "cpu-amd64.h"
 #include "debugger-agent.h"
+#include "mini-gc.h"
 
 static gint lmf_tls_offset = -1;
 static gint lmf_addr_tls_offset = -1;
@@ -64,6 +69,13 @@ static CRITICAL_SECTION mini_arch_mutex;
 MonoBreakpointInfo
 mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
 
+/* Structure used by the sequence points in AOTed code */
+typedef struct {
+       gpointer ss_trigger_page;
+       gpointer bp_trigger_page;
+       gpointer bp_addrs [MONO_ZERO_LEN_ARRAY];
+} SeqPointInfo;
+
 /*
  * The code generated for sequence points reads from this location, which is
  * made read-only when single stepping is enabled.
@@ -204,11 +216,278 @@ amd64_is_near_call (guint8 *code)
        return code [0] == 0xe8;
 }
 
+#ifdef __native_client_codegen__
+
+/* Keep track of instruction "depth", that is, the level of sub-instruction */
+/* for any given instruction.  For instance, amd64_call_reg resolves to     */
+/* amd64_call_reg_internal, which uses amd64_alu_* macros, etc.             */
+/* We only want to force bundle alignment for the top level instruction,    */
+/* so NaCl pseudo-instructions can be implemented with sub instructions.    */
+static MonoNativeTlsKey nacl_instruction_depth;
+
+static MonoNativeTlsKey nacl_rex_tag;
+static MonoNativeTlsKey nacl_legacy_prefix_tag;
+
+void
+amd64_nacl_clear_legacy_prefix_tag ()
+{
+       mono_native_tls_set_value (nacl_legacy_prefix_tag, NULL);
+}
+
+void
+amd64_nacl_tag_legacy_prefix (guint8* code)
+{
+       if (mono_native_tls_get_value (nacl_legacy_prefix_tag) == NULL)
+               mono_native_tls_set_value (nacl_legacy_prefix_tag, code);
+}
+
+void
+amd64_nacl_tag_rex (guint8* code)
+{
+       mono_native_tls_set_value (nacl_rex_tag, code);
+}
+
+guint8*
+amd64_nacl_get_legacy_prefix_tag ()
+{
+       return (guint8*)mono_native_tls_get_value (nacl_legacy_prefix_tag);
+}
+
+guint8*
+amd64_nacl_get_rex_tag ()
+{
+       return (guint8*)mono_native_tls_get_value (nacl_rex_tag);
+}
+
+/* Increment the instruction "depth" described above */
+void
+amd64_nacl_instruction_pre ()
+{
+       intptr_t depth = (intptr_t) mono_native_tls_get_value (nacl_instruction_depth);
+       depth++;
+       mono_native_tls_set_value (nacl_instruction_depth, (gpointer)depth);
+}
+
+/* amd64_nacl_instruction_post: Decrement instruction "depth", force bundle */
+/* alignment if depth == 0 (top level instruction)                          */
+/* IN: start, end    pointers to instruction beginning and end              */
+/* OUT: start, end   pointers to beginning and end after possible alignment */
+/* GLOBALS: nacl_instruction_depth     defined above                        */
+void
+amd64_nacl_instruction_post (guint8 **start, guint8 **end)
+{
+       intptr_t depth = (intptr_t) mono_native_tls_get_value (nacl_instruction_depth);
+       depth--;
+       mono_native_tls_set_value (nacl_instruction_depth, (void*)depth);
+
+       g_assert ( depth >= 0 );
+       if (depth == 0) {
+               uintptr_t space_in_block;
+               uintptr_t instlen;
+               guint8 *prefix = amd64_nacl_get_legacy_prefix_tag ();
+               /* if legacy prefix is present, and if it was emitted before */
+               /* the start of the instruction sequence, adjust the start   */
+               if (prefix != NULL && prefix < *start) {
+                       g_assert (*start - prefix <= 3);/* only 3 are allowed */
+                       *start = prefix;
+               }
+               space_in_block = kNaClAlignment - ((uintptr_t)(*start) & kNaClAlignmentMask);
+               instlen = (uintptr_t)(*end - *start);
+               /* Only check for instructions which are less than        */
+               /* kNaClAlignment. The only instructions that should ever */
+               /* be that long are call sequences, which are already     */
+               /* padded out to align the return to the next bundle.     */
+               if (instlen > space_in_block && instlen < kNaClAlignment) {
+                       const size_t MAX_NACL_INST_LENGTH = kNaClAlignment;
+                       guint8 copy_of_instruction[MAX_NACL_INST_LENGTH];
+                       const size_t length = (size_t)((*end)-(*start));
+                       g_assert (length < MAX_NACL_INST_LENGTH);
+                       
+                       memcpy (copy_of_instruction, *start, length);
+                       *start = mono_arch_nacl_pad (*start, space_in_block);
+                       memcpy (*start, copy_of_instruction, length);
+                       *end = *start + length;
+               }
+               amd64_nacl_clear_legacy_prefix_tag ();
+               amd64_nacl_tag_rex (NULL);
+       }
+}
+
+/* amd64_nacl_membase_handler: ensure all access to memory of the form      */
+/*   OFFSET(%rXX) is sandboxed.  For allowable base registers %rip, %rbp,   */
+/*   %rsp, and %r15, emit the membase as usual.  For all other registers,   */
+/*   make sure the upper 32-bits are cleared, and use that register in the  */
+/*   index field of a new address of this form: OFFSET(%r15,%eXX,1)         */
+/* IN:      code                                                            */
+/*             pointer to current instruction stream (in the                */
+/*             middle of an instruction, after opcode is emitted)           */
+/*          basereg/offset/dreg                                             */
+/*             operands of normal membase address                           */
+/* OUT:     code                                                            */
+/*             pointer to the end of the membase/memindex emit              */
+/* GLOBALS: nacl_rex_tag                                                    */
+/*             position in instruction stream that rex prefix was emitted   */
+/*          nacl_legacy_prefix_tag                                          */
+/*             (possibly NULL) position in instruction of legacy x86 prefix */
+void
+amd64_nacl_membase_handler (guint8** code, gint8 basereg, gint32 offset, gint8 dreg)
+{
+       gint8 true_basereg = basereg;
+
+       /* Cache these values, they might change  */
+       /* as new instructions are emitted below. */
+       guint8* rex_tag = amd64_nacl_get_rex_tag ();
+       guint8* legacy_prefix_tag = amd64_nacl_get_legacy_prefix_tag ();
+
+       /* 'basereg' is given masked to 0x7 at this point, so check */
+       /* the rex prefix to see if this is an extended register.   */
+       if ((rex_tag != NULL) && IS_REX(*rex_tag) && (*rex_tag & AMD64_REX_B)) {
+               true_basereg |= 0x8;
+       }
+
+#define X86_LEA_OPCODE (0x8D)
+
+       if (!amd64_is_valid_nacl_base (true_basereg) && (*(*code-1) != X86_LEA_OPCODE)) {
+               guint8* old_instruction_start;
+               
+               /* This will hold the 'mov %eXX, %eXX' that clears the upper */
+               /* 32-bits of the old base register (new index register)     */
+               guint8 buf[32];
+               guint8* buf_ptr = buf;
+               size_t insert_len;
+
+               g_assert (rex_tag != NULL);
+
+               if (IS_REX(*rex_tag)) {
+                       /* The old rex.B should be the new rex.X */
+                       if (*rex_tag & AMD64_REX_B) {
+                               *rex_tag |= AMD64_REX_X;
+                       }
+                       /* Since our new base is %r15 set rex.B */
+                       *rex_tag |= AMD64_REX_B;
+               } else {
+                       /* Shift the instruction by one byte  */
+                       /* so we can insert a rex prefix      */
+                       memmove (rex_tag + 1, rex_tag, (size_t)(*code - rex_tag));
+                       *code += 1;
+                       /* New rex prefix only needs rex.B for %r15 base */
+                       *rex_tag = AMD64_REX(AMD64_REX_B);
+               }
+
+               if (legacy_prefix_tag) {
+                       old_instruction_start = legacy_prefix_tag;
+               } else {
+                       old_instruction_start = rex_tag;
+               }
+               
+               /* Clears the upper 32-bits of the previous base register */
+               amd64_mov_reg_reg_size (buf_ptr, true_basereg, true_basereg, 4);
+               insert_len = buf_ptr - buf;
+               
+               /* Move the old instruction forward to make */
+               /* room for 'mov' stored in 'buf_ptr'       */
+               memmove (old_instruction_start + insert_len, old_instruction_start, (size_t)(*code - old_instruction_start));
+               *code += insert_len;
+               memcpy (old_instruction_start, buf, insert_len);
+
+               /* Sandboxed replacement for the normal membase_emit */
+               x86_memindex_emit (*code, dreg, AMD64_R15, offset, basereg, 0);
+               
+       } else {
+               /* Normal default behavior, emit membase memory location */
+               x86_membase_emit_body (*code, dreg, basereg, offset);
+       }
+}
+
+
+static inline unsigned char*
+amd64_skip_nops (unsigned char* code)
+{
+       guint8 in_nop;
+       do {
+               in_nop = 0;
+               if (   code[0] == 0x90) {
+                       in_nop = 1;
+                       code += 1;
+               }
+               if (   code[0] == 0x66 && code[1] == 0x90) {
+                       in_nop = 1;
+                       code += 2;
+               }
+               if (code[0] == 0x0f && code[1] == 0x1f
+                && code[2] == 0x00) {
+                       in_nop = 1;
+                       code += 3;
+               }
+               if (code[0] == 0x0f && code[1] == 0x1f
+                && code[2] == 0x40 && code[3] == 0x00) {
+                       in_nop = 1;
+                       code += 4;
+               }
+               if (code[0] == 0x0f && code[1] == 0x1f
+                && code[2] == 0x44 && code[3] == 0x00
+                && code[4] == 0x00) {
+                       in_nop = 1;
+                       code += 5;
+               }
+               if (code[0] == 0x66 && code[1] == 0x0f
+                && code[2] == 0x1f && code[3] == 0x44
+                && code[4] == 0x00 && code[5] == 0x00) {
+                       in_nop = 1;
+                       code += 6;
+               }
+               if (code[0] == 0x0f && code[1] == 0x1f
+                && code[2] == 0x80 && code[3] == 0x00
+                && code[4] == 0x00 && code[5] == 0x00
+                && code[6] == 0x00) {
+                       in_nop = 1;
+                       code += 7;
+               }
+               if (code[0] == 0x0f && code[1] == 0x1f
+                && code[2] == 0x84 && code[3] == 0x00
+                && code[4] == 0x00 && code[5] == 0x00
+                && code[6] == 0x00 && code[7] == 0x00) {
+                       in_nop = 1;
+                       code += 8;
+               }
+       } while ( in_nop );
+       return code;
+}
+
+guint8*
+mono_arch_nacl_skip_nops (guint8* code)
+{
+  return amd64_skip_nops(code);
+}
+
+#endif /*__native_client_codegen__*/
+
 static inline void 
 amd64_patch (unsigned char* code, gpointer target)
 {
        guint8 rex = 0;
 
+#ifdef __native_client_codegen__
+       code = amd64_skip_nops (code);
+#endif
+#if defined(__native_client_codegen__) && defined(__native_client__)
+       if (nacl_is_code_address (code)) {
+               /* For tail calls, code is patched after being installed */
+               /* but not through the normal "patch callsite" method.   */
+               unsigned char buf[kNaClAlignment];
+               unsigned char *aligned_code = (uintptr_t)code & ~kNaClAlignmentMask;
+               int ret;
+               memcpy (buf, aligned_code, kNaClAlignment);
+               /* Patch a temp buffer of bundle size, */
+               /* then install to actual location.    */
+               amd64_patch (buf + ((uintptr_t)code - (uintptr_t)aligned_code), target);
+               ret = nacl_dyncode_modify (aligned_code, buf, kNaClAlignment);
+               g_assert (ret == 0);
+               return;
+       }
+       target = nacl_modify_patch_target (target);
+#endif
+
        /* Skip REX */
        if ((code [0] >= 0x40) && (code [0] <= 0x4f)) {
                rex = code [0];
@@ -227,7 +506,7 @@ amd64_patch (unsigned char* code, gpointer target)
                /* call *<OFFSET>(%rip) */
                *(guint32*)(code + 2) = ((guint32)(guint64)target) - 7;
        }
-       else if ((code [0] == 0xe8)) {
+       else if (code [0] == 0xe8) {
                /* call <DISP> */
                gint64 disp = (guint8*)target - (guint8*)code;
                g_assert (amd64_is_imm32 (disp));
@@ -261,6 +540,7 @@ typedef struct {
        /* Only if storage == ArgValuetypeInReg */
        ArgStorage pair_storage [2];
        gint8 pair_regs [2];
+       int nregs;
 } ArgInfo;
 
 typedef struct {
@@ -300,7 +580,9 @@ add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
 
     if (*gr >= PARAM_REGS) {
                ainfo->storage = ArgOnStack;
-               (*stack_size) += sizeof (gpointer);
+               /* Since the same stack slot size is used for all arg */
+               /*  types, it needs to be big enough to hold them all */
+               (*stack_size) += sizeof(mgreg_t);
     }
     else {
                ainfo->storage = ArgInIReg;
@@ -322,7 +604,9 @@ add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
 
     if (*gr >= FLOAT_PARAM_REGS) {
                ainfo->storage = ArgOnStack;
-               (*stack_size) += sizeof (gpointer);
+               /* Since the same stack slot size is used for both float */
+               /*  types, it needs to be big enough to hold them both */
+               (*stack_size) += sizeof(mgreg_t);
     }
     else {
                /* A double register */
@@ -417,6 +701,32 @@ merge_argument_class_from_type (MonoType *type, ArgumentClass class1)
 
        return class1;
 }
+#ifdef __native_client_codegen__
+const guint kNaClAlignment = kNaClAlignmentAMD64;
+const guint kNaClAlignmentMask = kNaClAlignmentMaskAMD64;
+
+/* Default alignment for Native Client is 32-byte. */
+gint8 nacl_align_byte = -32; /* signed version of 0xe0 */
+
+/* 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 = 8; /* see amd64-codegen.h:amd64_padding_size() */
+
+       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) {
+               amd64_padding (code, kMaxPadding);
+               pad -= kMaxPadding;
+       }
+       if (pad != 0) amd64_padding (code, pad);
+       return code;
+}
+#endif
 
 static void
 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
@@ -424,6 +734,9 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
                           guint32 *gr, guint32 *fr, guint32 *stack_size)
 {
        guint32 size, quad, nquads, i;
+       /* Keep track of the size used in each quad so we can */
+       /* use the right size when copying args/return vars.  */
+       guint32 quadsize [2] = {8, 8};
        ArgumentClass args [2];
        MonoMarshalType *info = NULL;
        MonoClass *klass;
@@ -452,6 +765,25 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
        }
 #endif
 
+       /* If this struct can't be split up naturally into 8-byte */
+       /* chunks (registers), pass it on the stack.              */
+       if (sig->pinvoke && !pass_on_stack) {
+               guint32 align;
+               guint32 field_size;
+
+               info = mono_marshal_load_type_info (klass);
+               g_assert(info);
+               for (i = 0; i < info->num_fields; ++i) {
+                       field_size = mono_marshal_type_size (info->fields [i].field->type, 
+                                                          info->fields [i].mspec, 
+                                                          &align, TRUE, klass->unicode);
+                       if ((info->fields [i].offset < 8) && (info->fields [i].offset + field_size) > 8) {
+                               pass_on_stack = TRUE;
+                               break;
+                       }
+               }
+       }
+
        if (pass_on_stack) {
                /* Allways pass in memory */
                ainfo->offset = *stack_size;
@@ -551,6 +883,10 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
                                if ((quad == 1) && (info->fields [i].offset < 8))
                                        continue;
 
+                               /* How far into this quad this data extends.*/
+                               /* (8 is size of quad) */
+                               quadsize [quad] = info->fields [i].offset + size - (quad * 8);
+
                                class1 = merge_argument_class_from_type (info->fields [i].field->type, class1);
                        }
                        g_assert (class1 != ARG_CLASS_NO_CLASS);
@@ -569,6 +905,7 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
 
                ainfo->storage = ArgValuetypeInReg;
                ainfo->pair_storage [0] = ainfo->pair_storage [1] = ArgNone;
+               ainfo->nregs = nquads;
                for (quad = 0; quad < nquads; ++quad) {
                        switch (args [quad]) {
                        case ARG_CLASS_INTEGER:
@@ -587,7 +924,9 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
                                if (*fr >= FLOAT_PARAM_REGS)
                                        args [quad] = ARG_CLASS_MEMORY;
                                else {
-                                       ainfo->pair_storage [quad] = ArgInDoubleSSEReg;
+                                       if (quadsize[quad] <= 4)
+                                               ainfo->pair_storage [quad] = ArgInFloatSSEReg;
+                                       else ainfo->pair_storage [quad] = ArgInDoubleSSEReg;
                                        ainfo->pair_regs [quad] = *fr;
                                        (*fr) ++;
                                }
@@ -608,7 +947,7 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
                        if (sig->pinvoke)
                                *stack_size += ALIGN_TO (info->native_size, 8);
                        else
-                               *stack_size += nquads * sizeof (gpointer);
+                               *stack_size += nquads * sizeof(mgreg_t);
                        ainfo->storage = ArgOnStack;
                }
        }
@@ -622,13 +961,14 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
  * Draft Version 0.23" document for more information.
  */
 static CallInfo*
-get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
+get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
 {
        guint32 i, gr, fr, pstart;
        MonoType *ret_type;
        int n = sig->hasthis + sig->param_count;
        guint32 stack_size = 0;
        CallInfo *cinfo;
+       gboolean is_pinvoke = sig->pinvoke;
 
        if (mp)
                cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
@@ -836,11 +1176,13 @@ get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSign
        stack_size += 0x20;
 #endif
 
+#ifndef MONO_AMD64_NO_PUSHES
        if (stack_size & 0x8) {
                /* The AMD64 ABI requires each stack frame to be 16 byte aligned */
                cinfo->need_stack_align = TRUE;
                stack_size += 8;
        }
+#endif
 
        cinfo->stack_usage = stack_size;
        cinfo->reg_usage = gr;
@@ -863,7 +1205,7 @@ int
 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
 {
        int k;
-       CallInfo *cinfo = get_call_info (NULL, NULL, csig, FALSE);
+       CallInfo *cinfo = get_call_info (NULL, NULL, csig);
        guint32 args_size = cinfo->stack_usage;
 
        /* The arguments are saved to a stack area in mono_arch_instrument_prolog */
@@ -888,8 +1230,8 @@ mono_amd64_tail_call_supported (MonoMethodSignature *caller_sig, MonoMethodSigna
        CallInfo *c1, *c2;
        gboolean res;
 
-       c1 = get_call_info (NULL, NULL, caller_sig, FALSE);
-       c2 = get_call_info (NULL, NULL, callee_sig, FALSE);
+       c1 = get_call_info (NULL, NULL, caller_sig);
+       c2 = get_call_info (NULL, NULL, callee_sig);
        res = c1->stack_usage >= c2->stack_usage;
        if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret) && c2->ret.storage != ArgValuetypeInReg)
                /* An address on the callee's stack is passed as the first argument */
@@ -904,6 +1246,9 @@ mono_amd64_tail_call_supported (MonoMethodSignature *caller_sig, MonoMethodSigna
 static int 
 cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx)
 {
+#if defined(MONO_CROSS_COMPILE)
+       return 0;
+#else
 #ifndef _MSC_VER
        __asm__ __volatile__ ("cpuid"
                : "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
@@ -917,6 +1262,7 @@ cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx)
        *p_edx = info[3];
 #endif
        return 1;
+#endif
 }
 
 /*
@@ -950,22 +1296,28 @@ mono_arch_init (void)
        int flags;
 
        InitializeCriticalSection (&mini_arch_mutex);
+#if defined(__native_client_codegen__)
+       mono_native_tls_alloc (&nacl_instruction_depth, NULL);
+       mono_native_tls_set_value (nacl_instruction_depth, (gpointer)0);
+       mono_native_tls_alloc (&nacl_rex_tag, NULL);
+       mono_native_tls_alloc (&nacl_legacy_prefix_tag, NULL);
+#endif
 
 #ifdef MONO_ARCH_NOMAP32BIT
        flags = MONO_MMAP_READ;
        /* amd64_mov_reg_imm () + amd64_mov_reg_membase () */
        breakpoint_size = 13;
        breakpoint_fault_size = 3;
-       /* amd64_alu_membase_imm_size (code, X86_CMP, AMD64_R11, 0, 0, 4); */
-       single_step_fault_size = 5;
 #else
        flags = MONO_MMAP_READ|MONO_MMAP_32BIT;
        /* amd64_mov_reg_mem () */
        breakpoint_size = 8;
        breakpoint_fault_size = 8;
-       single_step_fault_size = 8;
 #endif
 
+       /* amd64_alu_membase_imm_size (code, X86_CMP, AMD64_R11, 0, 0, 4); */
+       single_step_fault_size = 4;
+
        ss_trigger_page = mono_valloc (NULL, mono_pagesize (), flags);
        bp_trigger_page = mono_valloc (NULL, mono_pagesize (), flags);
        mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
@@ -982,6 +1334,11 @@ void
 mono_arch_cleanup (void)
 {
        DeleteCriticalSection (&mini_arch_mutex);
+#if defined(__native_client_codegen__)
+       mono_native_tls_free (nacl_instruction_depth);
+       mono_native_tls_free (nacl_rex_tag);
+       mono_native_tls_free (nacl_legacy_prefix_tag);
+#endif
 }
 
 /*
@@ -1104,7 +1461,7 @@ mono_arch_compute_omit_fp (MonoCompile *cfg)
        sig = mono_method_signature (cfg->method);
 
        if (!cfg->arch.cinfo)
-               cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
+               cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
        cinfo = cfg->arch.cinfo;
 
        /*
@@ -1113,6 +1470,13 @@ mono_arch_compute_omit_fp (MonoCompile *cfg)
        cfg->arch.omit_fp = TRUE;
        cfg->arch.omit_fp_computed = TRUE;
 
+#ifdef __native_client_codegen__
+       /* NaCl modules may not change the value of RBP, so it cannot be */
+       /* used as a normal register, but it can be used as a frame pointer*/
+       cfg->disable_omit_fp = TRUE;
+       cfg->arch.omit_fp = FALSE;
+#endif
+
        if (cfg->disable_omit_fp)
                cfg->arch.omit_fp = FALSE;
 
@@ -1169,7 +1533,9 @@ mono_arch_get_global_int_regs (MonoCompile *cfg)
                regs = g_list_prepend (regs, (gpointer)AMD64_R12);
                regs = g_list_prepend (regs, (gpointer)AMD64_R13);
                regs = g_list_prepend (regs, (gpointer)AMD64_R14);
+#ifndef __native_client_codegen__
                regs = g_list_prepend (regs, (gpointer)AMD64_R15);
+#endif
  
                regs = g_list_prepend (regs, (gpointer)AMD64_R10);
                regs = g_list_prepend (regs, (gpointer)AMD64_R9);
@@ -1188,7 +1554,9 @@ mono_arch_get_global_int_regs (MonoCompile *cfg)
                regs = g_list_prepend (regs, (gpointer)AMD64_R12);
                regs = g_list_prepend (regs, (gpointer)AMD64_R13);
                regs = g_list_prepend (regs, (gpointer)AMD64_R14);
+#ifndef __native_client_codegen__
                regs = g_list_prepend (regs, (gpointer)AMD64_R15);
+#endif
 #ifdef HOST_WIN32
                regs = g_list_prepend (regs, (gpointer)AMD64_RDI);
                regs = g_list_prepend (regs, (gpointer)AMD64_RSI);
@@ -1224,7 +1592,9 @@ mono_arch_get_iregs_clobbered_by_call (MonoCallInst *call)
                regs = g_list_prepend (regs, (gpointer)AMD64_R12);
                regs = g_list_prepend (regs, (gpointer)AMD64_R13);
                regs = g_list_prepend (regs, (gpointer)AMD64_R14);
+#ifndef __native_client_codegen__
                regs = g_list_prepend (regs, (gpointer)AMD64_R15);
+#endif
 
                regs = g_list_prepend (regs, (gpointer)AMD64_R10);
                regs = g_list_prepend (regs, (gpointer)AMD64_R9);
@@ -1410,22 +1780,14 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        }
 
        if (cfg->method->save_lmf) {
-               /* Reserve stack space for saving LMF */
-               if (cfg->arch.omit_fp) {
-                       cfg->arch.lmf_offset = offset;
-                       offset += sizeof (MonoLMF);
-               }
-               else {
-                       offset += sizeof (MonoLMF);
-                       cfg->arch.lmf_offset = -offset;
-               }
+               /* The LMF var is allocated normally */
        } else {
                if (cfg->arch.omit_fp)
                        cfg->arch.reg_save_area_offset = offset;
                /* Reserve space for caller saved registers */
                for (i = 0; i < AMD64_NREG; ++i)
                        if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
-                               offset += sizeof (gpointer);
+                               offset += sizeof(mgreg_t);
                        }
        }
 
@@ -1466,9 +1828,9 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                        cfg->ret->inst_basereg = cfg->frame_reg;
                        if (cfg->arch.omit_fp) {
                                cfg->ret->inst_offset = offset;
-                               offset += 16;
+                               offset += cinfo->ret.pair_storage [1] == ArgNone ? 8 : 16;
                        } else {
-                               offset += 16;
+                               offset += cinfo->ret.pair_storage [1] == ArgNone ? 8 : 16;
                                cfg->ret->inst_offset = - offset;
                        }
                        break;
@@ -1481,7 +1843,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
 
        /* Allocate locals */
        if (!cfg->globalra) {
-               offsets = mono_allocate_stack_slots_full (cfg, cfg->arch.omit_fp ? FALSE: TRUE, &locals_stack_size, &locals_stack_align);
+               offsets = mono_allocate_stack_slots (cfg, cfg->arch.omit_fp ? FALSE: TRUE, &locals_stack_size, &locals_stack_align);
                if (locals_stack_size > MONO_ARCH_MAX_FRAME_SIZE) {
                        char *mname = mono_method_full_name (cfg->method, TRUE);
                        cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
@@ -1554,12 +1916,12 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                                        ins->opcode = OP_REGOFFSET;
                                        ins->inst_basereg = cfg->frame_reg;
                                        /* These arguments are saved to the stack in the prolog */
-                                       offset = ALIGN_TO (offset, sizeof (gpointer));
+                                       offset = ALIGN_TO (offset, sizeof(mgreg_t));
                                        if (cfg->arch.omit_fp) {
                                                ins->inst_offset = offset;
-                                               offset += (ainfo->storage == ArgValuetypeInReg) ? 2 * sizeof (gpointer) : sizeof (gpointer);
+                                               offset += (ainfo->storage == ArgValuetypeInReg) ? ainfo->nregs * sizeof (mgreg_t) : sizeof (mgreg_t);
                                        } else {
-                                               offset += (ainfo->storage == ArgValuetypeInReg) ? 2 * sizeof (gpointer) : sizeof (gpointer);
+                                               offset += (ainfo->storage == ArgValuetypeInReg) ? ainfo->nregs * sizeof (mgreg_t) : sizeof (mgreg_t);
                                                ins->inst_offset = - offset;
                                        }
                                        break;
@@ -1631,14 +1993,14 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                                ins->opcode = OP_REGOFFSET;
                                ins->inst_basereg = cfg->frame_reg;
                                /* These arguments are saved to the stack in the prolog */
-                               offset = ALIGN_TO (offset, sizeof (gpointer));
+                               offset = ALIGN_TO (offset, sizeof(mgreg_t));
                                if (cfg->arch.omit_fp) {
                                        ins->inst_offset = offset;
-                                       offset += (ainfo->storage == ArgValuetypeInReg) ? 2 * sizeof (gpointer) : sizeof (gpointer);
+                                       offset += (ainfo->storage == ArgValuetypeInReg) ? ainfo->nregs * sizeof (mgreg_t) : sizeof (mgreg_t);
                                        // Arguments are yet supported by the stack map creation code
                                        //cfg->locals_max_stack_offset = MAX (cfg->locals_max_stack_offset, offset);
                                } else {
-                                       offset += (ainfo->storage == ArgValuetypeInReg) ? 2 * sizeof (gpointer) : sizeof (gpointer);
+                                       offset += (ainfo->storage == ArgValuetypeInReg) ? ainfo->nregs * sizeof (mgreg_t) : sizeof (mgreg_t);
                                        ins->inst_offset = - offset;
                                        //cfg->locals_min_stack_offset = MIN (cfg->locals_min_stack_offset, offset);
                                }
@@ -1658,7 +2020,7 @@ mono_arch_create_vars (MonoCompile *cfg)
        sig = mono_method_signature (cfg->method);
 
        if (!cfg->arch.cinfo)
-               cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
+               cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
        cinfo = cfg->arch.cinfo;
 
        if (cinfo->ret.storage == ArgValuetypeInReg)
@@ -1675,6 +2037,12 @@ mono_arch_create_vars (MonoCompile *cfg)
        if (cfg->gen_seq_points) {
                MonoInst *ins;
 
+               if (cfg->compile_aot) {
+                       MonoInst *ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+                       ins->flags |= MONO_INST_VOLATILE;
+                       cfg->arch.seq_point_info_var = ins;
+               }
+
            ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
                ins->flags |= MONO_INST_VOLATILE;
                cfg->arch.ss_trigger_page_var = ins;
@@ -1692,6 +2060,17 @@ mono_arch_create_vars (MonoCompile *cfg)
         */
        cfg->arch.no_pushes = TRUE;
 #endif
+
+       if (cfg->method->save_lmf) {
+               MonoInst *lmf_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+               lmf_var->flags |= MONO_INST_VOLATILE;
+               lmf_var->flags |= MONO_INST_LMF;
+               cfg->arch.lmf_var = lmf_var;
+       }
+
+#ifndef MONO_AMD64_NO_PUSHES
+       cfg->arch_eh_jit_info = 1;
+#endif
 }
 
 static void
@@ -1702,7 +2081,7 @@ add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int re
        switch (storage) {
        case ArgInIReg:
                MONO_INST_NEW (cfg, ins, OP_MOVE);
-               ins->dreg = mono_alloc_ireg (cfg);
+               ins->dreg = mono_alloc_ireg_copy (cfg, tree->dreg);
                ins->sreg1 = tree->dreg;
                MONO_ADD_INS (cfg->cbb, ins);
                mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, FALSE);
@@ -1734,7 +2113,11 @@ arg_storage_to_load_membase (ArgStorage storage)
 {
        switch (storage) {
        case ArgInIReg:
+#if defined(__mono_ilp32__)
+               return OP_LOADI8_MEMBASE;
+#else
                return OP_LOAD_MEMBASE;
+#endif
        case ArgInDoubleSSEReg:
                return OP_LOADR8_MEMBASE;
        case ArgInFloatSSEReg:
@@ -1751,14 +2134,11 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
 {
        MonoInst *arg;
        MonoMethodSignature *tmp_sig;
-       MonoInst *sig_arg;
+       int sig_reg;
 
        if (call->tail_call)
                NOT_IMPLEMENTED;
 
-       /* FIXME: Add support for signature tokens to AOT */
-       cfg->disable_aot = TRUE;
-
        g_assert (cinfo->sig_cookie.storage == ArgOnStack);
                        
        /*
@@ -1767,21 +2147,19 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
         * passed on the stack after the signature. So compensate by 
         * passing a different signature.
         */
-       tmp_sig = mono_metadata_signature_dup (call->signature);
+       tmp_sig = mono_metadata_signature_dup_full (cfg->method->klass->image, call->signature);
        tmp_sig->param_count -= call->signature->sentinelpos;
        tmp_sig->sentinelpos = 0;
        memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
 
-       MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
-       sig_arg->dreg = mono_alloc_ireg (cfg);
-       sig_arg->inst_p0 = tmp_sig;
-       MONO_ADD_INS (cfg->cbb, sig_arg);
+       sig_reg = mono_alloc_ireg (cfg);
+       MONO_EMIT_NEW_SIGNATURECONST (cfg, sig_reg, tmp_sig);
 
        if (cfg->arch.no_pushes) {
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, cinfo->sig_cookie.offset, sig_arg->dreg);
+               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, cinfo->sig_cookie.offset, sig_reg);
        } else {
                MONO_INST_NEW (cfg, arg, OP_X86_PUSH);
-               arg->sreg1 = sig_arg->dreg;
+               arg->sreg1 = sig_reg;
                MONO_ADD_INS (cfg->cbb, arg);
        }
 }
@@ -1813,7 +2191,7 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
 
        n = sig->param_count + sig->hasthis;
 
-       cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, sig->pinvoke);
+       cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
 
        linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
 
@@ -1908,7 +2286,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
        sig = call->signature;
        n = sig->param_count + sig->hasthis;
 
-       cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, sig->pinvoke);
+       cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
 
        if (COMPILE_LLVM (cfg)) {
                /* We shouldn't be called in the llvm case */
@@ -1948,6 +2326,11 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                                } else {
                                        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, AMD64_RSP, ainfo->offset, in->dreg);
                                }
+                               if (cfg->compute_gc_maps) {
+                                       MonoInst *def;
+
+                                       EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF (cfg, def, ainfo->offset, t);
+                               }
                        }
                }
        }
@@ -2138,7 +2521,7 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
 
                        MONO_INST_NEW (cfg, load, arg_storage_to_load_membase (ainfo->pair_storage [part]));
                        load->inst_basereg = src->dreg;
-                       load->inst_offset = part * sizeof (gpointer);
+                       load->inst_offset = part * sizeof(mgreg_t);
 
                        switch (ainfo->pair_storage [part]) {
                        case ArgInIReg:
@@ -2215,6 +2598,11 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
                                MONO_ADD_INS (cfg->cbb, arg);
                        }
                }
+
+               if (cfg->compute_gc_maps) {
+                       MonoInst *def;
+                       EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF (cfg, def, ainfo->offset, &ins->klass->byval_arg);
+               }
        }
 }
 
@@ -2321,7 +2709,7 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
        ArchDynCallInfo *info;
        CallInfo *cinfo;
 
-       cinfo = get_call_info (NULL, NULL, sig, FALSE);
+       cinfo = get_call_info (NULL, NULL, sig);
 
        if (!dyn_call_supported (sig, cinfo)) {
                g_free (cinfo);
@@ -2350,6 +2738,15 @@ mono_arch_dyn_call_free (MonoDynCallInfo *info)
        g_free (ainfo);
 }
 
+#if !defined(__native_client__)
+#define PTR_TO_GREG(ptr) (mgreg_t)(ptr)
+#define GREG_TO_PTR(greg) (gpointer)(greg)
+#else
+/* Correctly handle casts to/from 32-bit pointers without compiler warnings */
+#define PTR_TO_GREG(ptr) (mgreg_t)(uintptr_t)(ptr)
+#define GREG_TO_PTR(greg) (gpointer)(guint32)(greg)
+#endif
+
 /*
  * mono_arch_get_start_dyn_call:
  *
@@ -2382,20 +2779,20 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
        pindex = 0;
 
        if (sig->hasthis || dinfo->cinfo->vret_arg_index == 1) {
-               p->regs [greg ++] = (mgreg_t)*(args [arg_index ++]);
+               p->regs [greg ++] = PTR_TO_GREG(*(args [arg_index ++]));
                if (!sig->hasthis)
                        pindex = 1;
        }
 
        if (dinfo->cinfo->vtype_retaddr)
-               p->regs [greg ++] = (mgreg_t)ret;
+               p->regs [greg ++] = PTR_TO_GREG(ret);
 
        for (i = pindex; i < sig->param_count; i++) {
                MonoType *t = mono_type_get_underlying_type (sig->params [i]);
                gpointer *arg = args [arg_index ++];
 
                if (t->byref) {
-                       p->regs [greg ++] = (mgreg_t)*(arg);
+                       p->regs [greg ++] = PTR_TO_GREG(*(arg));
                        continue;
                }
 
@@ -2408,11 +2805,20 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
                case MONO_TYPE_PTR:
                case MONO_TYPE_I:
                case MONO_TYPE_U:
+#if !defined(__mono_ilp32__)
                case MONO_TYPE_I8:
                case MONO_TYPE_U8:
+#endif
                        g_assert (dinfo->cinfo->args [i + sig->hasthis].reg == param_regs [greg]);
-                       p->regs [greg ++] = (mgreg_t)*(arg);
+                       p->regs [greg ++] = PTR_TO_GREG(*(arg));
                        break;
+#if defined(__mono_ilp32__)
+               case MONO_TYPE_I8:
+               case MONO_TYPE_U8:
+                       g_assert (dinfo->cinfo->args [i + sig->hasthis].reg == param_regs [greg]);
+                       p->regs [greg ++] = *(guint64*)(arg);
+                       break;
+#endif
                case MONO_TYPE_BOOLEAN:
                case MONO_TYPE_U1:
                        p->regs [greg ++] = *(guint8*)(arg);
@@ -2435,7 +2841,7 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g
                        break;
                case MONO_TYPE_GENERICINST:
                    if (MONO_TYPE_IS_REFERENCE (t)) {
-                               p->regs [greg ++] = (mgreg_t)*(arg);
+                               p->regs [greg ++] = PTR_TO_GREG(*(arg));
                                break;
                        } else {
                                /* Fall through */
@@ -2491,7 +2897,7 @@ mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf)
        case MONO_TYPE_I:
        case MONO_TYPE_U:
        case MONO_TYPE_PTR:
-               *(gpointer*)ret = (gpointer)res;
+               *(gpointer*)ret = GREG_TO_PTR(res);
                break;
        case MONO_TYPE_I1:
                *(gint8*)ret = res;
@@ -2521,7 +2927,7 @@ mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf)
                break;
        case MONO_TYPE_GENERICINST:
                if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
-                       *(gpointer*)ret = (gpointer)res;
+                       *(gpointer*)ret = GREG_TO_PTR(res);
                        break;
                } else {
                        /* Fall through */
@@ -2674,8 +3080,10 @@ emit_call_body (MonoCompile *cfg, guint8 *code, guint32 patch_type, gconstpointe
                         * not span cache lines. This is required for code patching to work on SMP
                         * systems.
                         */
-                       if (!no_patch && ((guint32)(code + 1 - cfg->native_code) % 4) != 0)
-                               amd64_padding (code, 4 - ((guint32)(code + 1 - cfg->native_code) % 4));
+                       if (!no_patch && ((guint32)(code + 1 - cfg->native_code) % 4) != 0) {
+                               guint32 pad_size = 4 - ((guint32)(code + 1 - cfg->native_code) % 4);
+                               amd64_padding (code, pad_size);
+                       }
                        mono_add_patch_info (cfg, code - cfg->native_code, patch_type, data);
                        amd64_call_code (code, 0);
                }
@@ -2861,7 +3269,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
                                        if (((ins2->opcode == OP_STORE_MEMBASE_IMM) || (ins2->opcode == OP_STOREI4_MEMBASE_IMM) || (ins2->opcode == OP_STOREI8_MEMBASE_IMM) || (ins2->opcode == OP_STORE_MEMBASE_IMM)) && (ins2->inst_imm == 0)) {
                                                ins2->opcode = store_membase_imm_to_store_membase_reg (ins2->opcode);
                                                ins2->sreg1 = ins->dreg;
-                                       } else if ((ins2->opcode == OP_STOREI1_MEMBASE_IMM) || (ins2->opcode == OP_STOREI2_MEMBASE_IMM) || (ins2->opcode == OP_STOREI4_MEMBASE_REG) || (ins2->opcode == OP_STOREI8_MEMBASE_REG) || (ins2->opcode == OP_STORE_MEMBASE_REG) || (ins2->opcode == OP_LIVERANGE_START)) {
+                                       } else if ((ins2->opcode == OP_STOREI1_MEMBASE_IMM) || (ins2->opcode == OP_STOREI2_MEMBASE_IMM) || (ins2->opcode == OP_STOREI4_MEMBASE_REG) || (ins2->opcode == OP_STOREI8_MEMBASE_REG) || (ins2->opcode == OP_STORE_MEMBASE_REG) || (ins2->opcode == OP_LIVERANGE_START) || (ins2->opcode == OP_GC_LIVENESS_DEF) || (ins2->opcode == OP_GC_LIVENESS_USE)) {
                                                /* Continue */
                                        } else if (((ins2->opcode == OP_ICONST) || (ins2->opcode == OP_I8CONST)) && (ins2->dreg == ins->dreg) && (ins2->inst_c0 == 0)) {
                                                NULLIFY_INS (ins2);
@@ -2932,8 +3340,13 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                                ins->sreg2 = temp->dreg;
                        }
                        break;
+#ifndef __mono_ilp32__
                case OP_LOAD_MEMBASE:
+#endif
                case OP_LOADI8_MEMBASE:
+#ifndef __native_client_codegen__
+               /*  Don't generate memindex opcodes (to simplify */
+               /*  read sandboxing) */
                        if (!amd64_is_imm32 (ins->inst_offset)) {
                                NEW_INS (cfg, ins, temp, OP_I8CONST);
                                temp->inst_c0 = ins->inst_offset;
@@ -2941,8 +3354,11 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                                ins->opcode = OP_AMD64_LOADI8_MEMINDEX;
                                ins->inst_indexreg = temp->dreg;
                        }
+#endif
                        break;
+#ifndef __mono_ilp32__
                case OP_STORE_MEMBASE_IMM:
+#endif
                case OP_STOREI8_MEMBASE_IMM:
                        if (!amd64_is_imm32 (ins->inst_imm)) {
                                NEW_INS (cfg, ins, temp, OP_I8CONST);
@@ -3094,8 +3510,20 @@ mono_emit_stack_alloc (MonoCompile *cfg, guchar *code, MonoInst* tree)
                if (cfg->param_area && cfg->arch.no_pushes)
                        amd64_alu_reg_imm (code, X86_ADD, AMD64_RDI, cfg->param_area);
                amd64_cld (code);
+#if defined(__default_codegen__)
+               amd64_prefix (code, X86_REP_PREFIX);
+               amd64_stosl (code);
+#elif defined(__native_client_codegen__)
+               /* NaCl stos pseudo-instruction */
+               amd64_codegen_pre(code);
+               /* First, clear the upper 32 bits of RDI (mov %edi, %edi)  */
+               amd64_mov_reg_reg (code, AMD64_RDI, AMD64_RDI, 4);
+               /* Add %r15 to %rdi using lea, condition flags unaffected. */
+               amd64_lea_memindex_size (code, AMD64_RDI, AMD64_R15, 0, AMD64_RDI, 0, 8);
                amd64_prefix (code, X86_REP_PREFIX);
                amd64_stosl (code);
+               amd64_codegen_post(code);
+#endif /* __native_client_codegen__ */
                
                if (tree->dreg != AMD64_RDI && sreg != AMD64_RDI)
                        amd64_pop_reg (code, AMD64_RDI);
@@ -3141,18 +3569,18 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
        case OP_VCALL2:
        case OP_VCALL2_REG:
        case OP_VCALL2_MEMBASE:
-               cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
+               cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, ((MonoCallInst*)ins)->signature);
                if (cinfo->ret.storage == ArgValuetypeInReg) {
                        MonoInst *loc = cfg->arch.vret_addr_loc;
 
                        /* Load the destination address */
                        g_assert (loc->opcode == OP_REGOFFSET);
-                       amd64_mov_reg_membase (code, AMD64_RCX, loc->inst_basereg, loc->inst_offset, 8);
+                       amd64_mov_reg_membase (code, AMD64_RCX, loc->inst_basereg, loc->inst_offset, sizeof(gpointer));
 
                        for (quad = 0; quad < 2; quad ++) {
                                switch (cinfo->ret.pair_storage [quad]) {
                                case ArgInIReg:
-                                       amd64_mov_membase_reg (code, AMD64_RCX, (quad * 8), cinfo->ret.pair_regs [quad], 8);
+                                       amd64_mov_membase_reg (code, AMD64_RCX, (quad * sizeof(mgreg_t)), cinfo->ret.pair_regs [quad], sizeof(mgreg_t));
                                        break;
                                case ArgInFloatSSEReg:
                                        amd64_movss_membase_reg (code, AMD64_RCX, (quad * 8), cinfo->ret.pair_regs [quad]);
@@ -3175,6 +3603,48 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
 
 #endif /* DISABLE_JIT */
 
+#ifdef __APPLE__
+static int tls_gs_offset;
+#endif
+
+gboolean
+mono_amd64_have_tls_get (void)
+{
+#ifdef __APPLE__
+       static gboolean have_tls_get = FALSE;
+       static gboolean inited = FALSE;
+
+       if (inited)
+               return have_tls_get;
+
+       guint8 *ins = (guint8*)pthread_getspecific;
+
+       /*
+        * We're looking for these two instructions:
+        *
+        * mov    %gs:[offset](,%rdi,8),%rax
+        * retq
+        */
+       have_tls_get = ins [0] == 0x65 &&
+                      ins [1] == 0x48 &&
+                      ins [2] == 0x8b &&
+                      ins [3] == 0x04 &&
+                      ins [4] == 0xfd &&
+                      ins [6] == 0x00 &&
+                      ins [7] == 0x00 &&
+                      ins [8] == 0x00 &&
+                      ins [9] == 0xc3;
+
+       inited = TRUE;
+
+       tls_gs_offset = ins[5];
+
+       return have_tls_get;
+#else
+       return TRUE;
+#endif
+}
+
 /*
  * mono_amd64_emit_tls_get:
  * @code: buffer to store code to
@@ -3194,6 +3664,9 @@ mono_amd64_emit_tls_get (guint8* code, int dreg, int tls_offset)
        g_assert (tls_offset < 64);
        x86_prefix (code, X86_GS_PREFIX);
        amd64_mov_reg_mem (code, dreg, (tls_offset * 8) + 0x1480, 8);
+#elif defined(__APPLE__)
+       x86_prefix (code, X86_GS_PREFIX);
+       amd64_mov_reg_mem (code, dreg, tls_gs_offset + (tls_offset * 8), 8);
 #else
        if (optimize_for_xen) {
                x86_prefix (code, X86_FS_PREFIX);
@@ -3207,6 +3680,165 @@ mono_amd64_emit_tls_get (guint8* code, int dreg, int tls_offset)
        return code;
 }
 
+/*
+ * emit_setup_lmf:
+ *
+ *   Emit code to initialize an LMF structure at LMF_OFFSET.
+ */
+static guint8*
+emit_setup_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, int cfa_offset)
+{
+       int i;
+
+       /* 
+        * The ip field is not set, the exception handling code will obtain it from the stack location pointed to by the sp field.
+        */
+       /* 
+        * sp is saved right before calls but we need to save it here too so
+        * async stack walks would work.
+        */
+       amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rsp), AMD64_RSP, 8);
+       /* Skip method (only needed for trampoline LMF frames) */
+       /* Save callee saved regs */
+       for (i = 0; i < MONO_MAX_IREGS; ++i) {
+               int offset;
+
+               switch (i) {
+               case AMD64_RBX: offset = G_STRUCT_OFFSET (MonoLMF, rbx); break;
+               case AMD64_RBP: offset = G_STRUCT_OFFSET (MonoLMF, rbp); break;
+               case AMD64_R12: offset = G_STRUCT_OFFSET (MonoLMF, r12); break;
+               case AMD64_R13: offset = G_STRUCT_OFFSET (MonoLMF, r13); break;
+               case AMD64_R14: offset = G_STRUCT_OFFSET (MonoLMF, r14); break;
+#ifndef __native_client_codegen__
+               case AMD64_R15: offset = G_STRUCT_OFFSET (MonoLMF, r15); break;
+#endif
+#ifdef HOST_WIN32
+               case AMD64_RDI: offset = G_STRUCT_OFFSET (MonoLMF, rdi); break;
+               case AMD64_RSI: offset = G_STRUCT_OFFSET (MonoLMF, rsi); break;
+#endif
+               default:
+                       offset = -1;
+                       break;
+               }
+
+               if (offset != -1) {
+                       amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + offset, i, 8);
+                       if ((cfg->arch.omit_fp || (i != AMD64_RBP)) && cfa_offset != -1)
+                               mono_emit_unwind_op_offset (cfg, code, i, - (cfa_offset - (lmf_offset + offset)));
+               }
+       }
+
+       /* These can't contain refs */
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), SLOT_NOREF);
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), SLOT_NOREF);
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method), SLOT_NOREF);
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rip), SLOT_NOREF);
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rsp), SLOT_NOREF);
+
+       /* These are handled automatically by the stack marking code */
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rbx), SLOT_NOREF);
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rbp), SLOT_NOREF);
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, r12), SLOT_NOREF);
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, r13), SLOT_NOREF);
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, r14), SLOT_NOREF);
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, r15), SLOT_NOREF);
+#ifdef HOST_WIN32
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rdi), SLOT_NOREF);
+       mini_gc_set_slot_type_from_fp (cfg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rsi), SLOT_NOREF);
+#endif
+
+       return code;
+}
+
+/*
+ * emit_save_lmf:
+ *
+ *   Emit code to push an LMF structure on the LMF stack.
+ */
+static guint8*
+emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, gboolean *args_clobbered)
+{
+       if ((lmf_tls_offset != -1) && !optimize_for_xen) {
+               /*
+                * Optimized version which uses the mono_lmf TLS variable instead of 
+                * indirection through the mono_lmf_addr TLS variable.
+                */
+               /* %rax = previous_lmf */
+               x86_prefix (code, X86_FS_PREFIX);
+               amd64_mov_reg_mem (code, AMD64_RAX, lmf_tls_offset, 8);
+
+               /* Save previous_lmf */
+               amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), AMD64_RAX, 8);
+               /* Set new lmf */
+               if (lmf_offset == 0) {
+                       x86_prefix (code, X86_FS_PREFIX);
+                       amd64_mov_mem_reg (code, lmf_tls_offset, cfg->frame_reg, 8);
+               } else {
+                       amd64_lea_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset);
+                       x86_prefix (code, X86_FS_PREFIX);
+                       amd64_mov_mem_reg (code, lmf_tls_offset, AMD64_R11, 8);
+               }
+       } else {
+               if (lmf_addr_tls_offset != -1) {
+                       /* Load lmf quicky using the FS register */
+                       code = mono_amd64_emit_tls_get (code, AMD64_RAX, lmf_addr_tls_offset);
+#ifdef HOST_WIN32
+                       /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
+                       /* FIXME: Add a separate key for LMF to avoid this */
+                       amd64_alu_reg_imm (code, X86_ADD, AMD64_RAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
+#endif
+               }
+               else {
+                       /* 
+                        * The call might clobber argument registers, but they are already
+                        * saved to the stack/global regs.
+                        */
+                       if (args_clobbered)
+                               *args_clobbered = TRUE;
+                       code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
+                                                         (gpointer)"mono_get_lmf_addr", TRUE);         
+               }
+
+               /* Save lmf_addr */
+               amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), AMD64_RAX, sizeof(gpointer));
+               /* Save previous_lmf */
+               amd64_mov_reg_membase (code, AMD64_R11, AMD64_RAX, 0, sizeof(gpointer));
+               amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), AMD64_R11, sizeof(gpointer));
+               /* Set new lmf */
+               amd64_lea_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset);
+               amd64_mov_membase_reg (code, AMD64_RAX, 0, AMD64_R11, sizeof(gpointer));
+       }
+
+       return code;
+}
+
+/*
+ * emit_save_lmf:
+ *
+ *   Emit code to pop an LMF structure from the LMF stack.
+ */
+static guint8*
+emit_restore_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
+{
+       if ((lmf_tls_offset != -1) && !optimize_for_xen) {
+               /*
+                * Optimized version which uses the mono_lmf TLS variable instead of indirection
+                * through the mono_lmf_addr TLS variable.
+                */
+               /* reg = previous_lmf */
+               amd64_mov_reg_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sizeof(gpointer));
+               x86_prefix (code, X86_FS_PREFIX);
+               amd64_mov_mem_reg (code, lmf_tls_offset, AMD64_R11, 8);
+       } else {
+               /* Restore previous lmf */
+               amd64_mov_reg_membase (code, AMD64_RCX, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sizeof(gpointer));
+               amd64_mov_reg_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), sizeof(gpointer));
+               amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RCX, sizeof(gpointer));
+       }
+
+       return code;
+}
+
 #define REAL_PRINT_REG(text,reg) \
 mono_assert (reg >= 0); \
 amd64_push_reg (code, AMD64_RAX); \
@@ -3228,6 +3860,15 @@ amd64_pop_reg (code, AMD64_RAX);
 
 #ifndef DISABLE_JIT
 
+#if defined(__native_client__) || defined(__native_client_codegen__)
+void mono_nacl_gc()
+{
+#ifdef __native_client_gc__
+       __nacl_suspend_thread_if_needed();
+#endif
+}
+#endif
+
 void
 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 {
@@ -3261,6 +3902,21 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                }
        }
 
+#if defined(__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 ( 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);
 
@@ -3286,11 +3942,13 @@ 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++;
+                       cfg->stat_code_reallocs++;
                }
 
                if (cfg->debug_info)
@@ -3321,7 +3979,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_STOREI2_MEMBASE_REG:
                        amd64_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 2);
                        break;
+               /* In AMD64 NaCl, pointers are 4 bytes, */
+               /*  so STORE_* != STOREI8_*. Likewise below. */
                case OP_STORE_MEMBASE_REG:
+                       amd64_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, sizeof(gpointer));
+                       break;
                case OP_STOREI8_MEMBASE_REG:
                        amd64_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 8);
                        break;
@@ -3329,15 +3991,32 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        amd64_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 4);
                        break;
                case OP_STORE_MEMBASE_IMM:
+#ifndef __native_client_codegen__
+                       /* In NaCl, this could be a PCONST type, which could */
+                       /* mean a pointer type was copied directly into the  */
+                       /* lower 32-bits of inst_imm, so for InvalidPtr==-1  */
+                       /* the value would be 0x00000000FFFFFFFF which is    */
+                       /* not proper for an imm32 unless you cast it.       */
+                       g_assert (amd64_is_imm32 (ins->inst_imm));
+#endif
+                       amd64_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, (gint32)ins->inst_imm, sizeof(gpointer));
+                       break;
                case OP_STOREI8_MEMBASE_IMM:
                        g_assert (amd64_is_imm32 (ins->inst_imm));
                        amd64_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 8);
                        break;
                case OP_LOAD_MEM:
+#ifdef __mono_ilp32__
+                       /* In ILP32, pointers are 4 bytes, so separate these */
+                       /* cases, use literal 8 below where we really want 8 */
+                       amd64_mov_reg_imm (code, ins->dreg, ins->inst_imm);
+                       amd64_mov_reg_membase (code, ins->dreg, ins->dreg, 0, sizeof(gpointer));
+                       break;
+#endif
                case OP_LOADI8_MEM:
                        // FIXME: Decompose this earlier
                        if (amd64_is_imm32 (ins->inst_imm))
-                               amd64_mov_reg_mem (code, ins->dreg, ins->inst_imm, sizeof (gpointer));
+                               amd64_mov_reg_mem (code, ins->dreg, ins->inst_imm, 8);
                        else {
                                amd64_mov_reg_imm (code, ins->dreg, ins->inst_imm);
                                amd64_mov_reg_membase (code, ins->dreg, ins->dreg, 0, 8);
@@ -3361,13 +4040,20 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        amd64_widen_membase (code, ins->dreg, ins->dreg, 0, FALSE, FALSE);
                        break;
                case OP_LOADU2_MEM:
+                       /* For NaCl, pointers are 4 bytes, so separate these */
+                       /* cases, use literal 8 below where we really want 8 */
                        amd64_mov_reg_imm (code, ins->dreg, ins->inst_imm);
                        amd64_widen_membase (code, ins->dreg, ins->dreg, 0, FALSE, TRUE);
                        break;
                case OP_LOAD_MEMBASE:
+                       g_assert (amd64_is_imm32 (ins->inst_offset));
+                       amd64_mov_reg_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, sizeof(gpointer));
+                       break;
                case OP_LOADI8_MEMBASE:
+                       /* Use literal 8 instead of sizeof pointer or */
+                       /* register, we really want 8 for this opcode */
                        g_assert (amd64_is_imm32 (ins->inst_offset));
-                       amd64_mov_reg_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, sizeof (gpointer));
+                       amd64_mov_reg_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, 8);
                        break;
                case OP_LOADI4_MEMBASE:
                        amd64_movsxd_reg_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
@@ -3598,9 +4284,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_SEQ_POINT: {
                        int i;
 
-                       if (cfg->compile_aot)
-                               NOT_IMPLEMENTED;
-
                        /* 
                         * Read from the single stepping trigger page. This will cause a
                         * SIGSEGV when single stepping is enabled.
@@ -3608,29 +4291,41 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                         * a breakpoint is hit will step to the next IL offset.
                         */
                        if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
-                               if (((guint64)ss_trigger_page >> 32) == 0)
-                                       amd64_mov_reg_mem (code, AMD64_R11, (guint64)ss_trigger_page, 4);
-                               else {
-                                       MonoInst *var = cfg->arch.ss_trigger_page_var;
+                               MonoInst *var = cfg->arch.ss_trigger_page_var;
 
-                                       amd64_mov_reg_membase (code, AMD64_R11, var->inst_basereg, var->inst_offset, 8);
-                                       amd64_alu_membase_imm_size (code, X86_CMP, AMD64_R11, 0, 0, 4);
-                               }
+                               amd64_mov_reg_membase (code, AMD64_R11, var->inst_basereg, var->inst_offset, 8);
+                               amd64_alu_membase_imm_size (code, X86_CMP, AMD64_R11, 0, 0, 4);
                        }
 
                        /* 
                         * This is the address which is saved in seq points, 
-                        * get_ip_for_single_step () / get_ip_for_breakpoint () needs to compute this
-                        * from the address of the instruction causing the fault.
                         */
                        mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
 
-                       /* 
-                        * A placeholder for a possible breakpoint inserted by
-                        * mono_arch_set_breakpoint ().
+                       if (cfg->compile_aot) {
+                               guint32 offset = code - cfg->native_code;
+                               guint32 val;
+                               MonoInst *info_var = cfg->arch.seq_point_info_var;
+
+                               /* Load info var */
+                               amd64_mov_reg_membase (code, AMD64_R11, info_var->inst_basereg, info_var->inst_offset, 8);
+                               val = ((offset) * sizeof (guint8*)) + G_STRUCT_OFFSET (SeqPointInfo, bp_addrs);
+                               /* Load the info->bp_addrs [offset], which is either a valid address or the address of a trigger page */
+                               amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, val, 8);
+                               amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0, 8);
+                       } else {
+                               /* 
+                                * A placeholder for a possible breakpoint inserted by
+                                * mono_arch_set_breakpoint ().
+                                */
+                               for (i = 0; i < breakpoint_size; ++i)
+                                       x86_nop (code);
+                       }
+                       /*
+                        * Add an additional nop so skipping the bp doesn't cause the ip to point
+                        * to another IL offset.
                         */
-                       for (i = 0; i < breakpoint_size; ++i)
-                               x86_nop (code);
+                       x86_nop (code);
                        break;
                }
                case OP_ADDCC:
@@ -4055,14 +4750,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                case OP_AOTCONST:
                        mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
-                       amd64_mov_reg_membase (code, ins->dreg, AMD64_RIP, 0, 8);
+                       amd64_mov_reg_membase (code, ins->dreg, AMD64_RIP, 0, sizeof(gpointer));
                        break;
                case OP_JUMP_TABLE:
                        mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
                        amd64_mov_reg_imm_size (code, ins->dreg, 0, 8);
                        break;
                case OP_MOVE:
-                       amd64_mov_reg_reg (code, ins->dreg, ins->sreg1, sizeof (gpointer));
+                       amd64_mov_reg_reg (code, ins->dreg, ins->sreg1, sizeof(mgreg_t));
                        break;
                case OP_AMD64_SET_XMMREG_R4: {
                        amd64_sse_cvtsd2ss_reg_reg (code, ins->dreg, ins->sreg1);
@@ -4079,7 +4774,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        /* FIXME: no tracing support... */
                        if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
-                               code = mono_arch_instrument_epilog_full (cfg, mono_profiler_method_leave, code, FALSE, FALSE);
+                               code = mono_arch_instrument_epilog_full (cfg, mono_profiler_method_leave, code, FALSE, TRUE);
 
                        g_assert (!cfg->method->save_lmf);
 
@@ -4100,20 +4795,20 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        else {
                                for (i = 0; i < AMD64_NREG; ++i)
                                        if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i)))
-                                               pos -= sizeof (gpointer);
+                                               pos -= sizeof(mgreg_t);
 
                                /* Restore callee-saved registers */
                                for (i = AMD64_NREG - 1; i > 0; --i) {
                                        if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
-                                               amd64_mov_reg_membase (code, i, AMD64_RBP, pos, 8);
-                                               pos += 8;
+                                               amd64_mov_reg_membase (code, i, AMD64_RBP, pos, sizeof(mgreg_t));
+                                               pos += sizeof(mgreg_t);
                                        }
                                }
 
                                /* Copy arguments on the stack to our argument area */
-                               for (i = 0; i < call->stack_usage; i += 8) {
-                                       amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RSP, i, 8);
-                                       amd64_mov_membase_reg (code, AMD64_RBP, 16 + i, AMD64_RAX, 8);
+                               for (i = 0; i < call->stack_usage; i += sizeof(mgreg_t)) {
+                                       amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RSP, i, sizeof(mgreg_t));
+                                       amd64_mov_membase_reg (code, AMD64_RBP, 16 + i, AMD64_RAX, sizeof(mgreg_t));
                                }
                        
                                if (pos)
@@ -4129,6 +4824,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        else
                                amd64_set_reg_template (code, AMD64_R11);
                        amd64_jump_reg (code, AMD64_R11);
+                       ins->flags |= MONO_INST_GC_CALLSITE;
+                       ins->backend.pc_offset = code - cfg->native_code;
                        break;
                }
                case OP_CHECK_THIS:
@@ -4137,7 +4834,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                case OP_ARGLIST: {
                        amd64_lea_membase (code, AMD64_R11, cfg->frame_reg, cfg->sig_cookie);
-                       amd64_mov_membase_reg (code, ins->sreg1, 0, AMD64_R11, 8);
+                       amd64_mov_membase_reg (code, ins->sreg1, 0, AMD64_R11, sizeof(gpointer));
                        break;
                }
                case OP_CALL:
@@ -4173,6 +4870,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method, FALSE);
                        else
                                code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr, FALSE);
+                       ins->flags |= MONO_INST_GC_CALLSITE;
+                       ins->backend.pc_offset = code - cfg->native_code;
                        if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature->call_convention) && !cfg->arch.no_pushes)
                                amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, call->stack_usage);
                        code = emit_move_return_value (cfg, ins, code);
@@ -4221,6 +4920,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        }
 
                        amd64_call_reg (code, ins->sreg1);
+                       ins->flags |= MONO_INST_GC_CALLSITE;
+                       ins->backend.pc_offset = code - cfg->native_code;
                        if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature->call_convention) && !cfg->arch.no_pushes)
                                amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, call->stack_usage);
                        code = emit_move_return_value (cfg, ins, code);
@@ -4234,6 +4935,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        call = (MonoCallInst*)ins;
 
                        amd64_call_membase (code, ins->sreg1, ins->inst_offset);
+                       ins->flags |= MONO_INST_GC_CALLSITE;
+                       ins->backend.pc_offset = code - cfg->native_code;
                        if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature->call_convention) && !cfg->arch.no_pushes)
                                amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, call->stack_usage);
                        code = emit_move_return_value (cfg, ins, code);
@@ -4254,19 +4957,24 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        /* Set argument registers */
                        for (i = 0; i < PARAM_REGS; ++i)
-                               amd64_mov_reg_membase (code, param_regs [i], AMD64_R11, i * sizeof (gpointer), 8);
+                               amd64_mov_reg_membase (code, param_regs [i], AMD64_R11, i * sizeof(mgreg_t), sizeof(mgreg_t));
                        
                        /* Make the call */
                        amd64_call_reg (code, AMD64_R10);
 
+                       ins->flags |= MONO_INST_GC_CALLSITE;
+                       ins->backend.pc_offset = code - cfg->native_code;
+
                        /* Save result */
                        amd64_mov_reg_membase (code, AMD64_R11, var->inst_basereg, var->inst_offset, 8);
                        amd64_mov_membase_reg (code, AMD64_R11, G_STRUCT_OFFSET (DynCallArgs, res), AMD64_RAX, 8);
                        break;
                }
-               case OP_AMD64_SAVE_SP_TO_LMF:
-                       amd64_mov_membase_reg (code, cfg->frame_reg, cfg->arch.lmf_offset + G_STRUCT_OFFSET (MonoLMF, rsp), AMD64_RSP, 8);
+               case OP_AMD64_SAVE_SP_TO_LMF: {
+                       MonoInst *lmf_var = cfg->arch.lmf_var;
+                       amd64_mov_membase_reg (code, cfg->frame_reg, lmf_var->inst_offset + G_STRUCT_OFFSET (MonoLMF, rsp), AMD64_RSP, 8);
                        break;
+               }
                case OP_X86_PUSH:
                        g_assert (!cfg->arch.no_pushes);
                        amd64_push_reg (code, ins->sreg1);
@@ -4354,12 +5062,16 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        amd64_mov_reg_reg (code, AMD64_ARG_REG1, ins->sreg1, 8);
                        code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
                                             (gpointer)"mono_arch_throw_exception", FALSE);
+                       ins->flags |= MONO_INST_GC_CALLSITE;
+                       ins->backend.pc_offset = code - cfg->native_code;
                        break;
                }
                case OP_RETHROW: {
                        amd64_mov_reg_reg (code, AMD64_ARG_REG1, ins->sreg1, 8);
                        code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
                                             (gpointer)"mono_arch_rethrow_exception", FALSE);
+                       ins->flags |= MONO_INST_GC_CALLSITE;
+                       ins->backend.pc_offset = code - cfg->native_code;
                        break;
                }
                case OP_CALL_HANDLER: 
@@ -4372,8 +5084,11 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
                        break;
                case OP_START_HANDLER: {
+                       /* Even though we're saving RSP, use sizeof */
+                       /* gpointer because spvar is of type IntPtr */
+                       /* see: mono_create_spvar_for_region */
                        MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
-                       amd64_mov_membase_reg (code, spvar->inst_basereg, spvar->inst_offset, AMD64_RSP, 8);
+                       amd64_mov_membase_reg (code, spvar->inst_basereg, spvar->inst_offset, AMD64_RSP, sizeof(gpointer));
 
                        if ((MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_FINALLY) ||
                                 MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_FINALLY)) &&
@@ -4384,13 +5099,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                }
                case OP_ENDFINALLY: {
                        MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
-                       amd64_mov_reg_membase (code, AMD64_RSP, spvar->inst_basereg, spvar->inst_offset, 8);
+                       amd64_mov_reg_membase (code, AMD64_RSP, spvar->inst_basereg, spvar->inst_offset, sizeof(gpointer));
                        amd64_ret (code);
                        break;
                }
                case OP_ENDFILTER: {
                        MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
-                       amd64_mov_reg_membase (code, AMD64_RSP, spvar->inst_basereg, spvar->inst_offset, 8);
+                       amd64_mov_reg_membase (code, AMD64_RSP, spvar->inst_basereg, spvar->inst_offset, sizeof(gpointer));
                        /* The local allocator will put the result into RAX */
                        amd64_ret (code);
                        break;
@@ -4878,9 +5593,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                }
                case OP_MEMORY_BARRIER: {
-                       /* http://blogs.sun.com/dave/resource/NHM-Pipeline-Blog-V2.txt */
-                       x86_prefix (code, X86_LOCK_PREFIX);
-                       amd64_alu_membase_imm (code, X86_ADD, AMD64_RSP, 0, 0);
+                       switch (ins->backend.memory_barrier_kind) {
+                       case StoreLoadBarrier:
+                       case FullBarrier:
+                               /* http://blogs.sun.com/dave/resource/NHM-Pipeline-Blog-V2.txt */
+                               x86_prefix (code, X86_LOCK_PREFIX);
+                               amd64_alu_membase_imm (code, X86_ADD, AMD64_RSP, 0, 0);
+                               break;
+                       }
                        break;
                }
                case OP_ATOMIC_ADD_I4:
@@ -5015,6 +5735,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        gpointer card_table = mono_gc_get_card_table (&card_table_shift, &card_table_mask);
                        guint64 nursery_start = (guint64)mono_gc_get_nursery (&nursery_shift, &nursery_size);
+                       guint64 shifted_nursery_start = nursery_start >> nursery_shift;
 
                        /*If either point to the stack we can simply avoid the WB. This happens due to
                         * optimizations revealing a stack store that was not visible when op_cardtable was emited.
@@ -5047,7 +5768,19 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (value != AMD64_RDX)
                                amd64_mov_reg_reg (code, AMD64_RDX, value, 8);
                        amd64_shift_reg_imm (code, X86_SHR, AMD64_RDX, nursery_shift);
-                       amd64_alu_reg_imm (code, X86_CMP, AMD64_RDX, nursery_start >> nursery_shift);
+                       if (shifted_nursery_start >> 31) {
+                               /*
+                                * The value we need to compare against is 64 bits, so we need
+                                * another spare register.  We use RBX, which we save and
+                                * restore.
+                                */
+                               amd64_mov_membase_reg (code, AMD64_RSP, -8, AMD64_RBX, 8);
+                               amd64_mov_reg_imm (code, AMD64_RBX, shifted_nursery_start);
+                               amd64_alu_reg_reg (code, X86_CMP, AMD64_RDX, AMD64_RBX);
+                               amd64_mov_reg_membase (code, AMD64_RBX, AMD64_RSP, -8, 8);
+                       } else {
+                               amd64_alu_reg_imm (code, X86_CMP, AMD64_RDX, shifted_nursery_start);
+                       }
                        br = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
                        amd64_mov_reg_reg (code, AMD64_RDX, ptr, 8);
                        amd64_shift_reg_imm (code, X86_SHR, AMD64_RDX, card_table_shift);
@@ -5134,6 +5867,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
                        amd64_sse_pshufd_reg_reg_imm (code, ins->dreg, ins->sreg1, ins->inst_c0);
                        break;
+               case OP_SHUFPS:
+                       g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
+                       amd64_sse_shufps_reg_reg_imm (code, ins->sreg1, ins->sreg2, ins->inst_c0);
+                       break;
+               case OP_SHUFPD:
+                       g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0x3);
+                       amd64_sse_shufpd_reg_reg_imm (code, ins->sreg1, ins->sreg2, ins->inst_c0);
+                       break;
 
                case OP_ADDPD:
                        amd64_sse_addpd_reg_reg (code, ins->sreg1, ins->sreg2);
@@ -5459,6 +6200,30 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_PSHLQ_REG:
                        amd64_sse_psllq_reg_reg (code, ins->dreg, ins->sreg2);
                        break;  
+               case OP_CVTDQ2PD:
+                       amd64_sse_cvtdq2pd_reg_reg (code, ins->dreg, ins->sreg1);
+                       break;
+               case OP_CVTDQ2PS:
+                       amd64_sse_cvtdq2ps_reg_reg (code, ins->dreg, ins->sreg1);
+                       break;
+               case OP_CVTPD2DQ:
+                       amd64_sse_cvtpd2dq_reg_reg (code, ins->dreg, ins->sreg1);
+                       break;
+               case OP_CVTPD2PS:
+                       amd64_sse_cvtpd2ps_reg_reg (code, ins->dreg, ins->sreg1);
+                       break;
+               case OP_CVTPS2DQ:
+                       amd64_sse_cvtps2dq_reg_reg (code, ins->dreg, ins->sreg1);
+                       break;
+               case OP_CVTPS2PD:
+                       amd64_sse_cvtps2pd_reg_reg (code, ins->dreg, ins->sreg1);
+                       break;
+               case OP_CVTTPD2DQ:
+                       amd64_sse_cvttpd2dq_reg_reg (code, ins->dreg, ins->sreg1);
+                       break;
+               case OP_CVTTPS2DQ:
+                       amd64_sse_cvttps2dq_reg_reg (code, ins->dreg, ins->sreg1);
+                       break;
 
                case OP_ICONV_TO_X:
                        amd64_movd_xreg_reg_size (code, ins->dreg, ins->sreg1, 4);
@@ -5646,15 +6411,32 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
                        break;
                }
+               case OP_NACL_GC_SAFE_POINT: {
+#if defined(__native_client_codegen__)
+                       code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)mono_nacl_gc, TRUE);
+#endif
+                       break;
+               }
+               case OP_GC_LIVENESS_DEF:
+               case OP_GC_LIVENESS_USE:
+               case OP_GC_PARAM_SLOT_LIVENESS_DEF:
+                       ins->backend.pc_offset = code - cfg->native_code;
+                       break;
+               case OP_GC_SPILL_SLOT_LIVENESS_DEF:
+                       ins->backend.pc_offset = code - cfg->native_code;
+                       bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
+                       break;
                default:
                        g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
                        g_assert_not_reached ();
                }
 
                if ((code - cfg->native_code - offset) > max_len) {
+#if !defined(__native_client_codegen__)
                        g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %ld)",
                                   mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
                        g_assert_not_reached ();
+#endif
                }
               
                last_ins = ins;
@@ -5674,7 +6456,7 @@ mono_arch_register_lowlevel_calls (void)
 }
 
 void
-mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
+mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
 {
        MonoJumpInfo *patch_info;
        gboolean compile_aot = !run_cctors;
@@ -5781,13 +6563,30 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        int alloc_size, pos, i, cfa_offset, quad, max_epilog_size;
        guint8 *code;
        CallInfo *cinfo;
-       gint32 lmf_offset = cfg->arch.lmf_offset;
+       MonoInst *lmf_var = cfg->arch.lmf_var;
        gboolean args_clobbered = FALSE;
        gboolean trace = FALSE;
+#ifdef __native_client_codegen__
+       guint alignment_check;
+#endif
 
        cfg->code_size =  MAX (cfg->header->code_size * 4, 10240);
 
+#if defined(__default_codegen__)
        code = cfg->native_code = g_malloc (cfg->code_size);
+#elif defined(__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 = (uintptr_t)cfg->native_code_alloc + kNaClAlignment;
+       cfg->native_code = (uintptr_t)cfg->native_code & ~kNaClAlignmentMask;
+
+       code = cfg->native_code;
+
+       alignment_check = (guint)cfg->native_code & kNaClAlignmentMask;
+       g_assert (alignment_check == 0);
+#endif
 
        if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
                trace = TRUE;
@@ -5819,6 +6618,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        // IP saved at CFA - 8
        mono_emit_unwind_op_offset (cfg, code, AMD64_RIP, -cfa_offset);
        async_exc_point (code);
+       mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
 
        if (!cfg->arch.omit_fp) {
                amd64_push_reg (code, AMD64_RBP);
@@ -5829,8 +6629,10 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 #ifdef HOST_WIN32
                mono_arch_unwindinfo_add_push_nonvol (&cfg->arch.unwindinfo, cfg->native_code, code, AMD64_RBP);
 #endif
+               /* These are handled automatically by the stack marking code */
+               mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
                
-               amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof (gpointer));
+               amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof(mgreg_t));
                mono_emit_unwind_op_def_cfa_reg (cfg, code, AMD64_RBP);
                async_exc_point (code);
 #ifdef HOST_WIN32
@@ -5845,10 +6647,13 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                for (i = 0; i < AMD64_NREG; ++i)
                        if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
                                amd64_push_reg (code, i);
-                               pos += sizeof (gpointer);
+                               pos += 8; /* AMD64 push inst is always 8 bytes, no way to change it */
                                offset += 8;
                                mono_emit_unwind_op_offset (cfg, code, i, - offset);
                                async_exc_point (code);
+
+                               /* These are handled automatically by the stack marking code */
+                               mini_gc_set_slot_type_from_cfa (cfg, - offset, SLOT_NOREF);
                        }
        }
 
@@ -5858,21 +6663,28 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                if (cfg->arch.omit_fp)
                        // FIXME:
                        g_assert_not_reached ();
-               cfg->stack_offset += ALIGN_TO (cfg->param_area, sizeof (gpointer));
+               cfg->stack_offset += ALIGN_TO (cfg->param_area, sizeof(mgreg_t));
        }
 
        if (cfg->arch.omit_fp) {
                /* 
-                * On enter, the stack is misaligned by the the pushing of the return
+                * On enter, the stack is misaligned by the pushing of the return
                 * address. It is either made aligned by the pushing of %rbp, or by
                 * this.
                 */
                alloc_size = ALIGN_TO (cfg->stack_offset, 8);
-               if ((alloc_size % 16) == 0)
+               if ((alloc_size % 16) == 0) {
                        alloc_size += 8;
+                       /* Mark the padding slot as NOREF */
+                       mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset - sizeof (mgreg_t), SLOT_NOREF);
+               }
        } else {
                alloc_size = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
-
+               if (cfg->stack_offset != alloc_size) {
+                       /* Mark the padding slot as NOREF */
+                       mini_gc_set_slot_type_from_fp (cfg, -alloc_size + cfg->param_area, SLOT_NOREF);
+               }
+               cfg->arch.sp_fp_offset = alloc_size;
                alloc_size -= pos;
        }
 
@@ -5889,9 +6701,9 @@ 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++;
+                       cfg->stat_code_reallocs++;
                }
 
                while (remaining_size >= 0x1000) {
@@ -5955,8 +6767,20 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                amd64_mov_reg_reg (code, AMD64_RDI, AMD64_RSP, 8);
 
                amd64_cld (code);
+#if defined(__default_codegen__)
+               amd64_prefix (code, X86_REP_PREFIX);
+               amd64_stosl (code);
+#elif defined(__native_client_codegen__)
+               /* NaCl stos pseudo-instruction */
+               amd64_codegen_pre (code);
+               /* First, clear the upper 32 bits of RDI (mov %edi, %edi)  */
+               amd64_mov_reg_reg (code, AMD64_RDI, AMD64_RDI, 4);
+               /* Add %r15 to %rdi using lea, condition flags unaffected. */
+               amd64_lea_memindex_size (code, AMD64_RDI, AMD64_R15, 0, AMD64_RDI, 0, 8);
                amd64_prefix (code, X86_REP_PREFIX);
                amd64_stosl (code);
+               amd64_codegen_post (code);
+#endif /* __native_client_codegen__ */
 
                amd64_mov_reg_membase (code, AMD64_RDI, AMD64_RSP, -8, 8);
                amd64_mov_reg_membase (code, AMD64_RCX, AMD64_RSP, -16, 8);
@@ -5965,41 +6789,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 
        /* Save LMF */
        if (method->save_lmf) {
-               /* 
-                * The ip field is not set, the exception handling code will obtain it from the stack location pointed to by the sp field.
-                */
-               /* 
-                * sp is saved right before calls but we need to save it here too so
-                * async stack walks would work.
-                */
-               amd64_mov_membase_reg (code, cfg->frame_reg, cfg->arch.lmf_offset + G_STRUCT_OFFSET (MonoLMF, rsp), AMD64_RSP, 8);
-               /* Skip method (only needed for trampoline LMF frames) */
-               /* Save callee saved regs */
-               for (i = 0; i < MONO_MAX_IREGS; ++i) {
-                       int offset;
-
-                       switch (i) {
-                       case AMD64_RBX: offset = G_STRUCT_OFFSET (MonoLMF, rbx); break;
-                       case AMD64_RBP: offset = G_STRUCT_OFFSET (MonoLMF, rbp); break;
-                       case AMD64_R12: offset = G_STRUCT_OFFSET (MonoLMF, r12); break;
-                       case AMD64_R13: offset = G_STRUCT_OFFSET (MonoLMF, r13); break;
-                       case AMD64_R14: offset = G_STRUCT_OFFSET (MonoLMF, r14); break;
-                       case AMD64_R15: offset = G_STRUCT_OFFSET (MonoLMF, r15); break;
-#ifdef HOST_WIN32
-                       case AMD64_RDI: offset = G_STRUCT_OFFSET (MonoLMF, rdi); break;
-                       case AMD64_RSI: offset = G_STRUCT_OFFSET (MonoLMF, rsi); break;
-#endif
-                       default:
-                               offset = -1;
-                               break;
-                       }
-
-                       if (offset != -1) {
-                               amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + offset, i, 8);
-                               if (cfg->arch.omit_fp || (i != AMD64_RBP))
-                                       mono_emit_unwind_op_offset (cfg, code, i, - (cfa_offset - (lmf_offset + offset)));
-                       }
-               }
+               code = emit_setup_lmf (cfg, code, lmf_var->inst_offset, cfa_offset);
        }
 
        /* Save callee saved registers */
@@ -6013,6 +6803,10 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
                                amd64_mov_membase_reg (code, AMD64_RSP, save_area_offset, i, 8);
                                mono_emit_unwind_op_offset (cfg, code, i, - (cfa_offset - save_area_offset));
+
+                               /* These are handled automatically by the stack marking code */
+                               mini_gc_set_slot_type_from_cfa (cfg, - (cfa_offset - save_area_offset), SLOT_NOREF);
+
                                save_area_offset += 8;
                                async_exc_point (code);
                        }
@@ -6023,7 +6817,10 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET &&
                                (cfg->rgctx_var->inst_basereg == AMD64_RBP || cfg->rgctx_var->inst_basereg == AMD64_RSP));
 
-               amd64_mov_membase_reg (code, cfg->rgctx_var->inst_basereg, cfg->rgctx_var->inst_offset, MONO_ARCH_RGCTX_REG, 8);
+               amd64_mov_membase_reg (code, cfg->rgctx_var->inst_basereg, cfg->rgctx_var->inst_offset, MONO_ARCH_RGCTX_REG, sizeof(gpointer));
+
+               mono_add_var_location (cfg, cfg->rgctx_var, TRUE, MONO_ARCH_RGCTX_REG, 0, 0, code - cfg->native_code);
+               mono_add_var_location (cfg, cfg->rgctx_var, FALSE, cfg->rgctx_var->inst_basereg, cfg->rgctx_var->inst_offset, code - cfg->native_code, 0);
        }
 
        /* compute max_length in order to use short forward jumps */
@@ -6038,8 +6835,22 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        /* max alignment for loops */
                        if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
                                max_length += LOOP_ALIGNMENT;
+#ifdef __native_client_codegen__
+                       /* max alignment for native client */
+                       max_length += kNaClAlignment;
+#endif
 
                        MONO_BB_FOR_EACH_INS (bb, ins) {
+#ifdef __native_client_codegen__
+                               {
+                                       int space_in_block = kNaClAlignment -
+                                               ((max_length + 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_length += space_in_block;
+                                       }
+                               }
+#endif  /*__native_client_codegen__*/
                                max_length += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
                        }
 
@@ -6091,13 +6902,13 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                for (quad = 0; quad < 2; quad ++) {
                                        switch (ainfo->pair_storage [quad]) {
                                        case ArgInIReg:
-                                               amd64_mov_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof (gpointer)), ainfo->pair_regs [quad], sizeof (gpointer));
+                                               amd64_mov_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof(mgreg_t)), ainfo->pair_regs [quad], sizeof(mgreg_t));
                                                break;
                                        case ArgInFloatSSEReg:
-                                               amd64_movss_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof (gpointer)), ainfo->pair_regs [quad]);
+                                               amd64_movss_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof(mgreg_t)), ainfo->pair_regs [quad]);
                                                break;
                                        case ArgInDoubleSSEReg:
-                                               amd64_movsd_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof (gpointer)), ainfo->pair_regs [quad]);
+                                               amd64_movsd_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof(mgreg_t)), ainfo->pair_regs [quad]);
                                                break;
                                        case ArgNone:
                                                break;
@@ -6131,6 +6942,16 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                        size = 8;
                                */
                                amd64_mov_membase_reg (code, ins->inst_basereg, ins->inst_offset, ainfo->reg, size);
+
+                               /*
+                                * Save the original location of 'this',
+                                * get_generic_info_from_stack_frame () needs this to properly look up
+                                * the argument value during the handling of async exceptions.
+                                */
+                               if (ins == cfg->args [0]) {
+                                       mono_add_var_location (cfg, ins, TRUE, ainfo->reg, 0, 0, code - cfg->native_code);
+                                       mono_add_var_location (cfg, ins, FALSE, ins->inst_basereg, ins->inst_offset, code - cfg->native_code, 0);
+                               }
                                break;
                        }
                        case ArgInFloatSSEReg:
@@ -6143,13 +6964,13 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                for (quad = 0; quad < 2; quad ++) {
                                        switch (ainfo->pair_storage [quad]) {
                                        case ArgInIReg:
-                                               amd64_mov_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof (gpointer)), ainfo->pair_regs [quad], sizeof (gpointer));
+                                               amd64_mov_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof(mgreg_t)), ainfo->pair_regs [quad], sizeof(mgreg_t));
                                                break;
                                        case ArgInFloatSSEReg:
-                                               amd64_movss_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof (gpointer)), ainfo->pair_regs [quad]);
+                                               amd64_movss_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof(mgreg_t)), ainfo->pair_regs [quad]);
                                                break;
                                        case ArgInDoubleSSEReg:
-                                               amd64_movsd_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof (gpointer)), ainfo->pair_regs [quad]);
+                                               amd64_movsd_membase_reg (code, ins->inst_basereg, ins->inst_offset + (quad * sizeof(mgreg_t)), ainfo->pair_regs [quad]);
                                                break;
                                        case ArgNone:
                                                break;
@@ -6177,114 +6998,16 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        default:
                                g_assert_not_reached ();
                        }
-               }
-       }
 
-       /* Might need to attach the thread to the JIT  or change the domain for the callback */
-       if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
-               guint64 domain = (guint64)cfg->domain;
-
-               args_clobbered = TRUE;
-
-               /* 
-                * The call might clobber argument registers, but they are already
-                * saved to the stack/global regs.
-                */
-               if (appdomain_tls_offset != -1 && lmf_tls_offset != -1) {
-                       guint8 *buf, *no_domain_branch;
-
-                       code = mono_amd64_emit_tls_get (code, AMD64_RAX, appdomain_tls_offset);
-                       if (cfg->compile_aot) {
-                               /* AOT code is only used in the root domain */
-                               amd64_mov_reg_imm (code, AMD64_ARG_REG1, 0);
-                       } else {
-                               if ((domain >> 32) == 0)
-                                       amd64_mov_reg_imm_size (code, AMD64_ARG_REG1, domain, 4);
-                               else
-                                       amd64_mov_reg_imm_size (code, AMD64_ARG_REG1, domain, 8);
+                       if (ins == cfg->args [0]) {
+                               mono_add_var_location (cfg, ins, TRUE, ainfo->reg, 0, 0, code - cfg->native_code);
+                               mono_add_var_location (cfg, ins, TRUE, ins->dreg, 0, code - cfg->native_code, 0);
                        }
-                       amd64_alu_reg_reg (code, X86_CMP, AMD64_RAX, AMD64_ARG_REG1);
-                       no_domain_branch = code;
-                       x86_branch8 (code, X86_CC_NE, 0, 0);
-                       code = mono_amd64_emit_tls_get ( code, AMD64_RAX, lmf_addr_tls_offset);
-                       amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
-                       buf = code;
-                       x86_branch8 (code, X86_CC_NE, 0, 0);
-                       amd64_patch (no_domain_branch, code);
-                       code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
-                                         (gpointer)"mono_jit_thread_attach", TRUE);
-                       amd64_patch (buf, code);
-#ifdef HOST_WIN32
-                       /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
-                       /* FIXME: Add a separate key for LMF to avoid this */
-                       amd64_alu_reg_imm (code, X86_ADD, AMD64_RAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
-#endif
-               } else {
-                       g_assert (!cfg->compile_aot);
-                       if (cfg->compile_aot) {
-                               /* AOT code is only used in the root domain */
-                               amd64_mov_reg_imm (code, AMD64_ARG_REG1, 0);
-                       } else {
-                               if ((domain >> 32) == 0)
-                                       amd64_mov_reg_imm_size (code, AMD64_ARG_REG1, domain, 4);
-                               else
-                                       amd64_mov_reg_imm_size (code, AMD64_ARG_REG1, domain, 8);
-                       }
-                       code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
-                                         (gpointer)"mono_jit_thread_attach", TRUE);
                }
        }
 
        if (method->save_lmf) {
-               if ((lmf_tls_offset != -1) && !optimize_for_xen) {
-                       /*
-                        * Optimized version which uses the mono_lmf TLS variable instead of 
-                        * indirection through the mono_lmf_addr TLS variable.
-                        */
-                       /* %rax = previous_lmf */
-                       x86_prefix (code, X86_FS_PREFIX);
-                       amd64_mov_reg_mem (code, AMD64_RAX, lmf_tls_offset, 8);
-
-                       /* Save previous_lmf */
-                       amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), AMD64_RAX, 8);
-                       /* Set new lmf */
-                       if (lmf_offset == 0) {
-                               x86_prefix (code, X86_FS_PREFIX);
-                               amd64_mov_mem_reg (code, lmf_tls_offset, cfg->frame_reg, 8);
-                       } else {
-                               amd64_lea_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset);
-                               x86_prefix (code, X86_FS_PREFIX);
-                               amd64_mov_mem_reg (code, lmf_tls_offset, AMD64_R11, 8);
-                       }
-               } else {
-                       if (lmf_addr_tls_offset != -1) {
-                               /* Load lmf quicky using the FS register */
-                               code = mono_amd64_emit_tls_get (code, AMD64_RAX, lmf_addr_tls_offset);
-#ifdef HOST_WIN32
-                               /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
-                               /* FIXME: Add a separate key for LMF to avoid this */
-                               amd64_alu_reg_imm (code, X86_ADD, AMD64_RAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
-#endif
-                       }
-                       else {
-                               /* 
-                                * The call might clobber argument registers, but they are already
-                                * saved to the stack/global regs.
-                                */
-                               args_clobbered = TRUE;
-                               code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
-                                                                 (gpointer)"mono_get_lmf_addr", TRUE);         
-                       }
-
-                       /* Save lmf_addr */
-                       amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), AMD64_RAX, 8);
-                       /* Save previous_lmf */
-                       amd64_mov_reg_membase (code, AMD64_R11, AMD64_RAX, 0, 8);
-                       amd64_mov_membase_reg (code, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), AMD64_R11, 8);
-                       /* Set new lmf */
-                       amd64_lea_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset);
-                       amd64_mov_membase_reg (code, AMD64_RAX, 0, AMD64_R11, 8);
-               }
+               code = emit_save_lmf (cfg, code, lmf_var->inst_offset, &args_clobbered);
        }
 
        if (trace) {
@@ -6362,15 +7085,31 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                }
        }
 
-       /* Initialize ss_trigger_page_var */
-       if (cfg->arch.ss_trigger_page_var) {
-               MonoInst *var = cfg->arch.ss_trigger_page_var;
+       if (cfg->gen_seq_points) {
+               MonoInst *info_var = cfg->arch.seq_point_info_var;
 
-               g_assert (!cfg->compile_aot);
-               g_assert (var->opcode == OP_REGOFFSET);
+               /* Initialize seq_point_info_var */
+               if (cfg->compile_aot) {
+                       /* Initialize the variable from a GOT slot */
+                       /* Same as OP_AOTCONST */
+                       mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_SEQ_POINT_INFO, cfg->method);
+                       amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, sizeof(gpointer));
+                       g_assert (info_var->opcode == OP_REGOFFSET);
+                       amd64_mov_membase_reg (code, info_var->inst_basereg, info_var->inst_offset, AMD64_R11, 8);
+               }
+
+               /* Initialize ss_trigger_page_var */
+               ins = cfg->arch.ss_trigger_page_var;
 
-               amd64_mov_reg_imm (code, AMD64_R11, (guint64)ss_trigger_page);
-               amd64_mov_membase_reg (code, var->inst_basereg, var->inst_offset, AMD64_R11, 8);
+               g_assert (ins->opcode == OP_REGOFFSET);
+
+               if (cfg->compile_aot) {
+                       amd64_mov_reg_membase (code, AMD64_R11, info_var->inst_basereg, info_var->inst_offset, 8);
+                       amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, G_STRUCT_OFFSET (SeqPointInfo, ss_trigger_page), 8);
+               } else {
+                       amd64_mov_reg_imm (code, AMD64_R11, (guint64)ss_trigger_page);
+               }
+               amd64_mov_membase_reg (code, ins->inst_basereg, ins->inst_offset, AMD64_R11, 8);
        }
 
        cfg->code_len = code - cfg->native_code;
@@ -6388,14 +7127,14 @@ mono_arch_emit_epilog (MonoCompile *cfg)
        guint8 *code;
        int max_epilog_size;
        CallInfo *cinfo;
-       gint32 lmf_offset = cfg->arch.lmf_offset;
+       gint32 lmf_offset = cfg->arch.lmf_var ? ((MonoInst*)cfg->arch.lmf_var)->inst_offset : -1;
        
        max_epilog_size = get_max_epilog_size (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);
-               mono_jit_stats.code_reallocs++;
+               cfg->native_code = mono_realloc_native_code (cfg);
+               cfg->stat_code_reallocs++;
        }
 
        code = cfg->native_code + cfg->code_len;
@@ -6410,35 +7149,22 @@ mono_arch_emit_epilog (MonoCompile *cfg)
                /* check if we need to restore protection of the stack after a stack overflow */
                if (mono_get_jit_tls_offset () != -1) {
                        guint8 *patch;
-                       code = mono_amd64_emit_tls_get (code, X86_ECX, mono_get_jit_tls_offset ());
+                       code = mono_amd64_emit_tls_get (code, AMD64_RCX, mono_get_jit_tls_offset ());
                        /* we load the value in a separate instruction: this mechanism may be
                         * used later as a safer way to do thread interruption
                         */
-                       amd64_mov_reg_membase (code, X86_ECX, X86_ECX, G_STRUCT_OFFSET (MonoJitTlsData, restore_stack_prot), 8);
+                       amd64_mov_reg_membase (code, AMD64_RCX, AMD64_RCX, G_STRUCT_OFFSET (MonoJitTlsData, restore_stack_prot), 8);
                        x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
                        patch = code;
-                       x86_branch8 (code, X86_CC_Z, 0, FALSE);
+                       x86_branch8 (code, X86_CC_Z, 0, FALSE);
                        /* note that the call trampoline will preserve eax/edx */
                        x86_call_reg (code, X86_ECX);
                        x86_patch (patch, code);
                } else {
                        /* FIXME: maybe save the jit tls in the prolog */
                }
-               if ((lmf_tls_offset != -1) && !optimize_for_xen) {
-                       /*
-                        * Optimized version which uses the mono_lmf TLS variable instead of indirection
-                        * through the mono_lmf_addr TLS variable.
-                        */
-                       /* reg = previous_lmf */
-                       amd64_mov_reg_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 8);
-                       x86_prefix (code, X86_FS_PREFIX);
-                       amd64_mov_mem_reg (code, lmf_tls_offset, AMD64_R11, 8);
-               } else {
-                       /* Restore previous lmf */
-                       amd64_mov_reg_membase (code, AMD64_RCX, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 8);
-                       amd64_mov_reg_membase (code, AMD64_R11, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 8);
-                       amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RCX, 8);
-               }
+
+               code = emit_restore_lmf (cfg, code, lmf_offset);
 
                /* Restore caller saved regs */
                if (cfg->used_int_regs & (1 << AMD64_RBP)) {
@@ -6457,7 +7183,11 @@ mono_arch_emit_epilog (MonoCompile *cfg)
                        amd64_mov_reg_membase (code, AMD64_R14, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, r14), 8);
                }
                if (cfg->used_int_regs & (1 << AMD64_R15)) {
+#if defined(__default_codegen__)
                        amd64_mov_reg_membase (code, AMD64_R15, cfg->frame_reg, lmf_offset + G_STRUCT_OFFSET (MonoLMF, r15), 8);
+#elif defined(__native_client_codegen__)
+                       g_assert_not_reached();
+#endif
                }
 #ifdef HOST_WIN32
                if (cfg->used_int_regs & (1 << AMD64_RDI)) {
@@ -6481,10 +7211,10 @@ mono_arch_emit_epilog (MonoCompile *cfg)
                else {
                        for (i = 0; i < AMD64_NREG; ++i)
                                if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i)))
-                                       pos -= sizeof (gpointer);
+                                       pos -= sizeof(mgreg_t);
 
                        if (pos) {
-                               if (pos == - sizeof (gpointer)) {
+                               if (pos == - sizeof(mgreg_t)) {
                                        /* Only one register, so avoid lea */
                                        for (i = AMD64_NREG - 1; i > 0; --i)
                                                if (AMD64_IS_CALLEE_SAVED_REG (i) && (cfg->used_int_regs & (1 << i))) {
@@ -6513,13 +7243,13 @@ mono_arch_emit_epilog (MonoCompile *cfg)
                for (quad = 0; quad < 2; quad ++) {
                        switch (ainfo->pair_storage [quad]) {
                        case ArgInIReg:
-                               amd64_mov_reg_membase (code, ainfo->pair_regs [quad], inst->inst_basereg, inst->inst_offset + (quad * sizeof (gpointer)), sizeof (gpointer));
+                               amd64_mov_reg_membase (code, ainfo->pair_regs [quad], inst->inst_basereg, inst->inst_offset + (quad * sizeof(mgreg_t)), sizeof(mgreg_t));
                                break;
                        case ArgInFloatSSEReg:
-                               amd64_movss_reg_membase (code, ainfo->pair_regs [quad], inst->inst_basereg, inst->inst_offset + (quad * sizeof (gpointer)));
+                               amd64_movss_reg_membase (code, ainfo->pair_regs [quad], inst->inst_basereg, inst->inst_offset + (quad * sizeof(mgreg_t)));
                                break;
                        case ArgInDoubleSSEReg:
-                               amd64_movsd_reg_membase (code, ainfo->pair_regs [quad], inst->inst_basereg, inst->inst_offset + (quad * sizeof (gpointer)));
+                               amd64_movsd_reg_membase (code, ainfo->pair_regs [quad], inst->inst_basereg, inst->inst_offset + (quad * sizeof(mgreg_t)));
                                break;
                        case ArgNone:
                                break;
@@ -6565,10 +7295,17 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                        code_size += 8 + 7; /*sizeof (void*) + alignment */
        }
 
+#ifdef __native_client_codegen__
+       /* Give us extra room on Native Client.  This could be   */
+       /* more carefully calculated, but bundle alignment makes */
+       /* it much trickier, so *2 like other places is good.    */
+       code_size *= 2;
+#endif
+
        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);
-               mono_jit_stats.code_reallocs++;
+               cfg->native_code = mono_realloc_native_code (cfg);
+               cfg->stat_code_reallocs++;
        }
 
        code = cfg->native_code + cfg->code_len;
@@ -6628,35 +7365,81 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                        /* do nothing */
                        break;
                }
+               g_assert(code < cfg->native_code + cfg->code_size);
        }
 
        /* Handle relocations with RIP relative addressing */
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                gboolean remove = FALSE;
+               guint8 *orig_code = code;
 
                switch (patch_info->type) {
                case MONO_PATCH_INFO_R8:
                case MONO_PATCH_INFO_R4: {
-                       guint8 *pos;
+                       guint8 *pos, *patch_pos;
+                       guint32 target_pos;
 
                        /* The SSE opcodes require a 16 byte alignment */
+#if defined(__default_codegen__)
                        code = (guint8*)ALIGN_TO (code, 16);
+#elif defined(__native_client_codegen__)
+                       {
+                               /* Pad this out with HLT instructions  */
+                               /* or we can get garbage bytes emitted */
+                               /* which will fail validation          */
+                               guint8 *aligned_code;
+                               /* extra align to make room for  */
+                               /* mov/push below                      */
+                               int extra_align = patch_info->type == MONO_PATCH_INFO_R8 ? 2 : 1;
+                               aligned_code = (guint8*)ALIGN_TO (code + extra_align, 16);
+                               /* The technique of hiding data in an  */
+                               /* instruction has a problem here: we  */
+                               /* need the data aligned to a 16-byte  */
+                               /* boundary but the instruction cannot */
+                               /* cross the bundle boundary. so only  */
+                               /* odd multiples of 16 can be used     */
+                               if ((intptr_t)aligned_code % kNaClAlignment == 0) {
+                                       aligned_code += 16;
+                               }
+                               while (code < aligned_code) {
+                                       *(code++) = 0xf4; /* hlt */
+                               }
+                       }       
+#endif
 
                        pos = cfg->native_code + patch_info->ip.i;
-
-                       if (IS_REX (pos [1]))
-                               *(guint32*)(pos + 5) = (guint8*)code - pos - 9;
-                       else
-                               *(guint32*)(pos + 4) = (guint8*)code - pos - 8;
+                       if (IS_REX (pos [1])) {
+                               patch_pos = pos + 5;
+                               target_pos = code - pos - 9;
+                       }
+                       else {
+                               patch_pos = pos + 4;
+                               target_pos = code - pos - 8;
+                       }
 
                        if (patch_info->type == MONO_PATCH_INFO_R8) {
+#ifdef __native_client_codegen__
+                               /* Hide 64-bit data in a         */
+                               /* "mov imm64, r11" instruction. */
+                               /* write it before the start of  */
+                               /* the data*/
+                               *(code-2) = 0x49; /* prefix      */
+                               *(code-1) = 0xbb; /* mov X, %r11 */
+#endif
                                *(double*)code = *(double*)patch_info->data.target;
                                code += sizeof (double);
                        } else {
+#ifdef __native_client_codegen__
+                               /* Hide 32-bit data in a        */
+                               /* "push imm32" instruction.    */
+                               *(code-1) = 0x68; /* push */
+#endif
                                *(float*)code = *(float*)patch_info->data.target;
                                code += sizeof (float);
                        }
 
+                       *(guint32*)(patch_pos) = target_pos;
+
                        remove = TRUE;
                        break;
                }
@@ -6668,6 +7451,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
 
                        /*loading is faster against aligned addresses.*/
                        code = (guint8*)ALIGN_TO (code, 8);
+                       memset (orig_code, 0, code - orig_code);
 
                        pos = cfg->native_code + patch_info->ip.i;
 
@@ -6698,6 +7482,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                                tmp->next = patch_info->next;
                        }
                }
+               g_assert (code < cfg->native_code + cfg->code_size);
        }
 
        cfg->code_len = code - cfg->native_code;
@@ -6723,7 +7508,7 @@ mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean ena
                /* Allocate a new area on the stack and save arguments there */
                sig = mono_method_signature (cfg->method);
 
-               cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
+               cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
 
                n = sig->param_count + sig->hasthis;
 
@@ -6769,6 +7554,7 @@ mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolea
        int save_mode = SAVE_NONE;
        MonoMethod *method = cfg->method;
        MonoType *ret_type = mini_type_get_underlying_type (NULL, mono_method_signature (method)->ret);
+       int i;
        
        switch (ret_type->type) {
        case MONO_TYPE_VOID:
@@ -6837,8 +7623,8 @@ mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolea
                amd64_mov_reg_imm (code, AMD64_RAX, 0);
 
        if (preserve_argument_registers) {
-               amd64_push_reg (code, MONO_AMD64_ARG_REG1);
-               amd64_push_reg (code, MONO_AMD64_ARG_REG2);
+               for (i = 0; i < PARAM_REGS; ++i)
+                       amd64_push_reg (code, param_regs [i]);
        }
 
        mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_METHODCONST, method);
@@ -6846,8 +7632,8 @@ mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolea
        code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)func, TRUE);
 
        if (preserve_argument_registers) {
-               amd64_pop_reg (code, MONO_AMD64_ARG_REG2);
-               amd64_pop_reg (code, MONO_AMD64_ARG_REG1);
+               for (i = PARAM_REGS - 1; i >= 0; --i)
+                       amd64_pop_reg (code, param_regs [i]);
        }
 
        /* Restore result */
@@ -7015,6 +7801,46 @@ mono_breakpoint_clean_code (guint8 *method_start, guint8 *code, int offset, guin
        return can_write;
 }
 
+#if defined(__native_client_codegen__)
+/* For membase calls, we want the base register. for Native Client,  */
+/* all indirect calls have the following sequence with the given sizes: */
+/* mov %eXX,%eXX                               [2-3]   */
+/* mov disp(%r15,%rXX,scale),%r11d             [4-8]   */
+/* and $0xffffffffffffffe0,%r11d               [4]     */
+/* add %r15,%r11                               [3]     */
+/* callq *%r11                                 [3]     */
+
+
+/* Determine if code points to a NaCl call-through-register sequence, */
+/* (i.e., the last 3 instructions listed above) */
+int
+is_nacl_call_reg_sequence(guint8* code)
+{
+       const char *sequence = "\x41\x83\xe3\xe0" /* and */
+                              "\x4d\x03\xdf"     /* add */
+                              "\x41\xff\xd3";   /* call */
+       return memcmp(code, sequence, 10) == 0;
+}
+
+/* Determine if code points to the first opcode of the mov membase component */
+/* of an indirect call sequence (i.e. the first 2 instructions listed above) */
+/* (there could be a REX prefix before the opcode but it is ignored) */
+static int
+is_nacl_indirect_call_membase_sequence(guint8* code)
+{
+              /* Check for mov opcode, reg-reg addressing mode (mod = 3), */
+       return code[0] == 0x8b && amd64_modrm_mod(code[1]) == 3 &&
+              /* and that src reg = dest reg */
+              amd64_modrm_reg(code[1]) == amd64_modrm_rm(code[1]) &&
+              /* Check that next inst is mov, uses SIB byte (rm = 4), */
+              IS_REX(code[2]) &&
+              code[3] == 0x8b && amd64_modrm_rm(code[4]) == 4 &&
+              /* and has dst of r11 and base of r15 */
+              (amd64_modrm_reg(code[4]) + amd64_rex_r(code[2])) == AMD64_R11 &&
+              (amd64_sib_base(code[5]) + amd64_rex_b(code[2])) == AMD64_R15;
+}
+#endif /* __native_client_codegen__ */
+
 int
 mono_arch_get_this_arg_reg (guint8 *code)
 {
@@ -7068,6 +7894,8 @@ get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *cod
                g_assert ((code - start) < 64);
        }
 
+       nacl_global_codeman_validate(&start, 64, &code);
+
        mono_debug_add_delegate_trampoline (start, code - start);
 
        if (code_len)
@@ -7167,42 +7995,33 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
 
        return start;
 }
-
-/*
- * Support for fast access to the thread-local lmf structure using the GS
- * segment register on NPTL + kernel 2.6.x.
- */
-
-static gboolean tls_offset_inited = FALSE;
-
 void
-mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
+mono_arch_finish_init (void)
 {
-       if (!tls_offset_inited) {
 #ifdef HOST_WIN32
-               /* 
-                * We need to init this multiple times, since when we are first called, the key might not
-                * be initialized yet.
-                */
-               appdomain_tls_offset = mono_domain_get_tls_key ();
-               lmf_tls_offset = mono_get_jit_tls_key ();
-               lmf_addr_tls_offset = mono_get_jit_tls_key ();
-
-               /* Only 64 tls entries can be accessed using inline code */
-               if (appdomain_tls_offset >= 64)
-                       appdomain_tls_offset = -1;
-               if (lmf_tls_offset >= 64)
-                       lmf_tls_offset = -1;
+       /* 
+        * We need to init this multiple times, since when we are first called, the key might not
+        * be initialized yet.
+        */
+       appdomain_tls_offset = mono_domain_get_tls_key ();
+       lmf_tls_offset = mono_get_jit_tls_key ();
+       lmf_addr_tls_offset = mono_get_jit_tls_key ();
+
+       /* Only 64 tls entries can be accessed using inline code */
+       if (appdomain_tls_offset >= 64)
+               appdomain_tls_offset = -1;
+       if (lmf_tls_offset >= 64)
+               lmf_tls_offset = -1;
+       if (lmf_addr_tls_offset >= 64)
+               lmf_addr_tls_offset = -1;
 #else
-               tls_offset_inited = TRUE;
 #ifdef MONO_XEN_OPT
-               optimize_for_xen = access ("/proc/xen", F_OK) == 0;
+       optimize_for_xen = access ("/proc/xen", F_OK) == 0;
 #endif
-               appdomain_tls_offset = mono_domain_get_tls_offset ();
-               lmf_tls_offset = mono_get_lmf_tls_offset ();
-               lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
+       appdomain_tls_offset = mono_domain_get_tls_offset ();
+       lmf_tls_offset = mono_get_lmf_tls_offset ();
+       lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
 #endif
-       }               
 }
 
 void
@@ -7212,6 +8031,7 @@ mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
 
 #ifdef MONO_ARCH_HAVE_IMT
 
+#if defined(__default_codegen__)
 #define CMP_SIZE (6 + 1)
 #define CMP_REG_REG_SIZE (4 + 1)
 #define BR_SMALL_SIZE 2
@@ -7219,6 +8039,20 @@ mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
 #define MOV_REG_IMM_SIZE 10
 #define MOV_REG_IMM_32BIT_SIZE 6
 #define JUMP_REG_SIZE (2 + 1)
+#elif defined(__native_client_codegen__)
+/* NaCl N-byte instructions can be padded up to N-1 bytes */
+#define CMP_SIZE ((6 + 1) * 2 - 1)
+#define CMP_REG_REG_SIZE ((4 + 1) * 2 - 1)
+#define BR_SMALL_SIZE (2 * 2 - 1)
+#define BR_LARGE_SIZE (6 * 2 - 1)
+#define MOV_REG_IMM_SIZE (10 * 2 - 1)
+#define MOV_REG_IMM_32BIT_SIZE (6 * 2 - 1)
+/* Jump reg for NaCl adds a mask (+4) and add (+3) */
+#define JUMP_REG_SIZE ((2 + 1 + 4 + 3) * 2 - 1)
+/* Jump membase's size is large and unpredictable    */
+/* in native client, just pad it out a whole bundle. */
+#define JUMP_MEMBASE_SIZE (kNaClAlignment)
+#endif
 
 static int
 imt_branch_distance (MonoIMTCheckItem **imt_entries, int start, int target)
@@ -7258,6 +8092,9 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                                                item->chunk_size += MOV_REG_IMM_32BIT_SIZE;
                                        else
                                                item->chunk_size += MOV_REG_IMM_SIZE;
+#ifdef __native_client_codegen__
+                                       item->chunk_size += JUMP_MEMBASE_SIZE;
+#endif
                                }
                                item->chunk_size += BR_SMALL_SIZE + JUMP_REG_SIZE;
                        } else {
@@ -7273,6 +8110,9 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                                        /* with assert below:
                                         * item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
                                         */
+#ifdef __native_client_codegen__
+                                       item->chunk_size += JUMP_MEMBASE_SIZE;
+#endif
                                }
                        }
                } else {
@@ -7285,10 +8125,16 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                }
                size += item->chunk_size;
        }
+#if defined(__native_client__) && defined(__native_client_codegen__)
+       /* In Native Client, we don't re-use thunks, allocate from the */
+       /* normal code manager paths. */
+       code = mono_domain_code_reserve (domain, size);
+#else
        if (fail_tramp)
                code = mono_method_alloc_generic_virtual_thunk (domain, size);
        else
                code = mono_domain_code_reserve (domain, size);
+#endif
        start = code;
        for (i = 0; i < count; ++i) {
                MonoIMTCheckItem *item = imt_entries [i];
@@ -7301,24 +8147,24 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                                        if (amd64_is_imm32 (item->key))
                                                amd64_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)(gssize)item->key);
                                        else {
-                                               amd64_mov_reg_imm (code, AMD64_R11, item->key);
-                                               amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, AMD64_R11);
+                                               amd64_mov_reg_imm (code, MONO_ARCH_IMT_SCRATCH_REG, item->key);
+                                               amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, MONO_ARCH_IMT_SCRATCH_REG);
                                        }
                                }
                                item->jmp_code = code;
                                amd64_branch8 (code, X86_CC_NE, 0, FALSE);
                                if (item->has_target_code) {
-                                       amd64_mov_reg_imm (code, AMD64_R11, item->value.target_code);
-                                       amd64_jump_reg (code, AMD64_R11);
+                                       amd64_mov_reg_imm (code, MONO_ARCH_IMT_SCRATCH_REG, item->value.target_code);
+                                       amd64_jump_reg (code, MONO_ARCH_IMT_SCRATCH_REG);
                                } else {
-                                       amd64_mov_reg_imm (code, AMD64_R11, & (vtable->vtable [item->value.vtable_slot]));
-                                       amd64_jump_membase (code, AMD64_R11, 0);
+                                       amd64_mov_reg_imm (code, MONO_ARCH_IMT_SCRATCH_REG, & (vtable->vtable [item->value.vtable_slot]));
+                                       amd64_jump_membase (code, MONO_ARCH_IMT_SCRATCH_REG, 0);
                                }
 
                                if (fail_case) {
                                        amd64_patch (item->jmp_code, code);
-                                       amd64_mov_reg_imm (code, AMD64_R11, fail_tramp);
-                                       amd64_jump_reg (code, AMD64_R11);
+                                       amd64_mov_reg_imm (code, MONO_ARCH_IMT_SCRATCH_REG, fail_tramp);
+                                       amd64_jump_reg (code, MONO_ARCH_IMT_SCRATCH_REG);
                                        item->jmp_code = NULL;
                                }
                        } else {
@@ -7327,27 +8173,33 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                                if (amd64_is_imm32 (item->key))
                                        amd64_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)(gssize)item->key);
                                else {
-                                       amd64_mov_reg_imm (code, AMD64_R11, item->key);
-                                       amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, AMD64_R11);
+                                       amd64_mov_reg_imm (code, MONO_ARCH_IMT_SCRATCH_REG, item->key);
+                                       amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, MONO_ARCH_IMT_SCRATCH_REG);
                                }
                                item->jmp_code = code;
                                amd64_branch8 (code, X86_CC_NE, 0, FALSE);
-                               amd64_mov_reg_imm (code, AMD64_R11, & (vtable->vtable [item->value.vtable_slot]));
-                               amd64_jump_membase (code, AMD64_R11, 0);
+                               /* See the comment below about R10 */
+                               amd64_mov_reg_imm (code, MONO_ARCH_IMT_SCRATCH_REG, & (vtable->vtable [item->value.vtable_slot]));
+                               amd64_jump_membase (code, MONO_ARCH_IMT_SCRATCH_REG, 0);
                                amd64_patch (item->jmp_code, code);
                                amd64_breakpoint (code);
                                item->jmp_code = NULL;
 #else
-                               amd64_mov_reg_imm (code, AMD64_R11, & (vtable->vtable [item->value.vtable_slot]));
-                               amd64_jump_membase (code, AMD64_R11, 0);
+                               /* We're using R10 (MONO_ARCH_IMT_SCRATCH_REG) here because R11 (MONO_ARCH_IMT_REG)
+                                  needs to be preserved.  R10 needs
+                                  to be preserved for calls which
+                                  require a runtime generic context,
+                                  but interface calls don't. */
+                               amd64_mov_reg_imm (code, MONO_ARCH_IMT_SCRATCH_REG, & (vtable->vtable [item->value.vtable_slot]));
+                               amd64_jump_membase (code, MONO_ARCH_IMT_SCRATCH_REG, 0);
 #endif
                        }
                } else {
                        if (amd64_is_imm32 (item->key))
                                amd64_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)(gssize)item->key);
                        else {
-                               amd64_mov_reg_imm (code, AMD64_R11, item->key);
-                               amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, AMD64_R11);
+                               amd64_mov_reg_imm (code, MONO_ARCH_IMT_SCRATCH_REG, item->key);
+                               amd64_alu_reg_reg (code, X86_CMP, MONO_ARCH_IMT_REG, MONO_ARCH_IMT_SCRATCH_REG);
                        }
                        item->jmp_code = code;
                        if (x86_is_imm8 (imt_branch_distance (imt_entries, i, item->check_target_idx)))
@@ -7371,6 +8223,8 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                mono_stats.imt_thunks_size += code - start;
        g_assert (code - start <= size);
 
+       nacl_domain_code_validate(domain, &start, size, &code);
+
        return start;
 }
 
@@ -7491,17 +8345,17 @@ MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
        return ins;
 }
 
-#define _CTX_REG(ctx,fld,i) ((gpointer)((&ctx->fld)[i]))
+#define _CTX_REG(ctx,fld,i) ((&ctx->fld)[i])
 
-gpointer
+mgreg_t
 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
 {
        switch (reg) {
-       case AMD64_RCX: return (gpointer)ctx->rcx;
-       case AMD64_RDX: return (gpointer)ctx->rdx;
-       case AMD64_RBX: return (gpointer)ctx->rbx;
-       case AMD64_RBP: return (gpointer)ctx->rbp;
-       case AMD64_RSP: return (gpointer)ctx->rsp;
+       case AMD64_RCX: return ctx->rcx;
+       case AMD64_RDX: return ctx->rdx;
+       case AMD64_RBX: return ctx->rbx;
+       case AMD64_RBP: return ctx->rbp;
+       case AMD64_RSP: return ctx->rsp;
        default:
                if (reg < 8)
                        return _CTX_REG (ctx, rax, reg);
@@ -7512,6 +8366,35 @@ mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
        }
 }
 
+void
+mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val)
+{
+       switch (reg) {
+       case AMD64_RCX:
+               ctx->rcx = val;
+               break;
+       case AMD64_RDX: 
+               ctx->rdx = val;
+               break;
+       case AMD64_RBX:
+               ctx->rbx = val;
+               break;
+       case AMD64_RBP:
+               ctx->rbp = val;
+               break;
+       case AMD64_RSP:
+               ctx->rsp = val;
+               break;
+       default:
+               if (reg < 8)
+                       _CTX_REG (ctx, rax, reg) = val;
+               else if (reg >= 12)
+                       _CTX_REG (ctx, r12, reg - 12) = val;
+               else
+                       g_assert_not_reached ();
+       }
+}
+
 /*MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD*/
 gpointer
 mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value)
@@ -7590,14 +8473,7 @@ mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, in
 GSList *
 mono_arch_get_trampolines (gboolean aot)
 {
-       MonoTrampInfo *info;
-       GSList *tramps = NULL;
-
-       mono_arch_get_throw_pending_exception (&info, aot);
-
-       tramps = g_slist_append (tramps, info);
-
-       return tramps;
+       return mono_amd64_get_exception_trampolines (aot);
 }
 
 /* Soft Debug support */
@@ -7615,20 +8491,28 @@ mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
        guint8 *code = ip;
        guint8 *orig_code = code;
 
-       /* 
-        * In production, we will use int3 (has to fix the size in the md 
-        * file). But that could confuse gdb, so during development, we emit a SIGSEGV
-        * instead.
-        */
-       g_assert (code [0] == 0x90);
-       if (breakpoint_size == 8) {
-               amd64_mov_reg_mem (code, AMD64_R11, (guint64)bp_trigger_page, 4);
+       if (ji->from_aot) {
+               guint32 native_offset = ip - (guint8*)ji->code_start;
+               SeqPointInfo *info = mono_arch_get_seq_point_info (mono_domain_get (), ji->code_start);
+
+               g_assert (info->bp_addrs [native_offset] == 0);
+               info->bp_addrs [native_offset] = bp_trigger_page;
        } else {
-               amd64_mov_reg_imm_size (code, AMD64_R11, (guint64)bp_trigger_page, 8);
-               amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0, 4);
-       }
+               /* 
+                * In production, we will use int3 (has to fix the size in the md 
+                * file). But that could confuse gdb, so during development, we emit a SIGSEGV
+                * instead.
+                */
+               g_assert (code [0] == 0x90);
+               if (breakpoint_size == 8) {
+                       amd64_mov_reg_mem (code, AMD64_R11, (guint64)bp_trigger_page, 4);
+               } else {
+                       amd64_mov_reg_imm_size (code, AMD64_R11, (guint64)bp_trigger_page, 8);
+                       amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0, 4);
+               }
 
-       g_assert (code - orig_code == breakpoint_size);
+               g_assert (code - orig_code == breakpoint_size);
+       }
 }
 
 /*
@@ -7642,8 +8526,16 @@ mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
        guint8 *code = ip;
        int i;
 
-       for (i = 0; i < breakpoint_size; ++i)
-               x86_nop (code);
+       if (ji->from_aot) {
+               guint32 native_offset = ip - (guint8*)ji->code_start;
+               SeqPointInfo *info = mono_arch_get_seq_point_info (mono_domain_get (), ji->code_start);
+
+               g_assert (info->bp_addrs [native_offset] == 0);
+               info->bp_addrs [native_offset] = info;
+       } else {
+               for (i = 0; i < breakpoint_size; ++i)
+                       x86_nop (code);
+       }
 }
 
 gboolean
@@ -7662,22 +8554,6 @@ mono_arch_is_breakpoint_event (void *info, void *sigctx)
 #endif
 }
 
-/*
- * mono_arch_get_ip_for_breakpoint:
- *
- *   Convert the ip in CTX to the address where a breakpoint was placed.
- */
-guint8*
-mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx)
-{
-       guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
-
-       /* ip points to the instruction causing the fault */
-       ip -= (breakpoint_size - breakpoint_fault_size);
-
-       return ip;
-}
-
 /*
  * mono_arch_skip_breakpoint:
  *
@@ -7685,9 +8561,14 @@ mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx)
  * we resume, the instruction is not executed again.
  */
 void
-mono_arch_skip_breakpoint (MonoContext *ctx)
+mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
 {
-       MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + breakpoint_fault_size);
+       if (ji->from_aot) {
+               /* amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0, 8) */
+               MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 3);
+       } else {
+               MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + breakpoint_fault_size);
+       }
 }
        
 /*
@@ -7734,21 +8615,6 @@ mono_arch_is_single_step_event (void *info, void *sigctx)
 #endif
 }
 
-/*
- * mono_arch_get_ip_for_single_step:
- *
- *   Convert the ip in CTX to the address stored in seq_points.
- */
-guint8*
-mono_arch_get_ip_for_single_step (MonoJitInfo *ji, MonoContext *ctx)
-{
-       guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
-
-       ip += single_step_fault_size;
-
-       return ip;
-}
-
 /*
  * mono_arch_skip_single_step:
  *
@@ -7770,8 +8636,37 @@ mono_arch_skip_single_step (MonoContext *ctx)
 gpointer
 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
 {
-       NOT_IMPLEMENTED;
-       return NULL;
+       SeqPointInfo *info;
+       MonoJitInfo *ji;
+       int i;
+
+       // FIXME: Add a free function
+
+       mono_domain_lock (domain);
+       info = g_hash_table_lookup (domain_jit_info (domain)->arch_seq_points,
+                                                               code);
+       mono_domain_unlock (domain);
+
+       if (!info) {
+               ji = mono_jit_info_table_find (domain, (char*)code);
+               g_assert (ji);
+
+               // FIXME: Optimize the size
+               info = g_malloc0 (sizeof (SeqPointInfo) + (ji->code_size * sizeof (gpointer)));
+
+               info->ss_trigger_page = ss_trigger_page;
+               info->bp_trigger_page = bp_trigger_page;
+               /* Initialize to a valid address */
+               for (i = 0; i < ji->code_size; ++i)
+                       info->bp_addrs [i] = info;
+
+               mono_domain_lock (domain);
+               g_hash_table_insert (domain_jit_info (domain)->arch_seq_points,
+                                                        code, info);
+               mono_domain_unlock (domain);
+       }
+
+       return info;
 }
 
 #endif