[hybrid] Enable gsharedvt trampoline on amd64
[mono.git] / mono / mini / tramp-amd64-gsharedvt.c
index 675dcf6d3deedd2e75fcbecd46c6c1c708d88eec..0c986f14e7b8b7655ad2f16abd636e19197b0963 100644 (file)
@@ -5,6 +5,7 @@
  *   Zoltan Varga <vargaz@gmail.com>
  *   Rodrigo Kumpera <kumpera@gmail.com>
  *   Andi McClure <andi.mcclure@xamarin.com>
+ *   Johan Lorensson <johan.lorensson@xamarin.com>
  *
  * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
@@ -138,15 +139,14 @@ mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpoint
        amd64_jump_code (code, addr);
        g_assert ((code - start) < buf_len);
 
-       nacl_domain_code_validate (domain, &start, buf_len, &code);
        mono_arch_flush_icache (start, code - start);
        mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
 
-       g_assert (0);
+       mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain);
+
        return start;
 }
 
-
 gpointer
 mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
 {
@@ -246,8 +246,8 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
        <caller registers area>
        <rgctx>
        <gsharedvt info>
-       <calee stack area>
-       <calee reg area>
+       <callee stack area>
+       <callee reg area>
         */
 
        /* Call start_gsharedvt_call () */
@@ -264,9 +264,25 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
 
        if (aot) {
                code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_amd64_start_gsharedvt_call");
-               amd64_call_reg (code, AMD64_R11);
+               #ifdef TARGET_WIN32
+                       /* Since we are doing a call as part of setting up stackframe, the reserved shadow stack used by Windows platform is allocated up in
+                       the callee stack area but currently the callee reg area is in between. Windows calling convention dictates that room is made on stack where
+                       callee can save any parameters passed in registers. Since Windows x64 calling convention
+                       uses 4 registers for the first 4 parameters, stack needs to be adjusted before making the call.
+                       NOTE, Windows calling convention assumes that space for all registers have been reserved, regardless
+                       of the number of function parameters actually used.
+                       */
+                       int shadow_reg_size = 0;
+
+                       shadow_reg_size = ALIGN_TO (PARAM_REGS * sizeof(gpointer), MONO_ARCH_FRAME_ALIGNMENT);
+                       amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, shadow_reg_size);
+                       amd64_call_reg (code, AMD64_R11);
+                       amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, shadow_reg_size);
+               #else
+                       amd64_call_reg (code, AMD64_R11);
+               #endif
        } else {
-               g_error ("no aot");
+               amd64_call_code (code, mono_amd64_start_gsharedvt_call);
        }
 
        /* Method to call is now on RAX. Restore regs and jump */
@@ -303,13 +319,14 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
         */
 
        /* Load vret_slot */
-       amd64_mov_reg_membase (code, AMD64_RDI, AMD64_R10, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_slot), 4);
-       amd64_alu_reg_imm (code, X86_SUB, AMD64_RDI, n_arg_regs + n_arg_fregs);
-       amd64_shift_reg_imm (code, X86_SHL, AMD64_RDI, 3);
+       /* Use first input parameter register as scratch since it is volatile on all platforms */
+       amd64_mov_reg_membase (code, MONO_AMD64_ARG_REG1, AMD64_R10, MONO_STRUCT_OFFSET (GSharedVtCallInfo, vret_slot), 4);
+       amd64_alu_reg_imm (code, X86_SUB, MONO_AMD64_ARG_REG1, n_arg_regs + n_arg_fregs);
+       amd64_shift_reg_imm (code, X86_SHL, MONO_AMD64_ARG_REG1, 3);
 
        /* vret address is RBP - (framesize - caller_reg_area_offset) */
        amd64_mov_reg_reg (code, AMD64_R11, AMD64_RSP, sizeof(mgreg_t));
-       amd64_alu_reg_reg (code, X86_ADD, AMD64_R11, AMD64_RDI);
+       amd64_alu_reg_reg (code, X86_ADD, AMD64_R11, MONO_AMD64_ARG_REG1);
 
        /* Load ret marshal type */
        /* Load vret address in R11 */
@@ -367,10 +384,10 @@ mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
 
        /*
                Address to write return to is in the original value of the register specified by vret_arg_reg.
-               This will be either RSI or RDI depending on whether this is a static call.
+               This will be either RSI, RDI (System V) or RCX, RDX (Windows) depending on whether this is a static call.
                Its location:
                We alloc 'framesize' bytes below RBP to save regs, info and rgctx. RSP = RBP - framesize
-               We store rdi at RSP + caller_reg_area_offset + slot_index_of (register) * 8.
+               We store RDI (System V), RCX (Windows) at RSP + caller_reg_area_offset + slot_index_of (register) * 8.
 
                address: RBP - framesize + caller_reg_area_offset + 8*slot
        */