Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / mini / mini-amd64.h
index 24eb6524bf759596849b46637e9bc860c1a92d16..ba8466dfebeaa1d47b59d994c7b2995cb48e3929 100644 (file)
@@ -1,3 +1,7 @@
+/**
+ * \file
+ */
+
 #ifndef __MONO_MINI_AMD64_H__
 #define __MONO_MINI_AMD64_H__
 
@@ -47,6 +51,36 @@ void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler);
 
 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep);
 
+typedef struct {
+       SRWLOCK lock;
+       PVOID handle;
+       gsize begin_range;
+       gsize end_range;
+       PRUNTIME_FUNCTION rt_funcs;
+       DWORD rt_funcs_current_count;
+       DWORD rt_funcs_max_count;
+} DynamicFunctionTableEntry;
+
+#define MONO_UNWIND_INFO_RT_FUNC_SIZE 128
+
+// On Win8/Win2012Server and later we can use dynamic growable function tables
+// instead of RtlInstallFunctionTableCallback. This gives us the benefit to
+// include all needed unwind upon registration.
+typedef DWORD (NTAPI* RtlAddGrowableFunctionTablePtr)(
+    PVOID * DynamicTable,
+    PRUNTIME_FUNCTION FunctionTable,
+    DWORD EntryCount,
+    DWORD MaximumEntryCount,
+    ULONG_PTR RangeBase,
+    ULONG_PTR RangeEnd);
+
+typedef VOID (NTAPI* RtlGrowFunctionTablePtr)(
+    PVOID DynamicTable,
+    DWORD NewEntryCount);
+
+typedef VOID (NTAPI* RtlDeleteGrowableFunctionTablePtr)(
+    PVOID DynamicTable);
+
 #endif /* HOST_WIN32 */
 
 #ifdef sun    // Solaris x86
