Merge pull request #4444 from lateralusX/jlorenss/windows-unwind-info
authorJohan Lorensson <lateralusx.github@gmail.com>
Fri, 10 Mar 2017 10:16:23 +0000 (11:16 +0100)
committerGitHub <noreply@github.com>
Fri, 10 Mar 2017 10:16:23 +0000 (11:16 +0100)
Improve unwind support on Windows x64.

1  2 
mono/mini/Makefile.am.in
mono/mini/aot-compiler.c
mono/mini/mini-runtime.c
mono/mini/tramp-amd64-gsharedvt.c
mono/mini/tramp-amd64.c
mono/mini/unwind.c

diff --combined mono/mini/Makefile.am.in
index e4a126a7e29cda36597c0944289f8fea5efd5d10,3c7822f0fe018e837da805fe5ae40a27b7158e4c..4592dec23c164804b8b72003e49d64372c4aa311
@@@ -37,22 -37,13 +37,22 @@@ sgen_static_libs = 
        $(monodir)/mono/utils/libmonoutils.la \
        $(GLIB_LIBS) $(LIBICONV)
  
 +if FULL_AOT_TESTS
 +# if the tests are going to run with framework assemblies compiled with
 +# -d:MOBILE, tell the runtime to remap framework assemblies using the mobile
 +# runtime info
 +MOBILE_RUNTIME_ARG=--runtime=mobile
 +else
 +MOBILE_RUNTIME_ARG=
 +endif
 +
  CLASS=$(mcs_topdir)/class/lib/$(DEFAULT_PROFILE)
  
  RUNTIME_EXECUTABLE = $(if $(BOEHM),$(top_builddir)/mono/mini/mono-boehm,$(top_builddir)/runtime/mono-wrapper)
  
 -MINI_RUNTIME = MONO_PATH=$(CLASS) $(RUNTIME_EXECUTABLE)
 +MINI_RUNTIME = MONO_PATH=$(CLASS) $(RUNTIME_EXECUTABLE) $(MOBILE_RUNTIME_ARG)
  TOOLS_RUNTIME = MONO_PATH=$(mcs_topdir)/class/lib/build $(top_builddir)/runtime/mono-wrapper
 -INTERPRETER_RUNTIME = $(MINI_RUNTIME) --interpreter
 +INTERP_RUNTIME = $(MINI_RUNTIME) --interpreter
  RUNTIME_AOTCHECK = MONO_PATH="$(CLASS)$(PLATFORM_PATH_SEPARATOR)." $(RUNTIME_EXECUTABLE)
  
  MCS = CSC_SDK_PATH_DISABLED= $(TOOLS_RUNTIME) $(CSC) -unsafe -nowarn:0162 -nologo -noconfig -r:$(CLASS)/mscorlib.dll -r:$(CLASS)/System.dll -r:$(CLASS)/System.Core.dll
@@@ -378,7 -369,8 +378,8 @@@ darwin_sources = 
  windows_sources = \
        mini-windows.c \
        mini-windows.h \
-       mini-windows-dllmain.c
+       mini-windows-dllmain.c \
+       mini-windows-dlldac.c
  
  posix_sources = \
        mini-posix.c
@@@ -397,15 -389,15 +398,15 @@@ endi
  endif
  
  if ENABLE_INTERPRETER
 -interpreter_sources = \
 -      interpreter/hacks.h             \
 -      interpreter/interp.h    \
 -      interpreter/interp-internals.h  \
 -      interpreter/interp.c    \
 -      interpreter/mintops.h   \
 -      interpreter/mintops.def \
 -      interpreter/mintops.c   \
 -      interpreter/transform.c
 +interp_sources =      \
 +      interp/hacks.h          \
 +      interp/interp.h \
 +      interp/interp-internals.h       \
 +      interp/interp.c \
 +      interp/mintops.h        \
 +      interp/mintops.def      \
 +      interp/mintops.c        \
 +      interp/transform.c
  endif
  
  if ENABLE_LLVM
@@@ -538,6 -530,14 +539,6 @@@ endi
  
  regtests = $(filter-out $(regtests_DISABLED),$(regtests_UNIVERSAL))
  
 -iregtests = \
 -      basic.exe \
 -      basic-float.exe \
 -      basic-long.exe \
 -      basic-calls.exe \
 -      generics.exe \
 -      objects.exe
 -
  if X86
  arch_sources = $(x86_sources)
  arch_built=cpu-x86.h
@@@ -623,7 -623,7 +624,7 @@@ os_sources = $(darwin_sources) $(posix_
  monobin_platform_ldflags=-framework CoreFoundation -framework Foundation
  endif
  
 -libmini_la_SOURCES = $(common_sources) $(llvm_sources) $(llvm_runtime_sources) $(interpreter_sources) $(arch_sources) $(os_sources)
 +libmini_la_SOURCES = $(common_sources) $(llvm_sources) $(llvm_runtime_sources) $(interp_sources) $(arch_sources) $(os_sources)
  libmini_la_CFLAGS = $(mono_CFLAGS)
  
  libmonoboehm_2_0_la_SOURCES =
@@@ -747,8 -747,8 +748,8 @@@ rcheck-nunit: mono $(regtests
  rcheck: mono $(regtests)
        $(MINI_RUNTIME) --regression $(regtests)
  
 -richeck: mono $(iregtests)
 -      $(INTERPRETER_RUNTIME) --regression $(iregtests)
 +richeck: mono $(regtests)
 +      $(INTERP_RUNTIME) --regression $(regtests)
  
  if ARM
  check-seq-points:
@@@ -814,9 -814,9 +815,9 @@@ fullaotcheck: $(mono) $(fullaot_regtest
        mkdir $(FULLAOT_TMP_DIR)
        $(MAKE) fullaot-libs AOT_FLAGS="full,$(MONO_FULLAOT_ADDITIONAL_ARGS)$(INVARIANT_AOT_OPTIONS)" GSHAREDVT=$(GSHAREDVT)
        cp $(regtests) $(fullaot_regtests) generics-variant-types.dll TestDriver.dll $(FULLAOT_TMP_DIR)/
 -      MONO_PATH=$(FULLAOT_TMP_DIR) $(top_builddir)/runtime/mono-wrapper $(LLVM_AOT_RUNTIME_OPTS) $(GSHAREDVT_RUNTIME_OPTS) --aot="full,$(MONO_FULLAOT_ADDITIONAL_ARGS)$(INVARIANT_AOT_OPTIONS)" $(FULLAOT_TMP_DIR)/{generics-variant-types.dll,TestDriver.dll,*.exe} || exit 1
 +      MONO_PATH=$(FULLAOT_TMP_DIR) $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) $(LLVM_AOT_RUNTIME_OPTS) $(GSHAREDVT_RUNTIME_OPTS) --aot="full,$(MONO_FULLAOT_ADDITIONAL_ARGS)$(INVARIANT_AOT_OPTIONS)" $(FULLAOT_TMP_DIR)/{generics-variant-types.dll,TestDriver.dll,*.exe} || exit 1
        ln -s $(if $(MONO_EXECUTABLE),$(MONO_EXECUTABLE),$$PWD/mono) $(FULLAOT_TMP_DIR)/
 -      for i in $(fullaot_regtests); do echo $$i; MONO_PATH=$(FULLAOT_TMP_DIR) $(top_builddir)/runtime/mono-wrapper --full-aot $(FULLAOT_TMP_DIR)/$$i --exclude '!FULLAOT' $(ARCH_FULLAOT_EXCLUDE) || exit 1; done
 +      for i in $(fullaot_regtests); do echo $$i; MONO_PATH=$(FULLAOT_TMP_DIR) $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) --full-aot $(FULLAOT_TMP_DIR)/$$i --exclude '!FULLAOT' $(ARCH_FULLAOT_EXCLUDE) || exit 1; done
  
  # This can run in parallel
  fullaot-libs: $(patsubst %,fullaot-tmp/%.dylib,$(FULLAOT_LIBS))
  fullaot-tmp/%.dylib: $(CLASS)/%
        cp $(CLASS)/$* fullaot-tmp/
        mkdir fullaot-tmp/$*-tmp
 -      MONO_PATH="fullaot-tmp/$(PLATFORM_PATH_SEPARATOR)$(CLASS)" $(top_builddir)/runtime/mono-wrapper $(if $(GSHAREDVT),-O=gsharedvt) --aot=$(AOT_FLAGS),temp-path=fullaot-tmp/$*-tmp fullaot-tmp/$*
 +      MONO_PATH="fullaot-tmp/$(PLATFORM_PATH_SEPARATOR)$(CLASS)" $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) $(if $(GSHAREDVT),-O=gsharedvt) --aot=$(AOT_FLAGS),temp-path=fullaot-tmp/$*-tmp fullaot-tmp/$*
        rm -rf fullaot-tmp/$*-tmp
  
  llvmfullaotcheck:
@@@ -837,9 -837,9 +838,9 @@@ llvmonlycheck: mono $(llvmonly_regtests
        mkdir fullaot-tmp
        $(MAKE) fullaot-libs AOT_FLAGS="llvmonly,$(MONO_FULLAOT_ADDITIONAL_ARGS)$(INVARIANT_AOT_OPTIONS)"
        cp $(llvmonly_regtests) generics-variant-types.dll TestDriver.dll fullaot-tmp/
 -      MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper  --aot=llvmonly fullaot-tmp/{generics-variant-types.dll,TestDriver.dll,*.exe} || exit 1
 +      MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper  $(MOBILE_RUNTIME_ARG) --aot=llvmonly fullaot-tmp/{generics-variant-types.dll,TestDriver.dll,*.exe} || exit 1
        ln -s $$PWD/mono fullaot-tmp/
 -      for i in $(llvmonly_regtests); do echo $$i; MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper --llvmonly fullaot-tmp/$$i --exclude '!BITCODE' || exit 1; done
 +      for i in $(llvmonly_regtests); do echo $$i; MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper $(MOBILE_RUNTIME_ARG) --llvmonly fullaot-tmp/$$i --exclude '!BITCODE' || exit 1; done
  
  gccheck: gc-test.exe
        MONO_GC_PARAMS=stack-mark=precise MONO_GC_DEBUG=clear-at-gc ./mono-sgen gc-test.exe     
diff --combined mono/mini/aot-compiler.c
index c3ef028789288d800198496a68031222426e2cdf,864d0b247c2bbebacaa2927b5c55ae19929711bd..22dc64f95197ac60691c4a89eac17f793438fc2f
@@@ -5246,11 -5246,11 +5246,11 @@@ compute_line_numbers (MonoMethod *metho
                if (il_offset == -1 || il_offset == prev_il_offset)
                        continue;
                prev_il_offset = il_offset;
 -              loc = mono_debug_symfile_lookup_location (minfo, il_offset);
 +              loc = mono_debug_method_lookup_location (minfo, il_offset);
                if (!(loc && loc->source_file))
                        continue;
                if (loc->row == prev_line) {
 -                      mono_debug_symfile_free_location (loc);
 +                      mono_debug_free_source_location (loc);
                        continue;
                }
                prev_line = loc->row;
@@@ -5349,7 -5349,7 +5349,7 @@@ emit_and_reloc_code (MonoAotCompile *ac
                                options = "";
                        prologue_end = TRUE;
                        fprintf (acfg->fp, ".loc %d %d 0%s\n", findex, loc->row, options);
 -                      mono_debug_symfile_free_location (loc);
 +                      mono_debug_free_source_location (loc);
                }
  
                skip = FALSE;
@@@ -7892,13 -7892,14 +7892,13 @@@ compile_method (MonoAotCompile *acfg, M
  static mono_thread_start_return_t WINAPI
  compile_thread_main (gpointer user_data)
  {
 -      MonoDomain *domain = ((MonoDomain **)user_data) [0];
 -      MonoAotCompile *acfg = ((MonoAotCompile **)user_data) [1];
 -      GPtrArray *methods = ((GPtrArray **)user_data) [2];
 +      MonoAotCompile *acfg = ((MonoAotCompile **)user_data) [0];
 +      GPtrArray *methods = ((GPtrArray **)user_data) [1];
        int i;
  
        MonoError error;
 -      MonoThread *thread = mono_thread_attach (domain);
 -      mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "AOT compiler"), TRUE, FALSE, &error);
 +      MonoInternalThread *internal = mono_thread_internal_current ();
 +      mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "AOT compiler"), TRUE, FALSE, &error);
        mono_error_assert_ok (&error);
  
        for (i = 0; i < methods->len; ++i)
@@@ -8200,7 -8201,7 +8200,7 @@@ execute_system (const char * command
  {
        int status = 0;
  
- #if HOST_WIN32
+ #if defined(HOST_WIN32) && defined(HAVE_SYSTEM)
        // We need an extra set of quotes around the whole command to properly handle commands 
        // with spaces since internally the command is called through "cmd /c.
        char * quoted_command = g_strdup_printf ("\"%s\"", command);
@@@ -9868,9 -9869,6 +9868,9 @@@ compile_methods (MonoAotCompile *acfg
                        methods [i] = (MonoMethod *)g_ptr_array_index (acfg->methods, i);
                i = 0;
                while (i < methods_len) {
 +                      MonoError error;
 +                      MonoInternalThread *thread;
 +
                        frag = g_ptr_array_new ();
                        for (j = 0; j < len; ++j) {
                                if (i < methods_len) {
                        }
  
                        user_data = g_new0 (gpointer, 3);
 -                      user_data [0] = mono_domain_get ();
 -                      user_data [1] = acfg;
 -                      user_data [2] = frag;
 +                      user_data [0] = acfg;
 +                      user_data [1] = frag;
                        
 -                      thread_handle = mono_threads_create_thread (compile_thread_main, (gpointer) user_data, NULL, NULL);
 +                      thread = mono_thread_create_internal (mono_domain_get (), compile_thread_main, (gpointer) user_data, MONO_THREAD_CREATE_FLAGS_NONE, &error);
 +                      mono_error_assert_ok (&error);
 +
 +                      thread_handle = mono_threads_open_thread_handle (thread->handle);
                        g_ptr_array_add (threads, thread_handle);
                }
                g_free (methods);
diff --combined mono/mini/mini-runtime.c
index 9336b94f2d2bcc0f5935fa09163f6f5bfb9e0098,22d9a5cd227a889fe2192431f7357b12f972e822..d573c31ce04be54923e55f37bb708299940016df
@@@ -91,7 -91,7 +91,7 @@@
  #endif
  
  #ifdef ENABLE_INTERPRETER
 -#include "interpreter/interp.h"
 +#include "interp/interp.h"
  #endif
  
  static guint32 default_opt = 0;
@@@ -505,6 -505,10 +505,10 @@@ mono_tramp_info_register (MonoTrampInf
        mono_save_trampoline_xdebug_info (info);
        mono_lldb_save_trampoline_info (info);
  
+ #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
+       mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
+ #endif
        /* Only register trampolines that have unwind infos */
        if (mono_get_root_domain () && copy->uw_info)
                register_trampoline_jit_info (domain, copy);
@@@ -3048,10 -3052,6 +3052,10 @@@ mini_init_delegate (MonoDelegate *del
  {
        if (mono_llvm_only)
                del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
 +#ifdef ENABLE_INTERPRETER
 +      if (mono_use_interpreter)
 +              mono_interp_init_delegate (del);
 +#endif
  }
  
  char*
index 96d1e71adad3a8a7d874731d0493da317bbdb6d3,6497094328f27edbc433ca6d198a116c81f5e775..5cf1f75540db1a921bea4ea3755ebc5edd7118dd
@@@ -17,6 -17,7 +17,6 @@@
  #include <mono/metadata/appdomain.h>
  #include <mono/metadata/marshal.h>
  #include <mono/metadata/tabledefs.h>
 -#include <mono/metadata/mono-debug-debugger.h>
  #include <mono/metadata/profiler-private.h>
  #include <mono/metadata/gc-internals.h>
  #include <mono/arch/amd64/amd64-codegen.h>
@@@ -161,7 -162,7 +161,7 @@@ mono_arch_get_gsharedvt_trampoline (Mon
        int reg_area_size;
  
        buf_len = 2048;
-       buf = code = mono_global_codeman_reserve (buf_len);
+       buf = code = mono_global_codeman_reserve (buf_len + MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE);
  
        /*
         * We are being called by an gsharedvt arg trampoline, the info argument is in AMD64_RAX.
  
        /* unwind markers 3/3 */
        mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, AMD64_RBP);
+       mono_add_unwind_op_fp_alloc (unwind_ops, code, buf, AMD64_RBP, 0);
  
        /* setup the frame */
        amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize);
                mono_amd64_patch (br_ret [i], code);
  
        /* Exit code path */
+ #if TARGET_WIN32
+       amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
+       amd64_pop_reg (code, AMD64_RBP);
+       mono_add_unwind_op_same_value (unwind_ops, code, buf, AMD64_RBP);
+ #else
        amd64_leave (code);
+ #endif
        amd64_ret (code);
  
        g_assert ((code - buf) < buf_len);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE));
  
        if (info)
                *info = mono_tramp_info_create ("gsharedvt_trampoline", buf, code - buf, ji, unwind_ops);
@@@ -482,4 -491,4 +490,4 @@@ mono_amd64_start_gsharedvt_call (GShare
        return NULL;
  }
  
 -#endif
 +#endif
diff --combined mono/mini/tramp-amd64.c
index f0b3e9cbbedbae81c53f20dad9c5c1ccc626d69d,0a93c0e69e69b6300abab3ab163abbc8cb3c5e02..7ec7437eb30de65ba5895512bfc4619f583718d2
@@@ -4,6 -4,7 +4,7 @@@
   * Authors:
   *   Dietmar Maurer (dietmar@ximian.com)
   *   Zoltan Varga (vargaz@gmail.com)
+  *   Johan Lorensson (lateralusx.github@gmail.com)
   *
   * (C) 2001 Ximian, Inc.
   * Copyright 2003-2011 Novell, Inc (http://www.novell.com)
@@@ -18,6 -19,7 +19,6 @@@
  #include <mono/metadata/appdomain.h>
  #include <mono/metadata/marshal.h>
  #include <mono/metadata/tabledefs.h>
 -#include <mono/metadata/mono-debug-debugger.h>
  #include <mono/metadata/profiler-private.h>
  #include <mono/metadata/gc-internals.h>
  #include <mono/arch/amd64/amd64-codegen.h>
@@@ -53,7 -55,7 +54,7 @@@ mono_arch_get_unbox_trampoline (MonoMet
  
        this_reg = mono_arch_get_this_arg_reg (NULL);
  
-       start = code = (guint8 *)mono_domain_code_reserve (domain, size);
+       start = code = (guint8 *)mono_domain_code_reserve (domain, size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
  
        unwind_ops = mono_arch_get_cie_program ();
  
@@@ -62,6 -64,7 +63,7 @@@
        amd64_mov_reg_imm (code, AMD64_RAX, addr);
        amd64_jump_reg (code, AMD64_RAX);
        g_assert ((code - start) < size);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
  
        mono_arch_flush_icache (start, code - start);
        mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m);
@@@ -95,13 -98,14 +97,14 @@@ mono_arch_get_static_rgctx_trampoline (
                buf_len = 30;
  #endif
  
-       start = code = (guint8 *)mono_domain_code_reserve (domain, buf_len);
+       start = code = (guint8 *)mono_domain_code_reserve (domain, buf_len + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
  
        unwind_ops = mono_arch_get_cie_program ();
  
        amd64_mov_reg_imm (code, MONO_ARCH_RGCTX_REG, mrgctx);
        amd64_jump_code (code, addr);
        g_assert ((code - start) < buf_len);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
  
        mono_arch_flush_icache (start, code - start);
        mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
@@@ -236,7 -240,7 +239,7 @@@ mono_arch_create_generic_trampoline (Mo
        else
                has_caller = TRUE;
  
-       code = buf = (guint8 *)mono_global_codeman_reserve (kMaxCodeSize);
+       code = buf = (guint8 *)mono_global_codeman_reserve (kMaxCodeSize + MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE);
  
        /* Compute stack frame size and offsets */
        offset = 0;
        orig_rsp_to_rbp_offset -= sizeof(mgreg_t);
        amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof(mgreg_t));
        mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, AMD64_RBP);
+       mono_add_unwind_op_fp_alloc (unwind_ops, code, buf, AMD64_RBP, 0);
        amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize);
  
        /* Compute the trampoline address from the return address */
         * We have an exception we want to throw in the caller's frame, so pop
         * the trampoline frame and throw from the caller.
         */
+ #if TARGET_WIN32
+       amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
+       amd64_pop_reg (code, AMD64_RBP);
+       mono_add_unwind_op_same_value (unwind_ops, code, buf, AMD64_RBP);
+ #else
        amd64_leave (code);
+ #endif
        /* We are in the parent frame, the exception is in rax */
        /*
         * EH is initialized after trampolines, so get the address of the variable
                amd64_movsd_reg_membase (code, i, AMD64_RBP, saved_fpregs_offset + (i * sizeof(mgreg_t)));
  
        /* Restore stack */
+ #if TARGET_WIN32
+       amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
+       amd64_pop_reg (code, AMD64_RBP);
+       mono_add_unwind_op_same_value (unwind_ops, code, buf, AMD64_RBP);
+ #else
        amd64_leave (code);
+ #endif
        cfa_offset -= sizeof (mgreg_t);
        mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, cfa_offset);
  
        }
  
        g_assert ((code - buf) <= kMaxCodeSize);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE));
  
        mono_arch_flush_icache (buf, code - buf);
        mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);
@@@ -641,7 -659,7 +658,7 @@@ mono_arch_create_rgctx_lazy_fetch_tramp
  
        tramp_size = 64 + 8 * depth;
  
-       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size);
+       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
  
        unwind_ops = mono_arch_get_cie_program ();
  
        mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
  
        g_assert (code - buf <= tramp_size);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
  
        char *name = mono_get_rgctx_fetch_trampoline_name (slot);
        *info = mono_tramp_info_create (name, buf, code - buf, ji, unwind_ops);
@@@ -724,7 -743,7 +742,7 @@@ mono_arch_create_general_rgctx_lazy_fet
        g_assert (aot);
        tramp_size = 64;
  
-       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size);
+       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
  
        unwind_ops = mono_arch_get_cie_program ();
  
        mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
  
        g_assert (code - buf <= tramp_size);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
  
        if (info)
                *info = mono_tramp_info_create ("rgctx_fetch_trampoline_general", buf, code - buf, ji, unwind_ops);
@@@ -778,7 -798,7 +797,7 @@@ mono_arch_create_handler_block_trampoli
        MonoJumpInfo *ji = NULL;
        GSList *unwind_ops;
  
-       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size);
+       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
  
        unwind_ops = mono_arch_get_cie_program ();
  
        mono_arch_flush_icache (buf, code - buf);
        mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);
        g_assert (code - buf <= tramp_size);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
  
        *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops);
  
@@@ -886,7 -907,7 +906,7 @@@ mono_arch_create_sdb_trampoline (gboole
        GSList *unwind_ops = NULL;
        MonoJumpInfo *ji = NULL;
  
-       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size);
+       code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size + MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE);
  
        framesize = 0;
  #ifdef TARGET_WIN32
  
        amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof(mgreg_t));
        mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, AMD64_RBP);
+       mono_add_unwind_op_fp_alloc (unwind_ops, code, buf, AMD64_RBP, 0);
        amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize);
  
        gregs_offset = ctx_offset + MONO_STRUCT_OFFSET (MonoContext, gregs);
        amd64_mov_reg_membase (code, AMD64_R11, AMD64_RSP, gregs_offset + (AMD64_RIP * sizeof (mgreg_t)), sizeof (mgreg_t));
        amd64_mov_membase_reg (code, AMD64_RBP, sizeof (mgreg_t), AMD64_R11, sizeof (mgreg_t));
  
+ #if TARGET_WIN32
+       amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
+       amd64_pop_reg (code, AMD64_RBP);
+       mono_add_unwind_op_same_value (unwind_ops, code, buf, AMD64_RBP);
+ #else
        amd64_leave (code);
+ #endif
        cfa_offset -= sizeof (mgreg_t);
        mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, cfa_offset);
        amd64_ret (code);
        mono_arch_flush_icache (code, code - buf);
        mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);
        g_assert (code - buf <= tramp_size);
+       g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE));
  
        const char *tramp_name = single_step ? "sdb_single_step_trampoline" : "sdb_breakpoint_trampoline";
        *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops);
  
        return buf;
  }
 -#endif /* !DISABLE_JIT */
  
  /*
   * mono_arch_get_enter_icall_trampoline:
@@@ -980,144 -1010,80 +1008,144 @@@ gpointe
  mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
  {
  #ifdef ENABLE_INTERPRETER
 -      const int gregs_num = 6;
 -      guint8 *start = NULL, *code, *exits [gregs_num], *leave_tramp;
 +      const int gregs_num = 8;
 +      const int fregs_num = 3;
 +      guint8 *start = NULL, *code, *label_gexits [gregs_num], *label_fexits [fregs_num], *label_leave_tramp [3], *label_is_float_ret;
        MonoJumpInfo *ji = NULL;
        GSList *unwind_ops = NULL;
 -      static int arg_regs[] = {AMD64_ARG_REG1, AMD64_ARG_REG2, AMD64_ARG_REG3, AMD64_ARG_REG4, AMD64_R8, AMD64_R9};
 -      int i, offset = 0;
 +      static int farg_regs[] = {AMD64_XMM0, AMD64_XMM1, AMD64_XMM2};
 +      int i, framesize = 0, off_rbp, off_methodargs, off_targetaddr;
  
-       start = code = (guint8 *) mono_global_codeman_reserve (256);
+       start = code = (guint8 *) mono_global_codeman_reserve (256 + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
  
 +      off_rbp = -framesize;
 +
 +      framesize += sizeof (mgreg_t);
 +      off_methodargs = -framesize;
 +
 +      framesize += sizeof (mgreg_t);
 +      off_targetaddr = -framesize;
 +
 +      framesize += (gregs_num - PARAM_REGS) * sizeof (mgreg_t);
 +
 +      amd64_push_reg (code, AMD64_RBP);
 +      amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof (mgreg_t));
 +      amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT));
 +
        /* save MethodArguments* onto stack */
 -      amd64_push_reg (code, AMD64_ARG_REG2);
 +      amd64_mov_membase_reg (code, AMD64_RBP, off_methodargs, AMD64_ARG_REG2, sizeof (mgreg_t));
  
        /* save target address on stack */
 -      amd64_push_reg (code, AMD64_ARG_REG1);
 -      amd64_push_reg (code, AMD64_RAX);
 +      amd64_mov_membase_reg (code, AMD64_RBP, off_targetaddr, AMD64_ARG_REG1, sizeof (mgreg_t));
  
        /* load pointer to MethodArguments* into R11 */
        amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG2, 8);
        
 -      /* TODO: do float stuff first */
 +      /* move flen into RAX */ // TODO: struct offset
 +      amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, 16, sizeof (mgreg_t));
 +      /* load pointer to fregs into R11 */ // TODO: struct offset
 +      amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 24, sizeof (mgreg_t));
 +
 +      for (i = 0; i < fregs_num; ++i) {
 +              amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
 +              label_fexits [i] = code;
 +              x86_branch8 (code, X86_CC_Z, 0, FALSE);
 +
 +              amd64_sse_movsd_reg_membase (code, farg_regs [i], AMD64_R11, i * sizeof (double));
 +              amd64_dec_reg_size (code, AMD64_RAX, 1);
 +      }
 +
 +      for (i = 0; i < fregs_num; i++) {
 +              x86_patch (label_fexits [i], code);
 +      }
  
 +      /* load pointer to MethodArguments* into R11 */
 +      amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG2, sizeof (mgreg_t));
        /* move ilen into RAX */ // TODO: struct offset
 -      amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, 0, 8);
 -      /* load pointer to iregs into R11 */ // TODO: struct offset
 -      amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 8, 8);
 +      amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, 0, sizeof (mgreg_t));
  
 +      int stack_offset = 0;
        for (i = 0; i < gregs_num; i++) {
                amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
 -              exits [i] = code;
 -              x86_branch8 (code, X86_CC_Z, 0, FALSE);
 +              label_gexits [i] = code;
 +              x86_branch32 (code, X86_CC_Z, 0, FALSE);
  
 -#ifdef TARGET_WIN32
 -              if (i < 4) {
 -#else
 -              if (i < 6) {
 -#endif
 -                      amd64_mov_reg_membase (code, arg_regs [i], AMD64_R11, i * sizeof (gpointer), 8);
 +              /* load pointer to MethodArguments* into R11 */
 +              amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_methodargs, sizeof (mgreg_t));
 +              /* load pointer to iregs into R11 */ // TODO: struct offset
 +              amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 8, sizeof (mgreg_t));
 +
 +              if (i < PARAM_REGS) {
 +                      amd64_mov_reg_membase (code, param_regs [i], AMD64_R11, i * sizeof (mgreg_t), sizeof (mgreg_t));
                } else {
 -                      g_error ("not tested yet.");
 -                      amd64_push_reg (code, AMD64_RAX);
 -                      amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, i * sizeof (gpointer), 8);
 -                      amd64_mov_membase_reg (code, AMD64_RBP, offset, AMD64_RAX, sizeof (gpointer));
 -                      offset += sizeof (gpointer);
 -                      amd64_pop_reg (code, AMD64_RAX);
 +                      amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, i * sizeof (mgreg_t), sizeof (mgreg_t));
 +                      amd64_mov_membase_reg (code, AMD64_RSP, stack_offset, AMD64_R11, sizeof (mgreg_t));
 +                      stack_offset += sizeof (mgreg_t);
                }
                amd64_dec_reg_size (code, AMD64_RAX, 1);
        }
  
        for (i = 0; i < gregs_num; i++) {
 -              x86_patch (exits [i], code);
 +              x86_patch (label_gexits [i], code);
        }
  
 -
 -      amd64_pop_reg (code, AMD64_RAX);
 -      amd64_pop_reg (code, AMD64_R11);
 +      /* load target addr */
 +      amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_targetaddr, sizeof (mgreg_t));
  
        /* call into native function */
        amd64_call_reg (code, AMD64_R11);
  
        /* load MethodArguments */
 -      amd64_pop_reg (code, AMD64_R11);
 +      amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_methodargs, sizeof (mgreg_t));
 +
 +      /* load is_float_ret */ // TODO: struct offset
 +      amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0x28, sizeof (mgreg_t));
 +
 +      /* check if a float return value is expected */
 +      amd64_test_reg_reg (code, AMD64_R11, AMD64_R11);
 +
 +      label_is_float_ret = code;
 +      x86_branch8 (code, X86_CC_NZ, 0, FALSE);
 +
 +
 +
 +      /* greg return */
 +      /* load MethodArguments */
 +      amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_methodargs, sizeof (mgreg_t));
        /* load retval */ // TODO: struct offset
 -      amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0x20, 8);
 +      amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0x20, sizeof (mgreg_t));
  
        amd64_test_reg_reg (code, AMD64_R11, AMD64_R11);
 -      leave_tramp = code;
 +      label_leave_tramp [0] = code;
        x86_branch8 (code, X86_CC_Z, 0, FALSE);
  
 -      amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RAX, 8);
 +      amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RAX, sizeof (mgreg_t));
 +
 +      label_leave_tramp [1] = code;
 +      x86_jump8 (code, 0);
  
 -      x86_patch (leave_tramp, code);
 -      amd64_ret (code);
  
  
 +      /* freg return */
 +      x86_patch (label_is_float_ret, code);
 +      /* load MethodArguments */
 +      amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_methodargs, sizeof (mgreg_t));
 +      /* load retval */ // TODO: struct offset
 +      amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0x20, sizeof (mgreg_t));
 +
 +      amd64_test_reg_reg (code, AMD64_R11, AMD64_R11);
 +      label_leave_tramp [2] = code;
 +      x86_branch8 (code, X86_CC_Z, 0, FALSE);
 +
 +      amd64_sse_movsd_membase_reg (code, AMD64_R11, 0, AMD64_XMM0);
 +
 +      for (i = 0; i < 3; i++)
 +              x86_patch (label_leave_tramp [i], code);
 +
 +      amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT));
 +      amd64_pop_reg (code, AMD64_RBP);
 +      amd64_ret (code);
 +
        mono_arch_flush_icache (start, code - start);
        mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL);
  
        return NULL;
  #endif /* ENABLE_INTERPRETER */
  }
 +#endif /* !DISABLE_JIT */
  
  #ifdef DISABLE_JIT
  gpointer
diff --combined mono/mini/unwind.c
index 3f8a2bdfcdedcd623a2c6014326496db48846901,960447171e690e113129845451173abf39cbcadb..f63171e52f171eaf656667e33b5a9297c37231f2
@@@ -382,14 -382,14 +382,14 @@@ mono_unwind_ops_encode_full (GSList *un
  
                /* Emit an advance_loc if neccesary */
                while (op->when > loc) {
 -                      if (op->when - loc > 65536) {
 +                      if (op->when - loc >= 65536) {
                                *p ++ = DW_CFA_advance_loc4;
                                guint32 v = (guint32)(op->when - loc);
                                memcpy (p, &v, 4);
                                g_assert (read32 (p) == (guint32)(op->when - loc));
                                p += 4;
                                loc = op->when;
 -                      } else if (op->when - loc > 256) {
 +                      } else if (op->when - loc >= 256) {
                                *p ++ = DW_CFA_advance_loc2;
                                guint16 v = (guint16)(op->when - loc);
                                memcpy (p, &v, 2);
                        g_assert (op->val == 0);
                        *p ++ = op->op;
                        break;
+ #if defined(TARGET_WIN32) && defined(TARGET_AMD64)
+               case DW_CFA_mono_sp_alloc_info_win64:
+               case DW_CFA_mono_fp_alloc_info_win64:
+                       // Drop Windows specific unwind op's. These op's are currently
+                       // only used when registering unwind info with Windows OS unwinder.
+                       break;
+ #endif
                default:
                        g_assert_not_reached ();
                        break;