@@ -141,9 +175,6 @@ struct sigcontext {
  * reproduceable results for benchmarks */
 #define MONO_ARCH_CODE_ALIGNMENT 32
 
-/*This is the max size of the locals area of a given frame. I think 1MB is a safe default for now*/
-#define MONO_ARCH_MAX_FRAME_SIZE 0x100000
-
 struct MonoLMF {
        /* 
         * If the lowest bit is set, then this LMF has the rip field set. Otherwise,
@@ -178,7 +209,7 @@ typedef struct MonoCompileArch {
        gint32 async_point_count;
        gpointer vret_addr_loc;
 #ifdef HOST_WIN32
-       gpointer        unwindinfo;
+       gpointer unwindinfo;
 #endif
        gpointer seq_point_info_var;
        gpointer ss_trigger_page_var;
@@ -206,9 +237,10 @@ static AMD64_XMM_Reg_No float_return_regs [] = { AMD64_XMM0 };
 #define PARAM_REGS 6
 #define FLOAT_PARAM_REGS 8
 
-static AMD64_Reg_No param_regs [] = { AMD64_RDI, AMD64_RSI, AMD64_RDX, AMD64_RCX, AMD64_R8, AMD64_R9 };
+static const AMD64_Reg_No param_regs [] = {AMD64_RDI, AMD64_RSI, AMD64_RDX,
+                                          AMD64_RCX, AMD64_R8,  AMD64_R9};
 
-static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX };
+static const AMD64_Reg_No return_regs [] = {AMD64_RAX, AMD64_RDX};
 #endif
 
 typedef struct {
@@ -238,15 +270,15 @@ typedef struct {
        gpointer bp_addrs [MONO_ZERO_LEN_ARRAY];
 } SeqPointInfo;
 
-#define DYN_CALL_STACK_ARGS 6
-
 typedef struct {
-       mgreg_t regs [PARAM_REGS + DYN_CALL_STACK_ARGS];
        mgreg_t res;
        guint8 *ret;
        double fregs [8];
        mgreg_t has_fp;
+       mgreg_t nstack_args;
        guint8 buffer [256];
+       /* This should come last as the structure is dynamically extended */
+       mgreg_t regs [PARAM_REGS];
 } DynCallArgs;
 
 typedef enum {
@@ -278,6 +310,8 @@ typedef struct {
        int nregs;
        /* Only if storage == ArgOnStack */
        int arg_size; // Bytes, will always be rounded up/aligned to 8 byte boundary
+       // Size in bytes for small arguments
+       int byte_arg_size;
        guint8 pass_empty_struct : 1; // Set in scenarios when empty structs needs to be represented as argument.
 } ArgInfo;
 
@@ -369,11 +403,8 @@ typedef struct {
 #define MONO_ARCH_EMULATE_CONV_R8_UN    1
 #define MONO_ARCH_EMULATE_FREM 1
 #define MONO_ARCH_HAVE_IS_INT_OVERFLOW 1
-
-#define MONO_ARCH_ENABLE_MONO_LMF_VAR 1
 #define MONO_ARCH_HAVE_INVALIDATE_METHOD 1
 #define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
-#define MONO_ARCH_HAVE_TLS_GET (mono_amd64_have_tls_get ())
 #define MONO_ARCH_IMT_REG AMD64_R10
 #define MONO_ARCH_IMT_SCRATCH_REG AMD64_R11
 #define MONO_ARCH_VTABLE_REG MONO_AMD64_ARG_REG1
@@ -398,11 +429,9 @@ typedef struct {
 
 #define MONO_ARCH_GSHARED_SUPPORTED 1
 #define MONO_ARCH_DYN_CALL_SUPPORTED 1
-#define MONO_ARCH_DYN_CALL_PARAM_AREA (DYN_CALL_STACK_ARGS * 8)
+#define MONO_ARCH_DYN_CALL_PARAM_AREA 0
 
 #define MONO_ARCH_LLVM_SUPPORTED 1
-#define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
-#define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD_AOT 1
 #define MONO_ARCH_HAVE_CARD_TABLE_WBARRIER 1
 #define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1
 #define MONO_ARCH_GC_MAPS_SUPPORTED 1
@@ -416,15 +445,12 @@ typedef struct {
 #define MONO_ARCH_HAVE_PATCH_CODE_NEW 1
 #define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1
 #define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE 1
+#define MONO_ARCH_HAVE_INIT_LMF_EXT 1
 
 #if defined(TARGET_OSX) || defined(__linux__)
 #define MONO_ARCH_HAVE_UNWIND_BACKTRACE 1
 #endif
 
-#if defined(TARGET_OSX) || defined(__linux__) || defined(TARGET_WIN32)
-#define MONO_ARCH_HAVE_TLS_GET_REG 1
-#endif
-
 #define MONO_ARCH_GSHAREDVT_SUPPORTED 1
 
 
@@ -470,30 +496,118 @@ mono_amd64_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpoi
 guint64
 mono_amd64_get_original_ip (void);
 
-guint8*
-mono_amd64_emit_tls_get (guint8* code, int dreg, int tls_offset);
-
-gboolean
-mono_amd64_have_tls_get (void);
-
 GSList*
 mono_amd64_get_exception_trampolines (gboolean aot);
 
 int
 mono_amd64_get_tls_gs_offset (void) MONO_LLVM_INTERNAL;
 
-gpointer
-mono_amd64_handler_block_trampoline_helper (void);
+#if defined(TARGET_WIN32) && !defined(DISABLE_JIT)
 
-#ifdef TARGET_WIN32
+#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
+#define MONO_ARCH_HAVE_UNWIND_TABLE 1
+#define MONO_ARCH_HAVE_CODE_CHUNK_TRACKING 1
 
-void mono_arch_unwindinfo_add_push_nonvol (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg );
-void mono_arch_unwindinfo_add_set_fpreg (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg );
-void mono_arch_unwindinfo_add_alloc_stack (gpointer* monoui, gpointer codebegin, gpointer nextip, guint size );
-guint mono_arch_unwindinfo_get_size (gpointer monoui);
-void mono_arch_unwindinfo_install_unwind_info (gpointer* monoui, gpointer code, guint code_size);
+#ifdef ENABLE_CHECKED_BUILD
+#define ENABLE_CHECKED_BUILD_UNWINDINFO
+#endif
 
-#define MONO_ARCH_HAVE_UNWIND_TABLE 1
+#define MONO_MAX_UNWIND_CODES 22
+
+typedef enum _UNWIND_OP_CODES {
+    UWOP_PUSH_NONVOL = 0, /* info == register number */
+    UWOP_ALLOC_LARGE,     /* no info, alloc size in next 2 slots */
+    UWOP_ALLOC_SMALL,     /* info == size of allocation / 8 - 1 */
+    UWOP_SET_FPREG,       /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
+    UWOP_SAVE_NONVOL,     /* info == register number, offset in next slot */
+    UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
+    UWOP_SAVE_XMM128,     /* info == XMM reg number, offset in next slot */
+    UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
+    UWOP_PUSH_MACHFRAME   /* info == 0: no error-code, 1: error-code */
+} UNWIND_CODE_OPS;
+
+typedef union _UNWIND_CODE {
+    struct {
+        guchar CodeOffset;
+        guchar UnwindOp : 4;
+        guchar OpInfo   : 4;
+    };
+    gushort FrameOffset;
+} UNWIND_CODE, *PUNWIND_CODE;
+
+typedef struct _UNWIND_INFO {
+       guchar Version       : 3;
+       guchar Flags         : 5;
+       guchar SizeOfProlog;
+       guchar CountOfCodes;
+       guchar FrameRegister : 4;
+       guchar FrameOffset   : 4;
+       UNWIND_CODE UnwindCode[MONO_MAX_UNWIND_CODES];
+/*     UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
+ *     union {
+ *             OPTIONAL ULONG ExceptionHandler;
+ *             OPTIONAL ULONG FunctionEntry;
+ *     };
+ *     OPTIONAL ULONG ExceptionData[]; */
+} UNWIND_INFO, *PUNWIND_INFO;
+
+static inline guint
+mono_arch_unwindinfo_get_size (guchar code_count)
+{
+       // Returned size will be used as the allocated size for unwind data trailing the memory used by compiled method.
+       // Windows x64 ABI have some requirements on the data written into this memory. Both the RUNTIME_FUNCTION
+       // and UNWIND_INFO struct needs to be DWORD aligned and the number of elements in unwind codes array
+       // should have an even number of entries, while the count stored in UNWIND_INFO struct should hold the real number
+       // of unwind codes. Adding extra bytes to the total size will make sure we can properly align the RUNTIME_FUNCTION
+       // struct. Since our UNWIND_INFO follows RUNTIME_FUNCTION struct in memory, it will automatically be DWORD aligned
+       // as well. Also make sure to allocate room for a padding UNWIND_CODE, if needed.
+       return (sizeof (mgreg_t) + sizeof (UNWIND_INFO)) -
+               (sizeof (UNWIND_CODE) * ((MONO_MAX_UNWIND_CODES - ((code_count + 1) & ~1))));
+}
+
+guchar
+mono_arch_unwindinfo_get_code_count (GSList *unwind_ops);
+
+guint
+mono_arch_unwindinfo_init_method_unwind_info (gpointer cfg);
+
+void
+mono_arch_unwindinfo_install_method_unwind_info (gpointer *monoui, gpointer code, guint code_size);
+
+void
+mono_arch_unwindinfo_install_tramp_unwind_info (GSList *unwind_ops, gpointer code, guint code_size);
+
+void
+mono_arch_code_chunk_new (void *chunk, int size);
+
+void
+mono_arch_code_chunk_destroy (void *chunk);
+
+#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
+#endif /* defined(TARGET_WIN32) && !defined(DISABLE_JIT) */
+
+#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
+// Allocate additional size for max 3 unwind ops (push + fp or sp small|large) + unwind info struct trailing code buffer.
+#define MONO_TRAMPOLINE_UNWINDINFO_SIZE(max_code_count) (mono_arch_unwindinfo_get_size (max_code_count))
+#define MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE (MONO_TRAMPOLINE_UNWINDINFO_SIZE(3))
+
+static inline gboolean
+mono_arch_unwindinfo_validate_size (GSList *unwind_ops, guint max_size)
+{
+       guint current_size = mono_arch_unwindinfo_get_size (mono_arch_unwindinfo_get_code_count (unwind_ops));
+       return current_size <= max_size;
+}
+
+#else
+
+#define MONO_TRAMPOLINE_UNWINDINFO_SIZE(max_code_count) 0
+#define MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE 0
+
+static inline gboolean
+mono_arch_unwindinfo_validate_size (GSList *unwind_ops, guint max_size)
+{
+       return TRUE;
+}
 #endif
 
 CallInfo* mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig);