diff --git a/include/jit/jit-common.h b/include/jit/jit-common.h
index 9f0955e..072e4d2 100644
--- a/include/jit/jit-common.h
+++ b/include/jit/jit-common.h
@@ -78,6 +78,15 @@ typedef jit_nuint jit_label_t;
 #define	JIT_NO_OFFSET		(~((unsigned int)0))
 
 /*
+ * Functions used for the plugin memory manager for code memory.
+ */
+typedef void* (*jit_malloc_code_func)(unsigned long minimalsize, unsigned long* actual_size);
+typedef void  (*jit_resize_code_func)(void *data, unsigned long actual_size);
+typedef void  (*jit_free_code_func)(void *data);
+typedef void* (*jit_malloc_func)(unsigned long size);
+typedef void  (*jit_free_func)(void *data);
+
+/*
  * Function that is used to free user-supplied metadata.
  */
 typedef void (*jit_meta_free_func)(void *data);
diff --git a/include/jit/jit-context.h b/include/jit/jit-context.h
index ccb89d9..ff39f14 100644
--- a/include/jit/jit-context.h
+++ b/include/jit/jit-context.h
@@ -44,6 +44,11 @@ void *jit_context_get_meta(jit_context_t context, int type) JIT_NOTHROW;
 jit_nuint jit_context_get_meta_numeric
 	(jit_context_t context, int type) JIT_NOTHROW;
 void jit_context_free_meta(jit_context_t context, int type) JIT_NOTHROW;
+void jit_context_set_code_allocator(jit_context_t context,
+				    jit_malloc_code_func malloc_code_func, jit_resize_code_func resize_code_func, jit_free_code_func free_code_func,
+				    jit_malloc_func malloc_func, jit_free_func free_func);
+int jit_context_get_code_factor(jit_context_t context);
+void jit_context_update_code_factor(jit_context_t context, int code_factor);
 
 /*
  * Standard meta values for builtin configurable options.
diff --git a/include/jit/jit-function.h b/include/jit/jit-function.h
index e24271a..75cd4f0 100644
--- a/include/jit/jit-function.h
+++ b/include/jit/jit-function.h
@@ -37,6 +37,7 @@ jit_function_t jit_function_create_nested
 	(jit_context_t context, jit_type_t signature,
 	 jit_function_t parent) JIT_NOTHROW;
 void jit_function_abandon(jit_function_t func) JIT_NOTHROW;
+void jit_function_free(jit_function_t func) JIT_NOTHROW;
 jit_context_t jit_function_get_context(jit_function_t func) JIT_NOTHROW;
 jit_type_t jit_function_get_signature(jit_function_t func) JIT_NOTHROW;
 int jit_function_set_meta
diff --git a/include/jit/jit-insn.h b/include/jit/jit-insn.h
index e2631eb..c000128 100644
--- a/include/jit/jit-insn.h
+++ b/include/jit/jit-insn.h
@@ -216,6 +216,7 @@ jit_value_t jit_insn_address_of
 	(jit_function_t func, jit_value_t value1) JIT_NOTHROW;
 jit_value_t jit_insn_address_of_label
 	(jit_function_t func, jit_label_t *label) JIT_NOTHROW;
+int jit_insn_cast(jit_function_t func, jit_value_t value, jit_type_t type) JIT_NOTHROW;
 jit_value_t jit_insn_convert
 	(jit_function_t func, jit_value_t value,
 	 jit_type_t type, int overflow_check) JIT_NOTHROW;
diff --git a/jit/Makefile.am b/jit/Makefile.am
index 4dd0274..9a010d3 100644
--- a/jit/Makefile.am
+++ b/jit/Makefile.am
@@ -83,7 +83,7 @@ EXTRA_DIST = \
 
 AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -I. -I$(srcdir)
 
-libjit_la_LDFLAGS = -version-info $(LIBJIT_VERSION) -no-undefined
+libjit_la_LDFLAGS = -shared -Wl,--kill-at,--output-def,libjit.def -version-info $(LIBJIT_VERSION) -no-undefined
 
 jit-interp.lo: jit-interp-labels.h
 
diff --git a/jit/jit-apply-x86-64.c b/jit/jit-apply-x86-64.c
index 895fccc..38f662b 100644
--- a/jit/jit-apply-x86-64.c
+++ b/jit/jit-apply-x86-64.c
@@ -487,13 +487,18 @@ _jit_classify_struct(jit_param_passing_t *passing,
 		}
 		if(arg_class == X86_64_ARG_INTEGER)
 		{
-			if(passing->word_index < passing->max_word_regs)
+#ifdef JIT_APPLY_ARG_REGISTERS_OVERLAP
+			int register_index = passing->word_index + passing->float_index;
+#else
+      int register_index = passing->word_index;
+#endif
+			if(register_index < passing->max_word_regs)
 			{
 				/* Set the arg class to the number of registers used */
 				param->arg_class = 1;
 
 				/* Set the first register to the register used */
-				param->un.reg_info[0].reg = passing->word_regs[passing->word_index];
+				param->un.reg_info[0].reg = passing->word_regs[register_index];
 				param->un.reg_info[0].value = param->value;
 				++(passing->word_index);
 			}
@@ -508,13 +513,18 @@ _jit_classify_struct(jit_param_passing_t *passing,
 		}
 		else if(arg_class == X86_64_ARG_SSE)
 		{
-			if(passing->float_index < passing->max_float_regs)
+#ifdef JIT_APPLY_ARG_REGISTERS_OVERLAP
+			int register_index = passing->word_index + passing->float_index;
+#else
+      int register_index = passing->float_index;
+#endif
+			if(register_index < passing->max_float_regs)
 			{
 				/* Set the arg class to the number of registers used */
 				param->arg_class = 1;
 
 				/* Set the first register to the register used */
-				param->un.reg_info[0].reg =	passing->float_regs[passing->float_index];
+				param->un.reg_info[0].reg =	passing->float_regs[register_index];
 				param->un.reg_info[0].value = param->value;
 				++(passing->float_index);
 			}
@@ -536,6 +546,7 @@ _jit_classify_struct(jit_param_passing_t *passing,
 			_jit_alloc_param_slot(passing, param, param_type);
 		}
 	}
+#ifdef JIT_APPLY_SPLIT_STRUCT_OVER_REGS
 	else if(size <= 16)
 	{
 		int arg_class1;
@@ -640,6 +651,7 @@ _jit_classify_struct(jit_param_passing_t *passing,
 			}
 		}
 	}
+#endif
 	else
 	{
 		/* Set the arg class to stack */
@@ -669,13 +681,18 @@ _jit_classify_param(jit_param_passing_t *passing,
 		{
 			case X86_64_ARG_INTEGER:
 			{
-				if(passing->word_index < passing->max_word_regs)
+#ifdef JIT_APPLY_ARG_REGISTERS_OVERLAP
+				int register_index = passing->word_index + passing->float_index;
+#else
+				int register_index = passing->word_index;
+#endif
+				if(register_index < passing->max_word_regs)
 				{
 					/* Set the arg class to the number of registers used */
 					param->arg_class = 1;
 
 					/* Set the first register to the register used */
-					param->un.reg_info[0].reg = passing->word_regs[passing->word_index];
+					param->un.reg_info[0].reg = passing->word_regs[register_index];
 					param->un.reg_info[0].value = param->value;
 					++(passing->word_index);
 				}
@@ -692,13 +709,18 @@ _jit_classify_param(jit_param_passing_t *passing,
 
 			case X86_64_ARG_SSE:
 			{
-				if(passing->float_index < passing->max_float_regs)
+#ifdef JIT_APPLY_ARG_REGISTERS_OVERLAP
+				int register_index = passing->word_index + passing->float_index;
+#else
+				int register_index = passing->float_index;
+#endif
+				if(register_index < passing->max_float_regs)
 				{
 					/* Set the arg class to the number of registers used */
 					param->arg_class = 1;
 
 					/* Set the first register to the register used */
-					param->un.reg_info[0].reg =	passing->float_regs[passing->float_index];
+					param->un.reg_info[0].reg =	passing->float_regs[register_index];
 					param->un.reg_info[0].value = param->value;
 					++(passing->float_index);
 				}
diff --git a/jit/jit-apply-x86-64.h b/jit/jit-apply-x86-64.h
index c2b452f..6138849 100644
--- a/jit/jit-apply-x86-64.h
+++ b/jit/jit-apply-x86-64.h
@@ -136,6 +136,9 @@ _jit_classify_struct(jit_param_passing_t *passing,
 
 #if defined(__GNUC__)
 
+#if !defined(__CYGWIN__) && !defined(__CYGWIN32__) && \
+	!defined(_WIN32) && !defined(WIN32)
+
 #ifndef	JIT_MEMCPY
 # if defined(__APPLE__) && defined(__MACH__)
 #  define JIT_MEMCPY "_jit_memcpy"
@@ -286,7 +289,278 @@ _jit_classify_struct(jit_param_passing_t *passing,
 		do { \
 		} while (0)
 
-#endif /* GNUC */
+#else /* Win64 */
+
+/*
+ * We have to add all registers not saved by the caller to the clobber list
+ * and not only the registers used for parameter passing because we call
+ * arbitrary functions.
+ * Maybe we should add the mmx* registers too?
+ */
+#define	jit_builtin_apply(func,args,size,return_float,return_buf)	\
+		do { \
+			void *__func = (void *)(func); \
+			void *__args = (void *)(args); \
+			jit_nint __size = (((jit_nint)(size) + (jit_nint)0xf) & ~(jit_nint)0xf); \
+			void *__return_buf = alloca(64); \
+			(return_buf) = __return_buf; \
+			__asm__ ( \
+				"movq %1, %%rax\n\t" \
+				"movq (%%rax), %%rdx\n\t" \
+				"movq %2, %%r8\n\t" \
+				"subq %%r8, %%rsp\n\t" \
+				"movq %%rsp, %%rcx\n\t" \
+				"callq _memcpy\n\t" \
+				"movq $0x20, %%rcx\n\t" \
+				"subq %%rcx, %%rsp\n\t" \
+				"movq %1, %%rax\n\t" \
+				"movq 0x08(%%rax), %%rcx\n\t" \
+				"movq 0x10(%%rax), %%rdx\n\t" \
+				"movq 0x18(%%rax), %%r8\n\t" \
+				"movq 0x20(%%rax), %%r9\n\t" \
+				"movaps 0x30(%%rax), %%xmm0\n\t" \
+				"movaps 0x40(%%rax), %%xmm1\n\t" \
+				"movaps 0x50(%%rax), %%xmm2\n\t" \
+				"movaps 0x60(%%rax), %%xmm3\n\t" \
+				"movq %0, %%r11\n\t" \
+				"callq *%%r11\n\t" \
+				"movq $0x20, %%rcx\n\t" \
+				"addq %%rcx, %%rsp\n\t" \
+				"movq %3, %%rcx\n\t" \
+				"movq %%rax, (%%rcx)\n\t" \
+				"movq %%rdx, 0x08(%%rcx)\n\t" \
+				"movaps %%xmm0, 0x10(%%rcx)\n\t" \
+				"movq %2, %%rcx\n\t" \
+				"addq %%rcx, %%rsp\n\t" \
+				: : "m"(__func), "m"(__args), "m"(__size), "m"(__return_buf) \
+				: "rax", "rcx", "rdx", "r8", "r9", \
+				  "r10", "r11", \
+				  "xmm0", "xmm1", "xmm2", "xmm3" \
+			); \
+			if((return_float)) \
+			{ \
+				__asm__ ( \
+					"movq %0, %%rax\n\t" \
+					"fstpt 0x20(%%rax)\n\t" \
+					: : "m"(__return_buf) \
+					: "rax", "st" \
+				); \
+			} \
+		} while (0)
+
+#define	jit_builtin_apply_args(type,args)	\
+		do { \
+			void *__args = alloca(192); \
+			__asm__ ( \
+				"pushq %%rdi\n\t" \
+				"leaq 16(%%rbp), %%rdi\n\t" \
+				"movq %0, %%rax\n\t" \
+				"movq %%rdi, (%%rax)\n\t" \
+				"popq %%rdi\n\t" \
+				"movq %%rdi, 0x08(%%rax)\n\t" \
+				"movq %%rsi, 0x10(%%rax)\n\t" \
+				"movq %%rdx, 0x18(%%rax)\n\t" \
+				"movq %%rcx, 0x20(%%rax)\n\t" \
+				"movq %%r8, 0x28(%%rax)\n\t" \
+				"movq %%r9, 0x30(%%rax)\n\t" \
+				"movaps %%xmm0, 0x40(%%rax)\n\t" \
+				"movaps %%xmm1, 0x50(%%rax)\n\t" \
+				"movaps %%xmm2, 0x60(%%rax)\n\t" \
+				"movaps %%xmm3, 0x70(%%rax)\n\t" \
+				"movaps %%xmm4, 0x80(%%rax)\n\t" \
+				"movaps %%xmm5, 0x90(%%rax)\n\t" \
+				"movaps %%xmm6, 0xA0(%%rax)\n\t" \
+				"movaps %%xmm7, 0xB0(%%rax)\n\t" \
+				: : "m"(__args) \
+				: "rax", "rcx", "rdx", "rdi", "rsi", "r8", "r9", \
+				  "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", \
+				  "xmm5", "xmm6", "xmm7" \
+			); \
+			(args) = (type)__args; \
+		} while (0)
+
+#define	jit_builtin_return_int(return_buf)	\
+		do { \
+			__asm__ ( \
+				"lea %0, %%rcx\n\t" \
+				"movq (%%rcx), %%rax\n\t" \
+				"movq 0x08(%%rcx), %%rdx\n\t" \
+				"movaps 0x10(%%rcx), %%xmm0\n\t" \
+				: : "m"(*(return_buf)) \
+				: "rax", "rcx", "rdx", "xmm0" \
+			); \
+			return; \
+		} while (0)
+
+#define	jit_builtin_return_float(return_buf)	\
+		do { \
+			__asm__ ( \
+				"lea %0, %%rcx\n\t" \
+				"movaps 0x10(%%rcx), %%xmm0\n\t" \
+				: : "m"(*(return_buf)) \
+				: "rcx", "xmm0", "st" \
+			); \
+			return; \
+		} while (0)
+
+#define	jit_builtin_return_double(return_buf)	\
+		do { \
+			__asm__ ( \
+				"lea %0, %%rcx\n\t" \
+				"movaps 0x10(%%rcx), %%xmm0\n\t" \
+				: : "m"(*(return_buf)) \
+				: "rcx", "xmm0", "st" \
+			); \
+			return; \
+		} while (0)
+
+#define	jit_builtin_return_nfloat(return_buf)	\
+		do { \
+			__asm__ ( \
+				"lea %0, %%rcx\n\t" \
+				"fldt 0x20(%%rcx)\n\t" \
+				: : "m"(*(return_buf)) \
+				: "rcx", "xmm0", "st" \
+			); \
+			return; \
+		} while (0)
+
+#define jit_builtin_return_struct(return_buf, type) \
+		do { \
+		} while (0)
+    
+#endif /* Win32 */
+
+#elif defined(_MSC_VER)
+
+#define	jit_builtin_apply(func,args,size,return_float,return_buf)	\
+		do { \
+			void *__func = (void *)(func); \
+			void *__args = (void *)(args); \
+			void *__size = (((long)(size) + (long)0xf) & ~(long)0xf); \
+			void *__return_buf = alloca(64); \
+			(return_buf) = __return_buf; \
+			__asm { \
+				__asm movq rax, ptr __size \
+				__asm movq rsi, [rax] \
+				__asm movq rdx, ptr __args \
+				__asm subq rsp, rdx \
+				__asm movq rdi, rsp \
+				__asm callq jit_memcpy \
+				__asm movq rax, ptr __args \
+				__asm movq rdi, [rax + 0x08] \
+				__asm movq rsi, [rax + 0x10] \
+				__asm movq rdx, [rax + 0x18] \
+				__asm movq rcx, [rax + 0x20] \
+				__asm movq r8, [rax + 0x28] \
+				__asm movq r9, [rax + 0x30] \
+				__asm movaps xmm0, [rax + 0x40] \
+				__asm movaps xmm1, [rax + 0x50] \
+				__asm movaps xmm2, [rax + 0x60] \
+				__asm movaps xmm3, [rax + 0x70] \
+				__asm movaps xmm4, [rax + 0x80] \
+				__asm movaps xmm5, [rax + 0x90] \
+				__asm movaps xmm6, [rax + 0xA0] \
+				__asm movaps xmm7, [rax + 0xB0] \
+				__asm movq r11, ptr __func \
+				__asm movl eax, 8 \
+				__asm callq r11 \
+				__asm movq rcx, ptr __return_buf \
+				__asm movq [rcx], rax \
+				__asm movq [rcx +0x08], rdx \
+				__asm movaps [rcx +0x10], xmm0 \
+				__asm movq rdx, ptr __size \
+				__asm addq rsp, rdx \
+			} \
+			if((return_float)) \
+			{ \
+				__asm { \
+          /* \
+					__asm mov ecx, dword ptr __return_buf \
+					__asm fstpl [ecx + 8] \
+					__asm _emit 0xDD \
+					__asm _emit 0x59 \
+					__asm _emit 0x08 \
+          */ \
+					__asm movq rax, ptr __return_buf \
+					__asm fstpt [rax + 0x20] \
+				} \
+			} \
+		} while (0)
+
+#define	jit_builtin_apply_args(type,args)	\
+		do { \
+			void *__args = alloca(192); \
+			__asm { \
+				__asm pushq rdi \
+				__asm leaq rdi, [rbp + 16] \
+				__asm movq rax, ptr __args \
+				__asm movq [rax], rdi \
+				__asm popq rdi \
+				__asm movq [rax + 0x08], rdi \
+				__asm movq [rax + 0x10], rsi \
+				__asm movq [rax + 0x18], rdx \
+				__asm movq [rax + 0x20], rcx \
+				__asm movq [rax + 0x28], r8 \
+				__asm movq [rax + 0x30], r9 \
+				__asm movaps [rax + 0x40], xmm0 \
+				__asm movaps [rax + 0x50], xmm1 \
+				__asm movaps [rax + 0x60], xmm2 \
+				__asm movaps [rax + 0x70], xmm3 \
+				__asm movaps [rax + 0x80], xmm4 \
+				__asm movaps [rax + 0x90], xmm5 \
+				__asm movaps [rax + 0xA0], xmm6 \
+				__asm movaps [rax + 0xB0], xmm7 \
+			} \
+			(args) = (type)(__args); \
+		} while (0)
+
+#define	jit_builtin_return_int(return_buf)	\
+		do { \
+			void *__return_buf = (void *)(return_buf); \
+			__asm { \
+				__asm lea rcx, ptr __return_buf \
+				__asm movq rax, [rcx] \
+				__asm movq rdx, [rcx + 0x08] \
+				__asm movaps xmm0, [rcx + 0x10] \
+			} \
+			return; \
+		} while (0)
+
+#define	jit_builtin_return_float(return_buf)	\
+		do { \
+			void *__return_buf = (void *)(return_buf); \
+			__asm { \
+				__asm lea rcx, ptr __return_buf \
+				__asm movaps xmm0, [rcx + 0x10] \
+			} \
+			return; \
+		} while (0)
+
+#define	jit_builtin_return_double(return_buf)	\
+		do { \
+			void *__return_buf = (void *)(return_buf); \
+			__asm__ ( \
+				__asm lea rcx, ptr __return_buf \
+				__asm movaps xmm0, [rcx + 0x10] \
+			} \
+			return; \
+		} while (0)
+
+#define	jit_builtin_return_nfloat(return_buf)	\
+		do { \
+			__asm { \
+				__asm lea rcx, ptr __return_buf \
+				__asm fldt [rcx + 0x20] \
+			} \
+			return; \
+		} while (0)
+
+#define jit_builtin_return_struct(return_buf, type) \
+		do { \
+		} while (0)
+
+#endif /* MSC_VER */
 
 /*
  * The maximum number of bytes that are needed to represent a closure,
diff --git a/jit/jit-cache.c b/jit/jit-cache.c
index 0f01485..cb176fa 100644
--- a/jit/jit-cache.c
+++ b/jit/jit-cache.c
@@ -32,6 +32,23 @@ See the bottom of this file for documentation on the cache system.
 extern	"C" {
 #endif
 
+/* #define RED_BLACK_DEBUG */
+/* #define RED_BLACK_DUMP */
+
+#ifdef RED_BLACK_DEBUG
+#define CHECKTREE(reason) RB_DEBUG(OutputDebugString(reason)); CheckLookupTreeValidity(cache)
+#else
+#define CHECKTREE(reason)
+#endif
+
+#ifdef RED_BLACK_DUMP
+#define RB_DEBUG(cmd) cmd
+#define DUMPLOOKUPTREE(dumpreason, highlight) DumpLookupTree(cache, dumpreason, highlight)
+#else
+#define RB_DEBUG(cmd)
+#define DUMPLOOKUPTREE(dumpreason, highlight)
+#endif
+
 /*
  * Tune the default size of a cache page.  Memory is allocated from
  * the system in chunks of this size.
@@ -71,11 +88,18 @@ struct jit_cache_method
 {
 	void			*method;	/* Method containing the region */
 	void			*cookie;	/* Cookie value for the region */
+	unsigned char		*allocated;	/* Allocated code memory for this method. */
 	unsigned char		*start;		/* Start of the region */
 	unsigned char		*end;		/* End of the region */
 	jit_cache_debug_t	debug;		/* Debug information for method */
-	jit_cache_method_t	left;		/* Left sub-tree and red/black bit */
-	jit_cache_method_t	right;		/* Right sub-tree */
+	union
+	{
+		jit_cache_method_t	link[2];
+		struct {
+			jit_cache_method_t	left;		/* Left sub-tree and red/black bit */
+			jit_cache_method_t	right;		/* Right sub-tree */
+		} lr;
+	};
 
 };
 
@@ -111,6 +135,12 @@ struct jit_cache
 	jit_cache_debug_t	firstDebug;	/* First debug block for method */
 	jit_cache_debug_t	lastDebug;	/* Last debug block for method */
 
+	/* plugable memmory management functions */
+	jit_malloc_code_func	malloc_code_func;
+	jit_resize_code_func	resize_code_func;
+	jit_free_code_func	free_code_func;
+	jit_malloc_func		malloc_func;
+	jit_free_func		free_func;
 };
 
 /*
@@ -382,24 +412,30 @@ static void AllocCachePage(jit_cache_t cache, int factor)
  * Get or set the sub-trees of a node.
  */
 #define	GetLeft(node)	\
-	((jit_cache_method_t)(((jit_nuint)((node)->left)) & ~((jit_nuint)1)))
-#define	GetRight(node)	((node)->right)
+	((jit_cache_method_t)(((jit_nuint)((node)->lr.left)) & ~((jit_nuint)1)))
+#define	GetRight(node)	((node)->lr.right)
 #define	SetLeft(node,value)	\
-	((node)->left = (jit_cache_method_t)(((jit_nuint)(value)) | \
-						(((jit_nuint)((node)->left)) & ((jit_nuint)1))))
+	((node)->lr.left = (jit_cache_method_t)(((jit_nuint)(value)) | \
+						(((jit_nuint)((node)->lr.left)) & ((jit_nuint)1))))
 #define	SetRight(node,value)	\
-			((node)->right = (value))
+			((node)->lr.right = (value))
+/* Code using indexed getters / setters can make use of the symetry of the tree algorithm. */
+#define GetIndex(node, index) \
+	((jit_cache_method_t)(((jit_nuint)((node)->link[index])) & ~((jit_nuint)1)))
+#define SetIndex(node, index, value) \
+	((node)->link[index] = (jit_cache_method_t)(((jit_nuint)(value)) | \
+						(((jit_nuint)((node)->link[index])) & ((jit_nuint)1))))
 
 /*
  * Get or set the red/black state of a node.
  */
 #define	GetRed(node)	\
-	((((jit_nuint)((node)->left)) & ((jit_nuint)1)) != 0)
+	((((jit_nuint)((node)->lr.left)) & ((jit_nuint)1)) != 0)
 #define	SetRed(node)	\
-	((node)->left = (jit_cache_method_t)(((jit_nuint)((node)->left)) | \
+	((node)->lr.left = (jit_cache_method_t)(((jit_nuint)((node)->lr.left)) | \
 									     ((jit_nuint)1)))
 #define	SetBlack(node)	\
-	((node)->left = (jit_cache_method_t)(((jit_nuint)((node)->left)) & \
+	((node)->lr.left = (jit_cache_method_t)(((jit_nuint)((node)->lr.left)) & \
 									    ~((jit_nuint)1)))
 
 /*
@@ -431,45 +467,171 @@ static int CacheCompare(jit_cache_t cache, unsigned char *key,
 	}
 }
 
+#ifdef RED_BLACK_DEBUG
+
+#include <stdio.h>
+
+void debugprintf(const unsigned char * format, ...)
+{
+	va_list argptr;
+	unsigned char buffer[1024];
+
+	va_start( argptr, format );
+	vsnprintf(buffer, sizeof(buffer)-1, format, argptr);
+	buffer[1023]='\0';
+	OutputDebugString(buffer);
+	va_end( argptr );
+}
 /*
- * Rotate a sub-tree around a specific node.
+ * Debug only: Check the validity of the red black tree.
  */
-static jit_cache_method_t CacheRotate(jit_cache_t cache, unsigned char *key,
-								      jit_cache_method_t around)
+int _CheckLookupTreeValidity_r(jit_cache_t cache, jit_cache_method_t node)
 {
-	jit_cache_method_t child, grandChild;
-	int setOnLeft;
-	if(CacheCompare(cache, key, around) < 0)
+	int lh;
+	int rh;
+	jit_cache_method_t nil = &(cache->nil);
+
+	if ( node == nil)
 	{
-		child = GetLeft(around);
-		setOnLeft = 1;
+		return 1;
 	}
-	else
+	else 
 	{
-		child = GetRight(around);
-		setOnLeft = 0;
+		jit_cache_method_t ln = GetLeft(node);
+		jit_cache_method_t rn = GetRight(node);
+
+		/* Consecutive red links */
+		if ( GetRed(node) ) 
+		{
+			if ( GetRed(ln) || GetRed(rn) ) 
+			{
+				OutputDebugString( "Red violation\n" );
+				return 0;
+			}
+		}
+
+		lh =  _CheckLookupTreeValidity_r(cache, ln);
+		rh =  _CheckLookupTreeValidity_r(cache, rn);
+
+		/* Invalid binary search tree */
+		if ( (ln != nil && CacheCompare(cache, node->start, ln) <= 0) || (rn != nil && CacheCompare(cache, node->start, rn) >= 0) )
+		{
+			OutputDebugString( "Binary tree violation\n" );
+			return 0;
+		}
+
+		/* Black height mismatch */
+		if ( lh != 0 && rh != 0 && lh != rh )
+		{
+			OutputDebugString("Black violation\n" );
+			return 0;
+		}
+
+		/* Only count black links */
+		if ( lh != 0 && rh != 0 )
+		{
+			return GetRed(node) ? lh : lh + 1;
+		}
+		else
+		{
+			return 0;
+		}
 	}
-	if(CacheCompare(cache, key, child) < 0)
+}
+
+void CheckLookupTreeValidity(jit_cache_t cache)
+{
+	int result;
+	
+	result = _CheckLookupTreeValidity_r(cache, GetRight(&cache->head));
+	if ( result )
 	{
-		grandChild = GetLeft(child);
-		SetLeft(child, GetRight(grandChild));
-		SetRight(grandChild, child);
+		RB_DEBUG(OutputDebugString("Tree OK.\n"));
 	}
 	else
 	{
-		grandChild = GetRight(child);
-		SetRight(child, GetLeft(grandChild));
-		SetLeft(grandChild, child);
+		DebugBreak();
+	}
+}
+
+/*
+ * Dump the lookup tree in a format that can be read by graphviz (http://www.graphviz.org)
+ */
+
+int dumpcount = 0;
+ 
+void _DumpLookupTree_r(jit_cache_t cache, jit_cache_method_t node, jit_cache_method_t highlight)
+{
+	jit_cache_method_t nil = &(cache->nil);
+
+	if ( node == nil)
+	{
+		return;
 	}
-	if(setOnLeft)
+	
+	jit_cache_method_t ln = GetLeft(node);
+	jit_cache_method_t rn = GetRight(node);
+
+	debugprintf("\t\tg%d%08lx [label = \"<f0> |<f1> %08lx|<f2> \"%s%s];\n", dumpcount, node->start, node->start,
+		GetRed(node) ? ", fillcolor=lightpink, style=filled" : "",
+		node == highlight ? ", color=red, penwidth=2" : ""
+	);
+	if ( ln != nil )
 	{
-		SetLeft(around, grandChild);
+		debugprintf("\t\tg%d%08lx:f0 -> g%d%08lx:f1 [color=%s%s];\n", dumpcount, node->start, dumpcount, ln->start, 
+			(node == highlight || ln == highlight) ? "red, penwidth=2" : "black",
+			GetRed(node) == GetRed(ln) ? ", minlen=2":"");
 	}
-	else
+	if ( rn != nil )
 	{
-		SetRight(around, grandChild);
+		debugprintf("\t\tg%d%08lx:f2 -> g%d%08lx:f1 [color=%s%s];\n", dumpcount, node->start, dumpcount, rn->start,
+			(node == highlight || rn == highlight) ? "red, penwidth=2" : "black",
+			GetRed(node) == GetRed(rn) ? ", minlen=2":""
+		);
 	}
-	return grandChild;
+	
+	_DumpLookupTree_r(cache, ln, highlight);
+	_DumpLookupTree_r(cache, rn, highlight);
+}
+
+void DumpLookupTree(jit_cache_t cache, char* dumpReason, jit_cache_method_t highlight)
+{
+	//debugprintf("DumpLookupTree, head = $%08lx, nil = $%08lx\n", &cache->head, &(cache->nil));
+	debugprintf("digraph G {\n");
+	debugprintf("\tgraph [dpi=100];\n");
+	debugprintf("\tnode [shape=record, fontsize=12, fontname=\"helvetica\"];\n");
+	debugprintf("\tsubgraph cluster%d\n\t{\n", dumpcount);
+	debugprintf("\t\tlabel=\"%s\"\n", dumpReason);
+	_DumpLookupTree_r(cache, GetRight(&cache->head), highlight);
+	debugprintf("\t}\n}\n", &cache->head, &(cache->nil));
+	dumpcount++;
+}
+
+#endif
+
+/*
+ * Rotate a sub-tree around a specific node.
+ */
+static jit_cache_method_t Rotate(jit_cache_method_t node, int dir)
+{
+	jit_cache_method_t save = GetIndex(node, !dir);
+	SetIndex(node, !dir, GetIndex(save, dir));
+	SetIndex(save, dir, node);
+	SetRed(node);
+	SetBlack(save);
+	return save;
+}
+ 
+static jit_cache_method_t CacheRotate(jit_cache_t cache, unsigned char *key,
+								      jit_cache_method_t around)
+{
+	jit_cache_method_t child, result;
+	int dir = CacheCompare(cache, key, around) > 0;
+
+	child = GetIndex(around, dir);
+	result = Rotate(child, CacheCompare(cache, key, child) < 0);
+	SetIndex(around, dir, result);
+	return result;
 }
 
 /*
@@ -544,8 +706,8 @@ static void AddToLookupTree(jit_cache_t cache, jit_cache_method_t method)
 	}
 
 	/* Insert the new node into the current position */
-	method->left = (jit_cache_method_t)(((jit_nuint)nil) | ((jit_nuint)1));
-	method->right = nil;
+	method->lr.left = (jit_cache_method_t)(((jit_nuint)nil) | ((jit_nuint)1));
+	method->lr.right = nil;
 	if(CacheCompare(cache, key, parent) < 0)
 	{
 		SetLeft(parent, method);
@@ -555,7 +717,134 @@ static void AddToLookupTree(jit_cache_t cache, jit_cache_method_t method)
 		SetRight(parent, method);
 	}
 	Split();
-	SetBlack(cache->head.right);
+	SetBlack(cache->head.lr.right);
+
+	CHECKTREE("After AddToLookupTree check... ");
+}
+
+/*
+ * Remove a method region block from the red-black lookup tree
+ * that is associated with a method cache.
+ * Algorithm loosely based on the information / code found at:
+ * http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx
+ */
+static void RemoveFromLookupTree(jit_cache_t cache, jit_cache_method_t method)
+{
+	unsigned char *key = method->start;
+	jit_cache_method_t temp;
+	jit_cache_method_t grandParent;
+	jit_cache_method_t parent;
+	jit_cache_method_t found = NULL;
+	jit_cache_method_t saved;
+	jit_cache_method_t nil = &(cache->nil);
+	int dir = 1;
+	int dir2;
+	int last;
+
+	temp = &(cache->head);
+	grandParent = temp;
+	parent = temp;
+	
+	/* Search while pushing a red node down our search path. */
+	RB_DEBUG(char dumpreason[64]; sprintf(dumpreason, "remove %08lx", (unsigned long)method->start));
+	DUMPLOOKUPTREE(dumpreason, method);
+	while( GetIndex(temp, dir) != nil)
+	{
+		/* Adjust our ancestor pointers */
+		grandParent = parent;
+		parent = temp;
+		temp = GetIndex(temp, dir);
+		last = dir;
+		dir = CacheCompare(cache, key, temp) > 0;
+
+		if(temp == method)
+		{
+			found = temp;
+		}
+
+		/* See if there's a red node in the direction we go. If not, push it down. */
+		if ( !GetRed(temp) && !GetRed( GetIndex(temp, dir) ) )
+		{
+			if ( GetRed( GetIndex(temp, !dir) ) )
+			{
+				RB_DEBUG(sprintf(dumpreason, "rotate under parent %08lx %d", (unsigned long)parent->start, dir));
+				SetIndex(parent, last, Rotate(temp, dir));
+				parent = GetIndex(parent, last);
+				DUMPLOOKUPTREE(dumpreason, parent);
+			}
+			else
+			{
+				saved = GetIndex(parent, !last);
+				if ( saved != nil )
+				{
+					if ( !GetRed(GetLeft(saved) ) && !GetRed(GetRight(saved)) )
+					{
+						/* Simply invert the colors */
+						SetBlack(parent);
+						SetRed(saved);
+						SetRed(temp);
+						DUMPLOOKUPTREE("swap colors", parent);
+					}
+					else
+					{
+						dir2 = GetRight(grandParent) == parent;
+
+						if ( GetRed(GetIndex(saved, last)) )
+						{
+							SetIndex(parent, !last, Rotate(GetIndex(parent, !last), !last));
+							RB_DEBUG(sprintf(dumpreason, "1) rotate under parent %08lx %d", (unsigned long)parent->start, last));
+							DUMPLOOKUPTREE(dumpreason, parent);
+							SetIndex(grandParent, dir2, Rotate(parent, last));
+							RB_DEBUG(sprintf(dumpreason, "2) rotate under grandparent %08lx %d", (unsigned long)grandParent->start, last));
+							DUMPLOOKUPTREE(dumpreason, grandParent);
+						}
+						else if ( GetRed(GetIndex(saved, !last)) )
+						{
+							SetIndex(grandParent, dir2, Rotate(parent, last));
+							RB_DEBUG(sprintf(dumpreason, "rotate under grandparent %08lx %d", (unsigned long)grandParent->start, last));
+							DUMPLOOKUPTREE(dumpreason, grandParent);
+						}
+
+						/* Make sure the coloring is correct */
+						SetRed(temp);
+						SetRed(GetIndex(grandParent, dir2));
+						SetBlack(GetLeft(GetIndex(grandParent, dir2)));
+						SetBlack(GetRight(GetIndex(grandParent, dir2)));
+						DUMPLOOKUPTREE("restore coloring", grandParent);
+					}
+				}
+			}
+			/* CHECKTREE("After 1 delete step..."); */
+		}
+	}
+
+	/* Do the actual switch & delete. */
+	if ( found != NULL ) 
+	{
+		if ( found != temp )
+		{
+			found->method = temp->method;
+			found->cookie = temp->cookie;
+			found->allocated = temp->allocated;
+			found->start = temp->start;
+			found->end = temp->end;
+			found->debug = temp->debug;
+		}
+		/* Give our parent the one and only link we had. */
+		SetIndex(parent,(GetRight(parent) == temp), GetIndex(temp, GetLeft(temp) == nil));
+		_jit_cache_free(cache, temp);
+	}
+	else
+	{
+		RB_DEBUG(debugprintf("RB node not found!\n"));
+		RB_DEBUG(DebugBreak(););
+	}
+
+	/* Make sure the root is black. */
+	SetBlack(GetRight(&cache->head));
+
+	DUMPLOOKUPTREE("Delete done", found);
+	CHECKTREE("After RemoveFromLookupTree check... ");
 }
 
 /*
@@ -565,7 +854,7 @@ static void FlushCacheDebug(jit_cache_posn *posn)
 {
 	jit_cache_t cache = posn->cache;
 	jit_cache_debug_t debug;
-
+	
 	/* Allocate a new jit_cache_debug structure to hold the data */
 	debug = _jit_cache_alloc(posn,
 		(unsigned long)(sizeof(struct jit_cache_debug) + cache->debugLen));
@@ -618,7 +907,15 @@ static void WriteCacheDebug(jit_cache_posn *posn, long offset, long nativeOffset
 	}
 }
 
-jit_cache_t _jit_cache_create(long limit, long cache_page_size, int max_page_factor)
+int _jit_cache_has_custom_allocator(jit_cache_t cache)
+{
+	return cache->malloc_code_func != 0;
+}
+
+jit_cache_t _jit_cache_create(long limit, long cache_page_size, int max_page_factor, 
+			      jit_malloc_code_func malloc_code_func, jit_resize_code_func resize_code_func, jit_free_code_func free_code_func,
+			      jit_malloc_func malloc_func, jit_free_func free_func
+			     )
 {
 	jit_cache_t cache;
 	unsigned long exec_page_size;
@@ -629,6 +926,13 @@ jit_cache_t _jit_cache_create(long limit, long cache_page_size, int max_page_fac
 		return 0;
 	}
 
+	/* Set optional external allocator callbacks. */
+	cache->malloc_code_func = malloc_code_func;
+	cache->resize_code_func	= resize_code_func;
+	cache->free_code_func	= free_code_func;
+	cache->malloc_func 	= malloc_func;
+	cache->free_func	= free_func;
+
 	/* determine the default cache page size */
 	exec_page_size = jit_exec_page_size();
 	if(cache_page_size <= 0)
@@ -676,26 +980,29 @@ jit_cache_t _jit_cache_create(long limit, long cache_page_size, int max_page_fac
 	cache->nil.start = 0;
 	cache->nil.end = 0;
 	cache->nil.debug = 0;
-	cache->nil.left = &(cache->nil);
-	cache->nil.right = &(cache->nil);
+	cache->nil.lr.left = &(cache->nil);
+	cache->nil.lr.right = &(cache->nil);
 	cache->head.method = 0;
 	cache->head.cookie = 0;
 	cache->head.start = 0;
 	cache->head.end = 0;
 	cache->head.debug = 0;
-	cache->head.left = 0;
-	cache->head.right = &(cache->nil);
+	cache->head.lr.left = &(cache->nil);;
+	cache->head.lr.right = &(cache->nil);
 	cache->start = 0;
 	cache->debugLen = 0;
 	cache->firstDebug = 0;
 	cache->lastDebug = 0;
 
-	/* Allocate the initial cache page */
-	AllocCachePage(cache, 0);
-	if(!cache->freeStart)
+	if ( !_jit_cache_has_custom_allocator(cache) )
 	{
-		_jit_cache_destroy(cache);
-		return 0;
+		/* Allocate the initial cache page */
+		AllocCachePage(cache, 0);
+		if(!cache->freeStart)
+		{
+			_jit_cache_destroy(cache);
+			return 0;
+		}
 	}
 
 	/* Ready to go */
@@ -737,18 +1044,42 @@ _jit_cache_check_space(jit_cache_posn *posn, int space)
 	}
 }
 
+_jit_cache_free_debug(jit_cache_t cache, jit_cache_debug_t debug)
+{
+	jit_cache_debug_t nextdebug;
+
+	while ( debug )
+	{
+		nextdebug = debug->next;
+		_jit_cache_free(cache, debug);
+		debug = nextdebug;
+	}
+}
+
 int _jit_cache_start_method(jit_cache_t cache,
 			    jit_cache_posn *posn,
 			    int page_factor,
 			    int align,
+			    unsigned long predicted_size,
 			    void *method)
 {
+	unsigned char *allocated = NULL;
 	unsigned char *ptr;
+	unsigned long actual_size;
 
-	/* Do we need to allocate a new cache page? */
-	if(page_factor > 0)
+	if ( _jit_cache_has_custom_allocator(cache) )
 	{
-		AllocCachePage(cache, page_factor);
+		allocated = (*cache->malloc_code_func)(predicted_size, &actual_size);
+		cache->freeStart = allocated;
+		cache->freeEnd = cache->freeStart + actual_size;
+	}
+	else
+	{	
+		/* Do we need to allocate a new cache page? */
+		if(page_factor > 0)
+		{
+			AllocCachePage(cache, page_factor);
+		}
 	}
 
 	/* Bail out if the cache is already full */
@@ -756,7 +1087,7 @@ int _jit_cache_start_method(jit_cache_t cache,
 	{
 		return JIT_CACHE_TOO_BIG;
 	}
-
+	
 	/* Set up the initial cache position */
 	posn->cache = cache;
 	posn->ptr = cache->freeStart;
@@ -791,11 +1122,12 @@ int _jit_cache_start_method(jit_cache_t cache,
 	}
 	cache->method->method = method;
 	cache->method->cookie = 0;
+	cache->method->allocated = allocated;
 	cache->method->start = posn->ptr;
 	cache->method->end = posn->ptr;
 	cache->method->debug = 0;
-	cache->method->left = 0;
-	cache->method->right = 0;
+	cache->method->lr.left = 0;
+	cache->method->lr.right = 0;
 
 	/* Store the method start address */
 	cache->start = posn->ptr;
@@ -814,25 +1146,44 @@ int _jit_cache_end_method(jit_cache_posn *posn)
 	jit_cache_method_t method;
 	jit_cache_method_t next;
 
+	method = cache->method;
+	
 	/* Determine if we ran out of space while writing the method */
 	if(posn->ptr >= posn->limit)
 	{
 		/* If we had a newly allocated page then it has to be freed
 		   to let allocate another new page of appropriate size. */
-		if((cache->freeStart == ((unsigned char *)(cache->pages[cache->numPages - 1].page)))
-		    && (cache->freeEnd
-			== (cache->freeStart + (cache->pageSize * cache->pages[cache->numPages - 1].factor))))
+		if ( _jit_cache_has_custom_allocator(cache) )
 		{
-			--(cache->numPages);
-			jit_free_exec(cache->pages[cache->numPages].page,
-				      cache->pageSize * cache->pages[cache->numPages].factor);
-			if (cache->pagesLeft >= 0)
+			_jit_cache_free_debug(cache, method->debug);
+			while ( method )
 			{
-				cache->pagesLeft += cache->pages[cache->numPages].factor;
+				_jit_cache_free_code(cache, method->allocated);
+				next = method->lr.right;
+				_jit_cache_free(cache, method);
+				method = next;
 			}
 			cache->freeStart = 0;
 			cache->freeEnd = 0;
 		}
+		else
+		{
+			if((cache->freeStart == ((unsigned char *)(cache->pages[cache->numPages - 1].page)))
+			    && (cache->freeEnd
+				== (cache->freeStart + (cache->pageSize * cache->pages[cache->numPages - 1].factor))))
+			{
+				--(cache->numPages);
+				jit_free_exec(cache->pages[cache->numPages].page,
+					      cache->pageSize * cache->pages[cache->numPages].factor);
+				if (cache->pagesLeft >= 0)
+				{
+					cache->pagesLeft += cache->pages[cache->numPages].factor;
+				}
+				cache->freeStart = 0;
+				cache->freeEnd = 0;
+			}
+		}
+		cache->method = 0;
 		return JIT_CACHE_RESTART;
 	}
 
@@ -847,19 +1198,27 @@ int _jit_cache_end_method(jit_cache_posn *posn)
 	}
 
 	/* Flush the position information back to the cache */
-	cache->freeStart = posn->ptr;
-	cache->freeEnd = posn->limit;
+	if ( _jit_cache_has_custom_allocator(cache) )
+	{
+		(*cache->resize_code_func)(cache->freeStart, posn->ptr - cache->freeStart);
+		cache->freeStart = 0;
+		cache->freeEnd = 0;
+	}
+	else
+	{
+		cache->freeStart = posn->ptr;
+		cache->freeEnd = posn->limit;
+	}
 
 	/* Update the last method region block and then
 	   add all method regions to the lookup tree */
-	method = cache->method;
 	if(method)
 	{
 		method->end = posn->ptr;
 		do
 		{
 			method->debug = cache->firstDebug;
-			next = method->right;
+			next = method->lr.right;
 			AddToLookupTree(cache, method);
 			method = next;
 		}
@@ -871,10 +1230,82 @@ int _jit_cache_end_method(jit_cache_posn *posn)
 	return JIT_CACHE_OK;
 }
 
+jit_cache_method_t _jit_cache_get_node(jit_cache_t cache, void *pc)
+{
+	jit_cache_method_t node = cache->head.lr.right;
+	while(node != &(cache->nil))
+	{
+		if(((unsigned char *)pc) < node->start)
+		{
+			node = GetLeft(node);
+		}
+		else if(((unsigned char *)pc) >= node->end)
+		{
+			node = GetRight(node);
+		}
+		else
+		{
+			return node;
+		}
+	}
+	return 0;
+}
+
+/* Initially, call with NULL method. The recursion will fill it. */
+void _jit_cache_free_method_r(jit_cache_t cache, void *entry_point, void* method)
+{
+	jit_cache_method_t node;
+
+	/* Check if we support freeing of methods. */
+	if ( !_jit_cache_has_custom_allocator(cache) )
+	{
+		return;
+	}
+
+	node = _jit_cache_get_node(cache, entry_point);
+	
+	if (node)
+	{
+		if ( method == NULL )
+		{
+			method = node->method;
+
+			/* First time, free the debug information */
+			_jit_cache_free_debug(cache, node->debug);
+		}
+
+		if ( method == node->method )
+		{
+			entry_point = node->end;
+
+			/* Free allocated code memory */
+			_jit_cache_free_code(cache, node->allocated);
+
+			/* Remove the node from the tree. This will also free the node. */
+			RemoveFromLookupTree(cache, node);
+
+			/* We are continues, so free the (optional) next parts of this method... */
+			_jit_cache_free_method_r(cache, entry_point, method);
+		}
+	}
+}
+
+void _jit_cache_free_method(jit_cache_t cache, void *entry_point)
+{
+	 _jit_cache_free_method_r(cache, entry_point, NULL);
+}
+
 void *_jit_cache_alloc(jit_cache_posn *posn, unsigned long size)
 {
+	jit_cache_t cache = posn->cache;
 	unsigned char *ptr;
 
+	/* Use the custom allocator, if provided. */
+	if ( _jit_cache_has_custom_allocator(cache) )
+	{
+		return (*cache->malloc_func)(size);
+	}
+	
 	/* Bail out if the request is too big to ever be satisfiable */
 	if(size > (unsigned long)(posn->limit - posn->ptr))
 	{
@@ -904,6 +1335,12 @@ void *_jit_cache_alloc_no_method
 {
 	unsigned char *ptr;
 
+	/* Use the custom allocator, if provided. */
+	if ( _jit_cache_has_custom_allocator(cache) )
+	{
+		return (*cache->malloc_func)(size);
+	}
+	
 	/* Bail out if the request is too big to ever be satisfiable */
 	if(size > (unsigned long)(cache->freeEnd - cache->freeStart))
 	{
@@ -930,6 +1367,40 @@ void *_jit_cache_alloc_no_method
 	return (void *)ptr;
 }
 
+void _jit_cache_free(jit_cache_t cache, void *data)
+{
+	/* Only in case of an external allocator. We don't free. */
+	if ( _jit_cache_has_custom_allocator(cache) )
+	{
+		(*cache->free_func)(data);
+	}
+}
+
+void *_jit_cache_alloc_code(jit_cache_t cache, unsigned long size)
+{
+	unsigned long realsize;
+	void* result;
+	if ( _jit_cache_has_custom_allocator(cache) )
+	{
+		result = (*cache->malloc_code_func)(size, &realsize);
+		(*cache->resize_code_func)(result, size);
+		return result;
+	}
+	else
+	{
+		return _jit_cache_alloc_no_method(cache, size, 1);
+	}
+}
+
+void _jit_cache_free_code(jit_cache_t cache, void *data)
+{
+	/* Only in case of an external allocator. We don't free. */
+	if ( _jit_cache_has_custom_allocator(cache) )
+	{
+		(*cache->free_code_func)(data);
+	}
+}
+
 void _jit_cache_align(jit_cache_posn *posn, int align, int diff, int nop)
 {
 	jit_nuint current;
@@ -1005,12 +1476,13 @@ void _jit_cache_new_region(jit_cache_posn *posn, void *cookie)
 	}
 	newMethod->method = method->method;
 	newMethod->cookie = cookie;
+	newMethod->allocated = NULL;
 	newMethod->start = posn->ptr;
 	newMethod->end = posn->ptr;
 
 	/* Attach the new region to the cache */
-	newMethod->left = 0;
-	newMethod->right = method;
+	newMethod->lr.left = 0;
+	newMethod->lr.right = method;
 	posn->cache->method = newMethod;
 }
 
@@ -1024,25 +1496,14 @@ void _jit_cache_set_cookie(jit_cache_posn *posn, void *cookie)
 
 void *_jit_cache_get_method(jit_cache_t cache, void *pc, void **cookie)
 {
-	jit_cache_method_t node = cache->head.right;
-	while(node != &(cache->nil))
+	jit_cache_method_t node = _jit_cache_get_node(cache, pc);
+	if (node)
 	{
-		if(((unsigned char *)pc) < node->start)
-		{
-			node = GetLeft(node);
-		}
-		else if(((unsigned char *)pc) >= node->end)
+		if(cookie)
 		{
-			node = GetRight(node);
-		}
-		else
-		{
-			if(cookie)
-			{
-				*cookie = node->cookie;
-			}
-			return node->method;
+			*cookie = node->cookie;
 		}
+		return node->method;
 	}
 	return 0;
 }
@@ -1088,21 +1549,10 @@ static int add_parent(jit_cache_method_t *parent_buf,
 void *_jit_cache_get_start_method(jit_cache_t cache, void *pc)
 {
 	/* TODO: This function is not currently aware of multiple regions. */
-	jit_cache_method_t node = cache->head.right;
-	while(node != &(cache->nil))
+	jit_cache_method_t node = _jit_cache_get_node(cache, pc);
+	if (node)
 	{
-		if(((unsigned char *)pc) < node->start)
-		{
-			node = GetLeft(node);
-		}
-		else if(((unsigned char *)pc) >= node->end)
-		{
-			node = GetRight(node);
-		}
-		else
-		{
-			return node->start;
-		}
+		return node->start;
 	}
 	return 0;
 }
@@ -1113,7 +1563,7 @@ void *_jit_cache_get_end_method(jit_cache_t cache, void *pc)
 	jit_cache_method_t *parents = parent_buf;
 	int num_parents = 0;
 	int max_parents = 16;
-	jit_cache_method_t node = cache->head.right;
+	jit_cache_method_t node = cache->head.lr.right;
 	jit_cache_method_t last;
 	jit_cache_method_t parent;
 	void *method;
@@ -1280,7 +1730,7 @@ void **_jit_cache_get_method_list(jit_cache_t cache)
 
 	/* Count the number of distinct methods in the tree */
 	prev = 0;
-	num = CountMethods(cache->head.right, &(cache->nil), &prev);
+	num = CountMethods(cache->head.lr.right, &(cache->nil), &prev);
 
 	/* Allocate a list to hold all of the method descriptors */
 	list = (void **)jit_malloc((num + 1) * sizeof(void *));
@@ -1291,7 +1741,7 @@ void **_jit_cache_get_method_list(jit_cache_t cache)
 
 	/* Fill the list with methods and then return it */
 	prev = 0;
-	FillMethodList(list, cache->head.right, &(cache->nil), &prev);
+	FillMethodList(list, cache->head.lr.right, &(cache->nil), &prev);
 	list[num] = 0;
 	return list;
 }
@@ -1312,7 +1762,7 @@ typedef struct
 static void InitDebugIter(jit_cache_debug_iter *iter,
 						  jit_cache_t cache, void *start)
 {
-	jit_cache_method_t node = cache->head.right;
+	jit_cache_method_t node = cache->head.lr.right;
 	while(node != &(cache->nil))
 	{
 		if(((unsigned char *)start) < node->start)
diff --git a/jit/jit-cache.h b/jit/jit-cache.h
index e0c5dab..0b00b45 100644
--- a/jit/jit-cache.h
+++ b/jit/jit-cache.h
@@ -54,7 +54,10 @@ typedef struct
  */
 jit_cache_t _jit_cache_create(long limit,
 			      long cache_page_size,
-			      int max_page_factor);
+			      int max_page_factor,
+			      jit_malloc_code_func malloc_code_func, jit_resize_code_func resize_code_func, jit_free_code_func free_code_func,
+			      jit_malloc_func malloc_func, jit_free_func free_func
+);
 
 /*
  * Destroy a method cache.
@@ -96,7 +99,8 @@ int _jit_cache_start_method(jit_cache_t cache,
 			    jit_cache_posn *posn,
 			    int page_factor,
 			    int align,
-			    void *cookie);
+			    unsigned long predicted_size,
+			    void *method);
 
 /*
  * End output of a method.  Returns zero if a restart.
@@ -104,6 +108,11 @@ int _jit_cache_start_method(jit_cache_t cache,
 int _jit_cache_end_method(jit_cache_posn *posn);
 
 /*
+ * Free all resources known by the cache, associated with this method.
+ */
+void _jit_cache_free_method(jit_cache_t cache, void *entry_point);
+
+/*
  * Allocate "size" bytes of storage in the method cache's
  * auxillary data area.  Returns NULL if insufficient space
  * to satisfy the request.  It may be possible to satisfy
@@ -118,6 +127,11 @@ void *_jit_cache_alloc(jit_cache_posn *posn, unsigned long size);
 void *_jit_cache_alloc_no_method
 	(jit_cache_t cache, unsigned long size, unsigned long align);
 
+void _jit_cache_free(jit_cache_t cache, void *data);
+
+void *_jit_cache_alloc_code(jit_cache_t cache, unsigned long size);
+void _jit_cache_free_code(jit_cache_t cache, void *data);
+	
 /*
  * Align the method code on a particular boundary if the
  * difference between the current position and the aligned
diff --git a/jit/jit-compile.c b/jit/jit-compile.c
index 8910912..7cf2bcf 100644
--- a/jit/jit-compile.c
+++ b/jit/jit-compile.c
@@ -42,6 +42,8 @@ typedef struct
 
 	int			restart;
 	int			page_factor;
+	int 			code_factor;
+	jit_nint		block_count;
 
 	void			*code_start;
 	void			*code_end;
@@ -404,21 +406,38 @@ cache_release(_jit_compile_t *state)
 static void
 cache_alloc(_jit_compile_t *state)
 {
+	jit_block_t block;
 	int result;
+	
+	if ( state->code_factor != 0 && state->block_count == 0 )
+	{
+		for(block = 0; (block = jit_block_next(state->func, block)) != 0; state->block_count++ );
+	}
 
 	/* First try with the current cache page */
 	result = _jit_cache_start_method(state->cache,
 					 &state->gen.posn,
 					 state->page_factor++,
 					 JIT_FUNCTION_ALIGNMENT,
+#ifdef JIT_PROLOG_SIZE
+					 state->block_count * state->code_factor + JIT_PROLOG_SIZE + 32,
+#else
+					 state->block_count * state->code_factor + 32,
+#endif
 					 state->func);
 	if(result == JIT_CACHE_RESTART)
 	{
 		/* No space left on the current cache page.  Allocate a new one. */
+		if ( state->code_factor ) state->code_factor += 3;
 		result = _jit_cache_start_method(state->cache,
 						 &state->gen.posn,
 						 state->page_factor++,
 						 JIT_FUNCTION_ALIGNMENT,
+#ifdef JIT_PROLOG_SIZE
+						 state->block_count * state->code_factor + JIT_PROLOG_SIZE + 32,
+#else
+						 state->block_count * state->code_factor + 32,
+#endif
 						 state->func);
 	}
 	if(result != JIT_CACHE_OK)
@@ -502,11 +521,17 @@ cache_realloc(_jit_compile_t *state)
 	cache_abort(state);
 
 	/* Allocate a new cache page with the size that grows
-	   by factor of 2 on each reallocation */
+	   by factor of 2 on each reallocation or with a 3-byte factor for custom allocation. */
+	if ( state->code_factor ) state->code_factor += 3;
 	result = _jit_cache_start_method(state->cache,
 					 &state->gen.posn,
 					 state->page_factor,
 					 JIT_FUNCTION_ALIGNMENT,
+#ifdef JIT_PROLOG_SIZE
+					 state->block_count * state->code_factor + JIT_PROLOG_SIZE + 32,
+#else
+					 state->block_count * state->code_factor + 32,
+#endif
 					 state->func);
 	if(result != JIT_CACHE_OK)
 	{
@@ -628,6 +653,7 @@ compile(_jit_compile_t *state, jit_function_t func)
 	/* Initialize compilation state */
 	jit_memzero(state, sizeof(_jit_compile_t));
 	state->func = func;
+	state->code_factor = jit_context_get_code_factor(func->context);
 
 	/* Replace user's exception handler with internal handler */
 	handler = jit_exception_set_handler(internal_exception_handler);
@@ -706,6 +732,11 @@ compile(_jit_compile_t *state, jit_function_t func)
 	jit_extra_gen_cleanup(&state->gen);
 #endif
 
+	if ( state->code_factor != 0 )
+	{
+		jit_context_update_code_factor(func->context, (state->code_end - state->code_start) / state->block_count + 1);
+	}
+	
 	/* End the function's output process */
 	cache_flush(state);
 
diff --git a/jit/jit-context.c b/jit/jit-context.c
index 3325960..da073fb 100644
--- a/jit/jit-context.c
+++ b/jit/jit-context.c
@@ -22,6 +22,7 @@
 
 #include "jit-internal.h"
 #include "jit-cache.h"
+#include <limits.h>
 
 /*@
 
@@ -91,6 +92,14 @@ jit_context_t jit_context_create(void)
 	context->functions = 0;
 	context->last_function = 0;
 	context->on_demand_driver = _jit_function_compile_on_demand;
+	context->malloc_code_func = NULL;
+	context->resize_code_func = NULL;
+	context->free_code_func = NULL;
+	context->malloc_func = NULL;
+	context->free_func = NULL;
+	context->code_factor = 0;
+	context->code_factor_count = 0;
+	context->code_factor_total = 0;
 	return context;
 }
 
@@ -322,6 +331,46 @@ void jit_context_free_meta(jit_context_t context, int type)
 	jit_meta_free(&(context->meta), type);
 }
 
+/*@
+ * @deftypefun void jit_context_set_code_allocator(jit_context_t @var{context}, jit_alloc_code_func @var{alloc_func}, jit_resize_code_func @var{resize_func}, jit_free_code_func @var{free_func})
+ * Sets cusstom code-memory allocation functions. You should do this before
+ * any code is generated / function is compiled.
+ * @end deftypefun
+@*/
+void jit_context_set_code_allocator(jit_context_t context, 
+				    jit_malloc_code_func malloc_code_func, jit_resize_code_func resize_code_func, jit_free_code_func free_code_func,
+				    jit_malloc_func malloc_func, jit_free_func free_func)
+{
+	context->malloc_code_func 	= malloc_code_func;
+	context->resize_code_func	= resize_code_func;
+	context->free_code_func		= free_code_func;
+	context->malloc_func 		= malloc_func;
+	context->free_func		= free_func;
+	if ( malloc_code_func != 0 )
+	{
+		/* Enable estimating the size of the code based on the number of blocks. */
+		context->code_factor = sizeof(void*);
+	}
+}
+
+#include <stdio.h>
+
+int jit_context_get_code_factor(jit_context_t context)
+{
+	return context->code_factor;
+}
+
+void jit_context_update_code_factor(jit_context_t context, int code_factor)
+{
+	/* As long as we can, calculate a running average and use that plus a little bit as factor */
+	if ( context->code_factor > 0 && (INT_MAX - context->code_factor_total) > code_factor )
+	{
+		context->code_factor_count++;
+		context->code_factor_total += code_factor;
+		context->code_factor = context->code_factor_total / context->code_factor_count + 2;
+	}
+}
+
 struct jit_cache *_jit_context_get_cache(jit_context_t context)
 {
 	if(!(context->cache))
@@ -332,7 +381,13 @@ struct jit_cache *_jit_context_get_cache(jit_context_t context)
 			 (long)jit_context_get_meta_numeric
 			 	(context, JIT_OPTION_CACHE_PAGE_SIZE),
 			 (int)jit_context_get_meta_numeric
-				(context, JIT_OPTION_CACHE_MAX_PAGE_FACTOR));
+				(context, JIT_OPTION_CACHE_MAX_PAGE_FACTOR),
+			 context->malloc_code_func,
+			 context->resize_code_func,
+			 context->free_code_func,
+			 context->malloc_func,
+			 context->free_func
+			);
 	}
 	return context->cache;
 }
diff --git a/jit/jit-function.c b/jit/jit-function.c
index 3cdc580..2879b59 100644
--- a/jit/jit-function.c
+++ b/jit/jit-function.c
@@ -60,7 +60,7 @@ jit_function_t jit_function_create(jit_context_t context, jit_type_t signature)
 
 #if !defined(JIT_BACKEND_INTERP) && (defined(jit_redirector_size) || defined(jit_indirector_size))
 	/* TODO: if the function is destroyed the redirector and indirector memory
-	   is leaked */
+	   is leaked -> Not with a custom allocator. */
 
 	/* We need the cache lock while we are allocating redirector and indirector */
 	jit_mutex_lock(&(context->cache_lock));
@@ -76,21 +76,21 @@ jit_function_t jit_function_create(jit_context_t context, jit_type_t signature)
 
 # if defined(jit_redirector_size)
 	/* Allocate redirector buffer */
-	func->redirector = _jit_cache_alloc_no_method(cache, jit_redirector_size, 1);
+	func->redirector = _jit_cache_alloc_code(cache, jit_redirector_size);
 	if(!func->redirector)
 	{
 		jit_mutex_unlock(&(context->cache_lock));
-		jit_free(func);
+		_jit_function_destroy(func);
 		return 0;
 	}
 # endif
 # if defined(jit_indirector_size)
 	/* Allocate indirector buffer */
-	func->indirector = _jit_cache_alloc_no_method(cache, jit_indirector_size, 1);
+	func->indirector = _jit_cache_alloc_code(cache, jit_indirector_size);
 	if(!func->indirector)
 	{
 		jit_mutex_unlock(&(context->cache_lock));
-		jit_free(func);
+		_jit_function_destroy(func);
 		return 0;
 	}
 # endif
@@ -260,6 +260,8 @@ void _jit_function_destroy(jit_function_t func)
 	_jit_function_free_builder(func);
 	jit_meta_destroy(&(func->meta));
 	jit_type_free(func->signature);
+	_jit_cache_free_code(func->context->cache, func->redirector);
+	_jit_cache_free_code(func->context->cache, func->indirector);
 	jit_free(func);
 }
 
@@ -292,6 +294,31 @@ void jit_function_abandon(jit_function_t func)
 }
 
 /*@
+ * @deftypefun void jit_function_free (jit_function_t @var{func})
+ * Free this function. The @var{func} object is completely destroyed and
+ * detached from its owning context. All associated resources are freed.
+ * Currently, the internal memory manager will NOT free the code memory.
+ * @end deftypefun
+@*/
+void jit_function_free(jit_function_t func)
+{
+	if(!func)
+	{
+		return;
+	}
+	if ( func->entry_point )
+	{
+		/* Acquire the cache lock */
+		jit_mutex_lock(&func->context->cache_lock);
+		jit_cache_t cache = _jit_context_get_cache(func->context);
+		_jit_cache_free_method(cache, func->entry_point);
+		jit_mutex_unlock(&func->context->cache_lock);
+	}
+
+	_jit_function_destroy(func);
+}
+
+/*@
  * @deftypefun jit_context_t jit_function_get_context (jit_function_t @var{func})
  * Get the context associated with a function.
  * @end deftypefun
diff --git a/jit/jit-gen-x86-64.h b/jit/jit-gen-x86-64.h
index 2a15ee7..996e2f3 100644
--- a/jit/jit-gen-x86-64.h
+++ b/jit/jit-gen-x86-64.h
@@ -26,6 +26,10 @@
 #include <jit/jit-defs.h>
 #include "jit-gen-x86.h"
 
+#if defined(__CYGWIN64__) || defined(_WIN64)
+#define WIN64
+#endif
+
 #ifdef	__cplusplus
 extern	"C" {
 #endif
diff --git a/jit/jit-insn.c b/jit/jit-insn.c
index b1dd2e2..07caed8 100644
--- a/jit/jit-insn.c
+++ b/jit/jit-insn.c
@@ -4278,6 +4278,25 @@ static jit_value_t apply_unary_conversion
 }
 
 /*@
+ * @deftypefun int jit_insn_cast (jit_function_t @var{func}, jit_value_t @var{value}, jit_type_t @var{type})
+ * Change the type of a value to a different type with the same size.
+ * @end deftypefun
+@*/
+int jit_insn_cast(jit_function_t func, jit_value_t value, jit_type_t type)
+{
+	if (value->type != type)
+	{
+		if (value->type->size != type->size)
+		{
+			return 0;
+		}
+		jit_type_free(value->type);
+		value->type = jit_type_copy(type);
+	}
+	return 1;
+}
+
+/*@
  * @deftypefun jit_value_t jit_insn_convert (jit_function_t @var{func}, jit_value_t @var{value}, jit_type_t @var{type}, int @var{overflow_check})
  * Convert the contents of a value into a new type, with optional
  * overflow checking.
@@ -5054,6 +5073,13 @@ jit_value_t jit_insn_convert(jit_function_t func, jit_value_t value,
 			value = apply_unary_conversion
 				(func, opcode_map->cvt3, value, opcode_map->type3);
 		}
+    
+		// Make sure we're actually the type we asked to convert to, and not some derivated type.
+		if ( value->type != type && jit_type_normalize(jit_value_get_type(value)) == jit_type_normalize(type) )
+		{
+			jit_type_free(value->type);
+			value->type = jit_type_copy(type);
+		}
 	}
 	return value;
 }
@@ -5985,6 +6011,13 @@ jit_value_t jit_insn_call_native
 		break;
 	}
 
+	// Make sure we're actually the type we asked to convert to, and not some derivated type.
+	if ( return_value->type != jit_type_get_return(signature) )
+	{
+		jit_type_free(return_value->type);
+		return_value->type = jit_type_copy(jit_type_get_return(signature));
+	}
+
 	/* Return the value containing the result to the caller */
 	return return_value;
 }
diff --git a/jit/jit-internal.h b/jit/jit-internal.h
index 35961ab..1ff90b5 100644
--- a/jit/jit-internal.h
+++ b/jit/jit-internal.h
@@ -549,6 +549,16 @@ struct _jit_context
 
 	/* On-demand compilation driver */
 	jit_on_demand_driver_func	on_demand_driver;
+	
+	/* plugable memmory management members */
+	jit_malloc_code_func	malloc_code_func;
+	jit_resize_code_func	resize_code_func;
+	jit_free_code_func	free_code_func;
+	jit_malloc_func		malloc_func;
+	jit_free_func		free_func;
+	int			code_factor_total;
+	int			code_factor_count;
+	int			code_factor;
 };
 
 /*
diff --git a/jit/jit-reg-alloc.c b/jit/jit-reg-alloc.c
index 21798c6..aac2de3 100644
--- a/jit/jit-reg-alloc.c
+++ b/jit/jit-reg-alloc.c
@@ -2648,7 +2648,7 @@ _jit_regs_lookup(char *name)
 	{
 		for(reg = 0; reg < JIT_NUM_REGS; reg++)
 		{
-			if(strcmp(jit_reg_name(reg), name) == 0)
+			if(strcmp(jit_reg_name(reg), name) == 0 || strcmp(jit_reg_alias(reg), name) == 0)
 			{
 				return reg;
 			}
@@ -2911,8 +2911,10 @@ _jit_regs_set_outgoing(jit_gencode_t gen, int reg, jit_value_t value)
 	if(value->in_register && value->reg == reg)
 	{
 		/* The value is already in the register, but we may need to spill
-		   if the frame copy is not up to date with the register */
-		if(!(value->in_global_register || value->in_frame))
+		   if the frame copy is not up to date with the register.
+		   If the usage_count <= 1 then this is the one and only used and
+		   we don't need to spill it. */
+		if( !(value->in_global_register || value->in_frame) && value->usage_count > 1 )
 		{
 			save_value(gen, value, reg, other_reg, 0);
 		}
diff --git a/jit/jit-rules-alpha.h b/jit/jit-rules-alpha.h
index 131267f..3d8f6cf 100644
--- a/jit/jit-rules-alpha.h
+++ b/jit/jit-rules-alpha.h
@@ -66,70 +66,70 @@ extern	"C" {
  * $f31 - Contains the value 0.0.
  */
 #define JIT_REG_INFO	\
-	{   "v0",  0, -1, JIT_REG_FIXED}, \
-	{   "t0",  1, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
-	{   "t1",  2, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
-	{   "t2",  3, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
-	{   "t3",  4, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
-	{   "t4",  5, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
-	{   "t5",  6, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
-	{   "t6",  7, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
-	{   "t7",  8, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
-	{   "s0",  9, -1, JIT_REG_ALPHA_INT | JIT_REG_GLOBAL}, \
- 	{   "s1", 10, -1, JIT_REG_ALPHA_INT | JIT_REG_GLOBAL}, \
-	{   "s2", 11, -1, JIT_REG_ALPHA_INT | JIT_REG_GLOBAL}, \
-	{   "s3", 12, -1, JIT_REG_ALPHA_INT | JIT_REG_GLOBAL}, \
-	{   "s4", 13, -1, JIT_REG_ALPHA_INT | JIT_REG_GLOBAL}, \
-	{   "s5", 14, -1, JIT_REG_ALPHA_INT | JIT_REG_GLOBAL}, \
-	{   "fp", 15, -1, JIT_REG_FIXED | JIT_REG_FRAME}, \
-	{   "a0", 16, -1, JIT_REG_FIXED}, \
-	{   "a1", 17, -1, JIT_REG_FIXED}, \
-	{   "a2", 18, -1, JIT_REG_FIXED}, \
-	{   "a3", 19, -1, JIT_REG_FIXED}, \
-	{   "a4", 20, -1, JIT_REG_FIXED}, \
-	{   "a5", 21, -1, JIT_REG_FIXED}, \
-	{   "t8", 22, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
-	{   "t9", 23, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
-	{  "t10", 24, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
-	{  "t11", 25, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
-	{   "ra", 26, -1, JIT_REG_FIXED}, \
-	{   "pv", 27, -1, JIT_REG_FIXED}, \
-	{   "at", 28, -1, JIT_REG_FIXED}, \
-	{   "gp", 29, -1, JIT_REG_FIXED}, \
-	{   "sp", 30, -1, JIT_REG_FIXED | JIT_REG_STACK_PTR}, \
-	{ "zero", 31, -1, JIT_REG_FIXED}, \
-	{  "fv0", 0, -1, JIT_REG_FIXED}, \
-	{  "fv1", 1, -1, JIT_REG_FIXED}, \
-	{  "fs0", 2, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
-	{  "fs1", 3, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
-	{  "fs2", 4, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
-	{  "fs3", 5, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
-	{  "fs4", 6, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
-	{  "fs5", 7, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
-	{  "fs6", 8, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
-	{  "fs7", 9, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
-	{  "ft0", 10, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_CALL_USED}, \
-	{  "ft1", 11, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_CALL_USED}, \
-	{  "ft2", 12, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_CALL_USED}, \
-	{  "ft3", 13, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_CALL_USED}, \
-	{  "ft4", 14, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_CALL_USED}, \
-	{  "ft5", 15, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_CALL_USED}, \
-	{  "fa0", 16, -1, JIT_REG_FIXED}, \
-	{  "fa1", 17, -1, JIT_REG_FIXED}, \
-	{  "fa2", 18, -1, JIT_REG_FIXED}, \
-	{  "fa3", 19, -1, JIT_REG_FIXED}, \
-	{  "fa4", 20, -1, JIT_REG_FIXED}, \
-	{  "fa5", 21, -1, JIT_REG_FIXED}, \
-	{  "fe0", 22, -1, JIT_REG_FIXED}, \
-	{  "fe1", 23, -1, JIT_REG_FIXED}, \
-	{  "fe2", 24, -1, JIT_REG_FIXED}, \
-	{  "fe3", 25, -1, JIT_REG_FIXED}, \
-	{  "fe4", 26, -1, JIT_REG_FIXED}, \
-	{  "fe5", 27, -1, JIT_REG_FIXED}, \
-	{  "fe6", 28, -1, JIT_REG_FIXED}, \
-	{  "fe7", 29, -1, JIT_REG_FIXED}, \
-	{  "fe8", 30, -1, JIT_REG_FIXED}, \
-	{"fzero", 31, -1, JIT_REG_FIXED},
+	{   "v0", NULL,  0, -1, JIT_REG_FIXED}, \
+	{   "t0", NULL,  1, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
+	{   "t1", NULL,  2, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
+	{   "t2", NULL,  3, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
+	{   "t3", NULL,  4, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
+	{   "t4", NULL,  5, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
+	{   "t5", NULL,  6, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
+	{   "t6", NULL,  7, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
+	{   "t7", NULL,  8, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
+	{   "s0", NULL,  9, -1, JIT_REG_ALPHA_INT | JIT_REG_GLOBAL}, \
+ 	{   "s1", NULL, 10, -1, JIT_REG_ALPHA_INT | JIT_REG_GLOBAL}, \
+	{   "s2", NULL, 11, -1, JIT_REG_ALPHA_INT | JIT_REG_GLOBAL}, \
+	{   "s3", NULL, 12, -1, JIT_REG_ALPHA_INT | JIT_REG_GLOBAL}, \
+	{   "s4", NULL, 13, -1, JIT_REG_ALPHA_INT | JIT_REG_GLOBAL}, \
+	{   "s5", NULL, 14, -1, JIT_REG_ALPHA_INT | JIT_REG_GLOBAL}, \
+	{   "fp", NULL, 15, -1, JIT_REG_FIXED | JIT_REG_FRAME}, \
+	{   "a0", NULL, 16, -1, JIT_REG_FIXED}, \
+	{   "a1", NULL, 17, -1, JIT_REG_FIXED}, \
+	{   "a2", NULL, 18, -1, JIT_REG_FIXED}, \
+	{   "a3", NULL, 19, -1, JIT_REG_FIXED}, \
+	{   "a4", NULL, 20, -1, JIT_REG_FIXED}, \
+	{   "a5", NULL, 21, -1, JIT_REG_FIXED}, \
+	{   "t8", NULL, 22, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
+	{   "t9", NULL, 23, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
+	{  "t10", NULL, 24, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
+	{  "t11", NULL, 25, -1, JIT_REG_ALPHA_INT | JIT_REG_CALL_USED}, \
+	{   "ra", NULL, 26, -1, JIT_REG_FIXED}, \
+	{   "pv", NULL, 27, -1, JIT_REG_FIXED}, \
+	{   "at", NULL, 28, -1, JIT_REG_FIXED}, \
+	{   "gp", NULL, 29, -1, JIT_REG_FIXED}, \
+	{   "sp", NULL, 30, -1, JIT_REG_FIXED | JIT_REG_STACK_PTR}, \
+	{ "zero", NULL, 31, -1, JIT_REG_FIXED}, \
+	{  "fv0", NULL, 0, -1, JIT_REG_FIXED}, \
+	{  "fv1", NULL, 1, -1, JIT_REG_FIXED}, \
+	{  "fs0", NULL, 2, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
+	{  "fs1", NULL, 3, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
+	{  "fs2", NULL, 4, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
+	{  "fs3", NULL, 5, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
+	{  "fs4", NULL, 6, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
+	{  "fs5", NULL, 7, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
+	{  "fs6", NULL, 8, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
+	{  "fs7", NULL, 9, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_GLOBAL}, \
+	{  "ft0", NULL, 10, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_CALL_USED}, \
+	{  "ft1", NULL, 11, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_CALL_USED}, \
+	{  "ft2", NULL, 12, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_CALL_USED}, \
+	{  "ft3", NULL, 13, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_CALL_USED}, \
+	{  "ft4", NULL, 14, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_CALL_USED}, \
+	{  "ft5", NULL, 15, -1, JIT_REG_ALPHA_FLOAT | JIT_REG_CALL_USED}, \
+	{  "fa0", NULL, 16, -1, JIT_REG_FIXED}, \
+	{  "fa1", NULL, 17, -1, JIT_REG_FIXED}, \
+	{  "fa2", NULL, 18, -1, JIT_REG_FIXED}, \
+	{  "fa3", NULL, 19, -1, JIT_REG_FIXED}, \
+	{  "fa4", NULL, 20, -1, JIT_REG_FIXED}, \
+	{  "fa5", NULL, 21, -1, JIT_REG_FIXED}, \
+	{  "fe0", NULL, 22, -1, JIT_REG_FIXED}, \
+	{  "fe1", NULL, 23, -1, JIT_REG_FIXED}, \
+	{  "fe2", NULL, 24, -1, JIT_REG_FIXED}, \
+	{  "fe3", NULL, 25, -1, JIT_REG_FIXED}, \
+	{  "fe4", NULL, 26, -1, JIT_REG_FIXED}, \
+	{  "fe5", NULL, 27, -1, JIT_REG_FIXED}, \
+	{  "fe6", NULL, 28, -1, JIT_REG_FIXED}, \
+	{  "fe7", NULL, 29, -1, JIT_REG_FIXED}, \
+	{  "fe8", NULL, 30, -1, JIT_REG_FIXED}, \
+	{"fzero", NULL, 31, -1, JIT_REG_FIXED},
 
 /* 32 floating-point registers + 32 integer registers */
 #define JIT_NUM_REGS			64
diff --git a/jit/jit-rules-arm.h b/jit/jit-rules-arm.h
index 1797e00..7645a7f 100644
--- a/jit/jit-rules-arm.h
+++ b/jit/jit-rules-arm.h
@@ -57,22 +57,22 @@ extern	"C" {
  * The definitions of the used flags are in jit-rules.h
  */
 #define	JIT_REG_INFO	\
-	{"r0",   0,  1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_CALL_USED}, \
-	{"r1",   1, -1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
-	{"r2",   2,  3, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_CALL_USED}, \
-	{"r3",   3, -1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
-	{"r4",   4, -1, JIT_REG_WORD}, \
-	{"r5",   5, -1, JIT_REG_WORD}, \
-	{"r6",   6, -1, JIT_REG_WORD | JIT_REG_GLOBAL},	\
-	{"r7",   7, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
-	{"r8",   8, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
-	{"r9",   9, -1, JIT_REG_FIXED}, /* pic reg */ \
-	{"r10", 10, -1, JIT_REG_FIXED}, /* stack limit */ \
-	{"fp",  11, -1, JIT_REG_FIXED | JIT_REG_FRAME},	\
-	{"r12", 12, -1, JIT_REG_FIXED | JIT_REG_CALL_USED}, /* work reg */ \
-	{"sp",  13, -1, JIT_REG_FIXED | JIT_REG_STACK_PTR}, \
-	{"lr",  14, -1, JIT_REG_FIXED}, \
-	{"pc",  15, -1, JIT_REG_FIXED}, \
+	{"r0", NULL,   0,  1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_CALL_USED}, \
+	{"r1", NULL,   1, -1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
+	{"r2", NULL,   2,  3, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_CALL_USED}, \
+	{"r3", NULL,   3, -1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
+	{"r4", NULL,   4, -1, JIT_REG_WORD}, \
+	{"r5", NULL,   5, -1, JIT_REG_WORD}, \
+	{"r6", NULL,   6, -1, JIT_REG_WORD | JIT_REG_GLOBAL},	\
+	{"r7", NULL,   7, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
+	{"r8", NULL,   8, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
+	{"r9", NULL,   9, -1, JIT_REG_FIXED}, /* pic reg */ \
+	{"r10", NULL, 10, -1, JIT_REG_FIXED}, /* stack limit */ \
+	{"fp", NULL,  11, -1, JIT_REG_FIXED | JIT_REG_FRAME},	\
+	{"r12", NULL, 12, -1, JIT_REG_FIXED | JIT_REG_CALL_USED}, /* work reg */ \
+	{"sp", NULL,  13, -1, JIT_REG_FIXED | JIT_REG_STACK_PTR}, \
+	{"lr", NULL,  14, -1, JIT_REG_FIXED}, \
+	{"pc", NULL,  15, -1, JIT_REG_FIXED}, \
 	JIT_REG_INFO_FLOAT_REGS
 
 /*
@@ -96,10 +96,10 @@ extern	"C" {
 	(JIT_REG_FLOAT32 | JIT_REG_FLOAT64 | JIT_REG_NFLOAT | JIT_REG_CALL_USED)
 
 #define JIT_REG_INFO_FLOAT_REGS	\
-	{"f0",   0, -1, JIT_REG_ARM_FLOAT}, \
-	{"f1",   1, -1, JIT_REG_ARM_FLOAT}, \
-	{"f2",   2, -1, JIT_REG_ARM_FLOAT}, \
-	{"f3",   3, -1, JIT_REG_ARM_FLOAT},
+	{"f0", NULL,   0, -1, JIT_REG_ARM_FLOAT}, \
+	{"f1", NULL,   1, -1, JIT_REG_ARM_FLOAT}, \
+	{"f2", NULL,   2, -1, JIT_REG_ARM_FLOAT}, \
+	{"f3", NULL,   3, -1, JIT_REG_ARM_FLOAT},
 
 /* JIT_NUM_REGS is the total number of registers (general purpose+floating point) */
 #define	JIT_NUM_REGS		20
@@ -115,30 +115,30 @@ extern	"C" {
 #define JIT_REG_ARM_FLOAT64	(JIT_REG_FLOAT64 | JIT_REG_NFLOAT)
 
 #define JIT_REG_INFO_FLOAT_REGS	\
-	{"s0",   0, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s1",   1, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s2",   2, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s3",   3, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s4",   4, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s5",   5, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s6",   6, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s7",   7, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s8",   8, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s9",   9, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s10",   10, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s11",   11, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s12",   12, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s13",   13, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s14",   14, -1, JIT_REG_ARM_FLOAT32}, \
-	{"s15",   15, -1, JIT_REG_ARM_FLOAT32}, \
-	{"d8",   8, -1, JIT_REG_ARM_FLOAT64},	\
-	{"d9",   9, -1, JIT_REG_ARM_FLOAT64},	\
-	{"d10",   10, -1, JIT_REG_ARM_FLOAT64},	\
-	{"d11",   11, -1, JIT_REG_ARM_FLOAT64},	\
-	{"d12",   12, -1, JIT_REG_ARM_FLOAT64},	\
-	{"d13",   13, -1, JIT_REG_ARM_FLOAT64},	\
-	{"d14",   14, -1, JIT_REG_ARM_FLOAT64},	\
-	{"d15",   15, -1, JIT_REG_ARM_FLOAT64},
+	{"s0", NULL,   0, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s1", NULL,   1, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s2", NULL,   2, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s3", NULL,   3, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s4", NULL,   4, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s5", NULL,   5, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s6", NULL,   6, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s7", NULL,   7, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s8", NULL,   8, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s9", NULL,   9, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s10", NULL,   10, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s11", NULL,   11, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s12", NULL,   12, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s13", NULL,   13, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s14", NULL,   14, -1, JIT_REG_ARM_FLOAT32}, \
+	{"s15", NULL,   15, -1, JIT_REG_ARM_FLOAT32}, \
+	{"d8", NULL,   8, -1, JIT_REG_ARM_FLOAT64},	\
+	{"d9", NULL,   9, -1, JIT_REG_ARM_FLOAT64},	\
+	{"d10", NULL,   10, -1, JIT_REG_ARM_FLOAT64},	\
+	{"d11", NULL,   11, -1, JIT_REG_ARM_FLOAT64},	\
+	{"d12", NULL,   12, -1, JIT_REG_ARM_FLOAT64},	\
+	{"d13", NULL,   13, -1, JIT_REG_ARM_FLOAT64},	\
+	{"d14", NULL,   14, -1, JIT_REG_ARM_FLOAT64},	\
+	{"d15", NULL,   15, -1, JIT_REG_ARM_FLOAT64},
 
 /* JIT_NUM_REGS is the total number of registers (general purpose+floating point) */
 #define JIT_NUM_REGS		40
diff --git a/jit/jit-rules-interp.h b/jit/jit-rules-interp.h
index d5a1022..2b00d08 100644
--- a/jit/jit-rules-interp.h
+++ b/jit/jit-rules-interp.h
@@ -33,9 +33,9 @@ extern	"C" {
  * Information about all of the registers, in allocation order.
  */
 #define	JIT_REG_INFO \
-	{"r0", 0, -1, JIT_REG_ALL | JIT_REG_CALL_USED}, \
-	{"r1", 1, -1, JIT_REG_ALL | JIT_REG_CALL_USED}, \
-	{"r2", 2, -1, JIT_REG_ALL | JIT_REG_CALL_USED},
+	{"r0", NULL, 0, -1, JIT_REG_ALL | JIT_REG_CALL_USED}, \
+	{"r1", NULL, 1, -1, JIT_REG_ALL | JIT_REG_CALL_USED}, \
+	{"r2", NULL, 2, -1, JIT_REG_ALL | JIT_REG_CALL_USED},
 #define	JIT_NUM_REGS		3
 #define	JIT_NUM_GLOBAL_REGS	0
 
diff --git a/jit/jit-rules-x86-64.c b/jit/jit-rules-x86-64.c
index 155d201..aae357a 100644
--- a/jit/jit-rules-x86-64.c
+++ b/jit/jit-rules-x86-64.c
@@ -152,17 +152,38 @@ typedef struct
 } _jit_va_list;
 
 /* Registers used for INTEGER arguments */
+#ifdef WIN64
+static int _jit_word_arg_regs[] = {
+								   X86_64_REG_RCX, X86_64_REG_RDX,
+								   X86_64_REG_R8, X86_64_REG_R9};
+#define _jit_num_word_regs	4
+#define ARGREG1 X86_64_RCX
+#define ARGREG2 X86_64_RDX
+#define ARGREG3 X86_64_R8
+#define ARGREG4 X86_64_R9
+#else
 static int _jit_word_arg_regs[] = {X86_64_REG_RDI, X86_64_REG_RSI,
 								   X86_64_REG_RDX, X86_64_REG_RCX,
 								   X86_64_REG_R8, X86_64_REG_R9};
 #define _jit_num_word_regs	6
+#define ARGREG1 X86_64_RDI
+#define ARGREG2 X86_64_RSI
+#define ARGREG3 X86_64_RDX
+#define ARGREG4 X86_64_RCX
+#endif
 
 /* Registers used for float arguments */
+#ifdef WIN64
+static int _jit_float_arg_regs[] = {X86_64_REG_XMM0, X86_64_REG_XMM1,
+									X86_64_REG_XMM2, X86_64_REG_XMM3};
+#define _jit_num_float_regs	4
+#else
 static int _jit_float_arg_regs[] = {X86_64_REG_XMM0, X86_64_REG_XMM1,
 									X86_64_REG_XMM2, X86_64_REG_XMM3,
 									X86_64_REG_XMM4, X86_64_REG_XMM5,
 									X86_64_REG_XMM6, X86_64_REG_XMM7};
 #define _jit_num_float_regs	8
+#endif
 
 /* Registers used for returning INTEGER values */
 static int _jit_word_return_regs[] = {X86_64_REG_RAX, X86_64_REG_RDX};
@@ -205,12 +226,21 @@ _jit_init_backend(void)
 
 	/* register class with all call clobbered registers */
 	x86_64_creg = _jit_regclass_create(
+#ifdef WIN64
+		"creg", JIT_REG_WORD | JIT_REG_LONG, 7,
+		X86_64_REG_RAX, X86_64_REG_RCX,
+		X86_64_REG_RDX, X86_64_REG_R8,
+		X86_64_REG_R9 , X86_64_REG_R10,
+		X86_64_REG_R11
+#else
 		"creg", JIT_REG_WORD | JIT_REG_LONG, 9,
 		X86_64_REG_RAX, X86_64_REG_RCX,
-		X86_64_REG_RDX, X86_64_REG_RSI,
-		X86_64_REG_RDI, X86_64_REG_R8,
-		X86_64_REG_R9, X86_64_REG_R10,
-		X86_64_REG_R11);
+		X86_64_REG_RDX, X86_64_REG_RSI, 
+    X86_64_REG_RDI, X86_64_REG_R8,
+		X86_64_REG_R9 , X86_64_REG_R10,
+		X86_64_REG_R11
+#endif
+    );
 
 	/* r egister class for divisors */
 	x86_64_dreg = _jit_regclass_create(
@@ -288,37 +318,13 @@ _jit_xmm1_reg_imm_size_float32(jit_gencode_t gen, unsigned char **inst_ptr,
 			       X86_64_XMM1_OP opc, int reg,
 			       jit_float32 *float32_value)
 {
-	void *ptr;
-	jit_nint offset;
-	unsigned char *inst;
+	jit_int* int_value = (jit_int*)float32_value;
+	unsigned char *inst = *inst_ptr;
 
-	inst = *inst_ptr;
-	ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float32));
-	if(!ptr)
-	{
-		return 0;
-	}
-	jit_memcpy(ptr, float32_value, sizeof(jit_float32));
+	x86_64_push_imm(inst, *int_value);
+	x86_64_xmm1_reg_membase(inst, opc, reg, X86_64_RSP, 0, 0);
+	x86_64_alu_reg_imm_size(inst, X86_ADD, X86_64_RSP, 8, 8);
 
-	offset = (jit_nint)ptr - ((jit_nint)inst + (reg > 7 ? 9 : 8));
-	if((offset >= jit_min_int) && (offset <= jit_max_int))
-	{
-		/* We can use RIP relative addressing here */
-		x86_64_xmm1_reg_membase(inst, opc, reg,
-									 X86_64_RIP, offset, 0);
-	}
-	else if(((jit_nint)ptr >= jit_min_int) &&
-			((jit_nint)ptr <= jit_max_int))
-	{
-		/* We can use absolute addressing */
-		x86_64_xmm1_reg_mem(inst, opc, reg, (jit_nint)ptr, 0);
-	}
-	else
-	{
-		/* We have to use an extra general register */
-		TODO();
-		return 0;
-	}
 	*inst_ptr = inst;
 	return 1;
 }
@@ -331,37 +337,14 @@ _jit_xmm1_reg_imm_size_float64(jit_gencode_t gen, unsigned char **inst_ptr,
 			       X86_64_XMM1_OP opc, int reg,
 			       jit_float64 *float64_value)
 {
-	void *ptr;
-	jit_nint offset;
-	unsigned char *inst;
+	jit_int* int_value = (jit_int*)float64_value;
+	unsigned char *inst = *inst_ptr;
 
-	inst = *inst_ptr;
-	ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float64));
-	if(!ptr)
-	{
-		return 0;
-	}
-	jit_memcpy(ptr, float64_value, sizeof(jit_float64));
+	x86_64_push_imm(inst, int_value[0]);
+	x86_64_mov_membase_imm_size(inst, X86_64_RSP, 4, int_value[1], 4);
+	x86_64_xmm1_reg_membase(inst, opc, reg, X86_64_RSP, 0, 1);
+	x86_64_alu_reg_imm_size(inst, X86_ADD, X86_64_RSP, 8, 8);
 
-	offset = (jit_nint)ptr - ((jit_nint)inst + (reg > 7 ? 9 : 8));
-	if((offset >= jit_min_int) && (offset <= jit_max_int))
-	{
-		/* We can use RIP relative addressing here */
-		x86_64_xmm1_reg_membase(inst, opc, reg,
-									 X86_64_RIP, offset, 1);
-	}
-	else if(((jit_nint)ptr >= jit_min_int) &&
-			((jit_nint)ptr <= jit_max_int))
-	{
-		/* We can use absolute addressing */
-		x86_64_xmm1_reg_mem(inst, opc, reg, (jit_nint)ptr, 1);
-	}
-	else
-	{
-		/* We have to use an extra general register */
-		TODO();
-		return 0;
-	}
 	*inst_ptr = inst;
 	return 1;
 }
@@ -373,39 +356,18 @@ static int
 _jit_plops_reg_imm(jit_gencode_t gen, unsigned char **inst_ptr,
 				   X86_64_XMM_PLOP opc, int reg, void *packed_value)
 {
-	void *ptr;
-	jit_nint offset;
-	unsigned char *inst;
+	jit_int* int_value = (jit_int*)packed_value;
+	unsigned char *inst = *inst_ptr;
 
-	inst = *inst_ptr;
-	ptr = _jit_cache_alloc(&(gen->posn), 16);
-	if(!ptr)
-	{
-		return 0;
-	}
-	jit_memcpy(ptr, packed_value, 16);
+	x86_64_push_imm(inst, int_value[2]);
+	x86_64_mov_membase_imm_size(inst, X86_64_RSP, 4, int_value[3], 4);
+	x86_64_push_imm(inst, int_value[0]);
+	x86_64_mov_membase_imm_size(inst, X86_64_RSP, 4, int_value[1], 4);
+	x86_64_plops_reg_membase(inst, opc, reg, X86_64_RSP, 0);
+	x86_64_alu_reg_imm_size(inst, X86_ADD, X86_64_RSP, 16, 8);
 
-	/* calculate the offset for membase addressing */
-	offset = (jit_nint)ptr - ((jit_nint)inst + (reg > 7 ? 8 : 7));
-	if((offset >= jit_min_int) && (offset <= jit_max_int))
-	{
-		/* We can use RIP relative addressing here */
-		x86_64_plops_reg_membase(inst, opc, reg, X86_64_RIP, offset);
-		*inst_ptr = inst;
-		return 1;
-	}
-	/* Check if mem addressing can be used */
-	if(((jit_nint)ptr >= jit_min_int) &&
-		((jit_nint)ptr <= jit_max_int))
-	{
-		/* We can use absolute addressing */
-		x86_64_plops_reg_mem(inst, opc, reg, (jit_nint)ptr);
-		*inst_ptr = inst;
-		return 1;
-	}
-	/* We have to use an extra general register */
-	TODO();
-	return 0;
+	*inst_ptr = inst;
+	return 1;
 }
 
 /*
@@ -415,39 +377,18 @@ static int
 _jit_plopd_reg_imm(jit_gencode_t gen, unsigned char **inst_ptr,
 				   X86_64_XMM_PLOP opc, int reg, void *packed_value)
 {
-	void *ptr;
-	jit_nint offset;
-	unsigned char *inst;
+	jit_int* int_value = (jit_int*)packed_value;
+	unsigned char *inst = *inst_ptr;
 
-	inst = *inst_ptr;
-	ptr = _jit_cache_alloc(&(gen->posn), 16);
-	if(!ptr)
-	{
-		return 0;
-	}
-	jit_memcpy(ptr, packed_value, 16);
+	x86_64_push_imm(inst, int_value[2]);
+	x86_64_mov_membase_imm_size(inst, X86_64_RSP, 4, int_value[3], 4);
+	x86_64_push_imm(inst, int_value[0]);
+	x86_64_mov_membase_imm_size(inst, X86_64_RSP, 4, int_value[1], 4);
+	x86_64_plopd_reg_membase(inst, opc, reg, X86_64_RSP, 0);
+	x86_64_alu_reg_imm_size(inst, X86_ADD, X86_64_RSP, 16, 8);
 
-	/* calculate the offset for membase addressing */
-	offset = (jit_nint)ptr - ((jit_nint)inst + (reg > 7 ? 9 : 8));
-	if((offset >= jit_min_int) && (offset <= jit_max_int))
-	{
-		/* We can use RIP relative addressing here */
-		x86_64_plopd_reg_membase(inst, opc, reg, X86_64_RIP, offset);
-		*inst_ptr = inst;
-		return 1;
-	}
-	/* Check if mem addressing can be used */
-	if(((jit_nint)ptr >= jit_min_int) &&
-		((jit_nint)ptr <= jit_max_int))
-	{
-		/* We can use absolute addressing */
-		x86_64_plopd_reg_mem(inst, opc, reg, (jit_nint)ptr);
-		*inst_ptr = inst;
-		return 1;
-	}
-	/* We have to use an extra general register */
-	TODO();
-	return 0;
+	*inst_ptr = inst;
+	return 1;
 }
 
 /*
@@ -820,7 +761,9 @@ x86_64_call_code(unsigned char *inst, jit_nint func)
 {
 	jit_nint offset;
 
+#ifndef WIN64
 	x86_64_mov_reg_imm_size(inst, X86_64_RAX, 8, 4);
+#endif
 	offset = func - ((jit_nint)inst + 5);
 	if(offset >= jit_min_int && offset <= jit_max_int)
 	{
@@ -1375,60 +1318,19 @@ static unsigned char *
 xmm_cmp_reg_imm(jit_gencode_t gen, unsigned char *inst, int xreg, void *imm,
 		int is_double)
 {
-	int inst_len = 7 + (is_double ? 1 : 0) + (xreg > 7 ? 1 : 0);
-	void *ptr;
-	jit_nint offset;
-
+	jit_int* int_value = (jit_int*)imm;
+	
+	x86_64_push_imm(inst, int_value[0]);
 	if(is_double)
 	{
-		ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float64));
-		if(!ptr)
-		{
-			return 0;
-		}
-		jit_memcpy(ptr, imm, sizeof(jit_float64));
-	}
-	else
-	{
-		ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float32));
-		if(!ptr)
-		{
-			return 0;
-		}
-		jit_memcpy(ptr, imm, sizeof(jit_float32));
-	}
-	offset = (jit_nint)ptr - ((jit_nint)inst + inst_len);
-	if((offset >= jit_min_int) && (offset <= jit_max_int))
-	{
-		/* We can use RIP relative addressing here */
-		if(is_double)
-		{
-			x86_64_ucomisd_reg_membase(inst, xreg, X86_64_RIP, offset);
-		}
-		else
-		{
-			x86_64_ucomiss_reg_membase(inst, xreg, X86_64_RIP, offset);
-		}
-	}
-	else if(((jit_nint)ptr >= jit_min_int) &&
-		((jit_nint)ptr <= jit_max_int))
-	{
-		/* We can use absolute addressing */
-		if(is_double)
-		{
-			x86_64_ucomisd_reg_mem(inst, xreg, (jit_nint)ptr);
-		}
-		else
-		{
-			x86_64_ucomiss_reg_mem(inst, xreg, (jit_nint)ptr);
-		}
+		x86_64_mov_membase_imm_size(inst, X86_64_RSP, 4, int_value[1], 4);
+		x86_64_ucomisd_reg_membase(inst, xreg, X86_64_RSP, 0);
 	}
 	else
 	{
-		/* We have to use an extra general register */
-		TODO();
-		return 0;
+		x86_64_ucomiss_reg_membase(inst, xreg, X86_64_RSP, 0);
 	}
+	x86_64_alu_reg_imm_size(inst, X86_ADD, X86_64_RSP, 8, 8);
 	return inst;
 }
 
@@ -1701,7 +1603,6 @@ _jit_gen_load_value(jit_gencode_t gen, int reg, int other_reg, jit_value_t value
 {
 	jit_type_t type;
 	int src_reg, other_src_reg;
-	void *ptr;
 	int offset;
 
 	/* Make sure that we have sufficient space */
@@ -1790,7 +1691,7 @@ _jit_gen_load_value(jit_gencode_t gen, int reg, int other_reg, jit_value_t value
 					}
 				}
 				else
-				{
+				{					
 					if(float32_value == (jit_float32) 0.0)
 					{
 						x86_fldz(inst);
@@ -1801,28 +1702,16 @@ _jit_gen_load_value(jit_gencode_t gen, int reg, int other_reg, jit_value_t value
 					}
 					else
 					{
-						jit_nint offset;
-
-						ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float32));
-						jit_memcpy(ptr, &float32_value, sizeof(float32_value));
-
-						offset = (jit_nint)ptr - ((jit_nint)inst + 6);
-						if((offset >= jit_min_int) && (offset <= jit_max_int))
+						union
 						{
-							/* We can use RIP relative addressing here */
-							x86_64_fld_membase_size(inst, X86_64_RIP, offset, 4);
-						}
-						else if(((jit_nint)ptr >= jit_min_int) &&
-								((jit_nint)ptr <= jit_max_int))
-						{
-							/* We can use absolute addressing */
-							x86_64_fld_mem_size(inst, (jit_nint)ptr, 4);
-						}
-						else
-						{
-							/* We have to use an extra general register */
-							TODO();
-						}
+							jit_float32 float32_value;
+							jit_int int_value;
+						} un;
+
+						un.float32_value = float32_value;
+						x86_64_push_imm(inst, un.int_value);
+						x86_64_fld_membase_size(inst, X86_64_RSP, 0, 4);
+						x86_64_alu_reg_imm_size(inst, X86_ADD, X86_64_RSP, 8, 8);
 					}
 				}
 			}
@@ -1870,28 +1759,17 @@ _jit_gen_load_value(jit_gencode_t gen, int reg, int other_reg, jit_value_t value
 					}
 					else
 					{
-						jit_nint offset;
-
-						ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float64));
-						jit_memcpy(ptr, &float64_value, sizeof(float64_value));
-
-						offset = (jit_nint)ptr - ((jit_nint)inst + 6);
-						if((offset >= jit_min_int) && (offset <= jit_max_int))
-						{
-							/* We can use RIP relative addressing here */
-							x86_64_fld_membase_size(inst, X86_64_RIP, offset, 8);
-						}
-						else if(((jit_nint)ptr >= jit_min_int) &&
-								((jit_nint)ptr <= jit_max_int))
-						{
-							/* We can use absolute addressing */
-							x86_64_fld_mem_size(inst, (jit_nint)ptr, 8);
-						}
-						else
+						union
 						{
-							/* We have to use an extra general register */
-							TODO();
-						}
+							jit_float64 float64_value;
+							jit_int int_value[2];
+						} un;
+
+						un.float64_value = float64_value;
+						x86_64_push_imm(inst, un.int_value[0]);
+						x86_64_mov_membase_imm_size(inst, X86_64_RSP, 4, un.int_value[1], 4);
+						x86_64_fld_membase_size(inst, X86_64_RSP, 0, 8);
+						x86_64_alu_reg_imm_size(inst, X86_ADD, X86_64_RSP, 8, 8);
 					}
 				}
 			}
@@ -1915,29 +1793,17 @@ _jit_gen_load_value(jit_gencode_t gen, int reg, int other_reg, jit_value_t value
 				}
 				else if(IS_XMM_REG(reg) && sizeof(jit_nfloat) == sizeof(jit_float64))
 				{
-					jit_nint offset;
-					int xmm_reg = _jit_reg_info[reg].cpu_reg;
-
-					ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_nfloat));
-					jit_memcpy(ptr, &nfloat_value, sizeof(nfloat_value));
-					offset = (jit_nint)ptr - 
-								((jit_nint)inst + (xmm_reg > 7 ? 9 : 8));
-					if((offset >= jit_min_int) && (offset <= jit_max_int))
-					{
-						/* We can use RIP relative addressing here */
-						x86_64_movsd_reg_membase(inst, xmm_reg, X86_64_RIP, offset);
-					}
-					else if(((jit_nint)ptr >= jit_min_int) &&
-							((jit_nint)ptr <= jit_max_int))
-					{
-						/* We can use absolute addressing */
-						x86_64_movsd_reg_mem(inst, xmm_reg, (jit_nint)ptr);
-					}
-					else
+					union
 					{
-						/* We have to use an extra general register */
-						TODO();
-					}
+						jit_nfloat nfloat_value;
+						jit_int int_value[2];
+					} un;
+
+					un.nfloat_value = nfloat_value;
+					x86_64_push_imm(inst, un.int_value[0]);
+					x86_64_mov_membase_imm_size(inst, X86_64_RSP, 4, un.int_value[1], 4);
+					x86_64_movsd_reg_membase(inst, reg, X86_64_RSP, 0);
+					x86_64_alu_reg_imm_size(inst, X86_ADD, X86_64_RSP, 8, 8);
 				}
 				else
 				{
@@ -1951,41 +1817,27 @@ _jit_gen_load_value(jit_gencode_t gen, int reg, int other_reg, jit_value_t value
 					}
 					else
 					{
-						jit_nint offset;
-
-						ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_nfloat));
-						jit_memcpy(ptr, &nfloat_value, sizeof(nfloat_value));
+						union
+						{
+							jit_nfloat nfloat_value;
+							jit_int int_value[3];
+						} un;
 
-						offset = (jit_nint)ptr - ((jit_nint)inst + 6);
-						if((offset >= jit_min_int) && (offset <= jit_max_int))
+						un.nfloat_value = nfloat_value;
+						if(sizeof(jit_nfloat) == sizeof(jit_float64))
 						{
-							/* We can use RIP relative addressing here */
-							if(sizeof(jit_nfloat) == sizeof(jit_float64))
-							{
-								x86_64_fld_membase_size(inst, X86_64_RIP, offset, 8);
-							}
-							else
-							{
-								x86_64_fld_membase_size(inst, X86_64_RIP, offset, 10);
-							}
-						}
-						else if(((jit_nint)ptr >= jit_min_int) &&
-								((jit_nint)ptr <= jit_max_int))
-						{
-							/* We can use absolute addressing */
-							if(sizeof(jit_nfloat) == sizeof(jit_float64))
-							{
-								x86_64_fld_mem_size(inst, (jit_nint)ptr, 8);
-							}
-							else
-							{
-								x86_64_fld_mem_size(inst, (jit_nint)ptr, 10);
-							}
+							x86_64_push_imm(inst, un.int_value[0]);
+							x86_64_mov_membase_imm_size(inst, X86_64_RSP, 4, un.int_value[1], 4);
+							x86_64_fld_membase_size(inst, X86_64_RSP, 0, 8);
+							x86_64_alu_reg_imm_size(inst, X86_ADD, X86_64_RSP, 8, 8);
 						}
 						else
 						{
-							/* We have to use an extra general register */
-							TODO();
+							x86_64_push_imm(inst, un.int_value[2]);
+							x86_64_push_imm(inst, un.int_value[0]);
+							x86_64_mov_membase_imm_size(inst, X86_64_RSP, 4, un.int_value[1], 4);
+							x86_64_fld_membase_size(inst, X86_64_RSP, 0, 10);
+							x86_64_alu_reg_imm_size(inst, X86_ADD, X86_64_RSP, 16, 8);
 						}
 					}
 				}
@@ -2387,6 +2239,25 @@ _jit_gen_get_elf_info(jit_elf_info_t *info)
 	info->abi_version = 0;
 }
 
+int
+_jit_count_regs_saved(jit_gencode_t gen)
+{
+	int regs_saved = 0;
+	int reg;
+	
+	/* Get the number of registers we preserves */
+	for(reg = 0; reg < 14; ++reg)
+	{
+		if(jit_reg_is_used(gen->touched, reg) &&
+		   (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
+		{
+			++regs_saved;
+		}
+	}
+	
+	return 	regs_saved;
+}
+
 void *
 _jit_gen_prolog(jit_gencode_t gen, jit_function_t func, void *buf)
 {
@@ -2394,7 +2265,7 @@ _jit_gen_prolog(jit_gencode_t gen, jit_function_t func, void *buf)
 	unsigned char *inst = prolog;
 	int reg;
 	int frame_size = 0;
-	int regs_to_save = 0;
+	int regs_to_save = _jit_count_regs_saved(gen);	
 
 	/* Push ebp onto the stack */
 	x86_64_push_reg_size(inst, X86_64_RBP, 8);
@@ -2409,16 +2280,6 @@ _jit_gen_prolog(jit_gencode_t gen, jit_function_t func, void *buf)
 		frame_size = (func->builder->frame_size + 0x7) & ~0x7;
 	}
 
-	/* Get the number of registers we need to preserve */
-	for(reg = 0; reg < 14; ++reg)
-	{
-		if(jit_reg_is_used(gen->touched, reg) &&
-		   (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
-		{
-			++regs_to_save;
-		}
-	}
-
 	/* add the register save area to the initial frame size */
 	frame_size += (regs_to_save << 3);
 
@@ -2529,17 +2390,7 @@ _jit_gen_epilog(jit_gencode_t gen, jit_function_t func)
 	if(gen->stack_changed)
 	{
 		int frame_size = func->builder->frame_size;
-		int regs_saved = 0;
-
-		/* Get the number of registers we preserves */
-		for(reg = 0; reg < 14; ++reg)
-		{
-			if(jit_reg_is_used(gen->touched, reg) &&
-			   (_jit_reg_info[reg].flags & JIT_REG_CALL_USED) == 0)
-			{
-				++regs_saved;
-			}
-		}
+		int regs_saved = _jit_count_regs_saved(gen);
 
 		/* add the register save area to the initial frame size */
 		frame_size += (regs_saved << 3);
@@ -2547,7 +2398,7 @@ _jit_gen_epilog(jit_gencode_t gen, jit_function_t func)
 		/* Make sure that the framesize is a multiple of 16 bytes */
 		/* so that the final RSP will be alligned on a 16byte boundary. */
 		frame_size = (frame_size + 0xf) & ~0xf;
-
+		
 		current_offset = -frame_size;
 
 		for(reg = 0; reg <= 14; ++reg)
@@ -2698,52 +2549,52 @@ memory_copy(jit_gencode_t gen, unsigned char *inst,
 			int dreg, jit_nint doffset,
 			int sreg, jit_nint soffset, jit_nint size)
 {
-	if(dreg == X86_64_RDI)
+	if(dreg == ARGREG1)
 	{
-		if(sreg != X86_64_RSI)
+		if(sreg != ARGREG2)
 		{
-			x86_64_mov_reg_reg_size(inst, X86_64_RSI, sreg, 8);
+			x86_64_mov_reg_reg_size(inst, ARGREG2, sreg, 8);
 		}
 	}
-	else if(dreg == X86_64_RSI)
+	else if(dreg == ARGREG2)
 	{
-		if(sreg == X86_64_RDI)
+		if(sreg == ARGREG1)
 		{
 			/* The registers are swapped so we need a temporary register */
-			x86_64_mov_reg_reg_size(inst, X86_64_RCX, X86_64_RSI, 8);
-			x86_64_mov_reg_reg_size(inst, X86_64_RSI, X86_64_RDI, 8);
-			x86_64_mov_reg_reg_size(inst, X86_64_RDI, X86_64_RCX, 8);
+			x86_64_mov_reg_reg_size(inst, X86_64_RCX, ARGREG2, 8);
+			x86_64_mov_reg_reg_size(inst, ARGREG2, ARGREG1, 8);
+			x86_64_mov_reg_reg_size(inst, ARGREG1, X86_64_RCX, 8);
 		}
 		else
 		{
-			x86_64_mov_reg_reg_size(inst, X86_64_RDI, X86_64_RSI, 8);
-			if(sreg != X86_64_RSI)
+			x86_64_mov_reg_reg_size(inst, ARGREG1, ARGREG2, 8);
+			if(sreg != ARGREG2)
 			{
-				x86_64_mov_reg_reg_size(inst, X86_64_RSI, sreg, 8);
+				x86_64_mov_reg_reg_size(inst, ARGREG2, sreg, 8);
 			}
 		}
 	}
 	else
 	{
-		x86_64_mov_reg_reg_size(inst, X86_64_RSI, sreg, 8);
-		x86_64_mov_reg_reg_size(inst, X86_64_RDI, dreg, 8);
+		x86_64_mov_reg_reg_size(inst, ARGREG2, sreg, 8);
+		x86_64_mov_reg_reg_size(inst, ARGREG1, dreg, 8);
 	}
 	/* Move the size to argument register 3 now */
 	if((size > 0) && (size <= jit_max_uint))
 	{
-		x86_64_mov_reg_imm_size(inst, X86_64_RDX, size, 4);
+		x86_64_mov_reg_imm_size(inst, ARGREG3, size, 4);
 	}
 	else
 	{
-		x86_64_mov_reg_imm_size(inst, X86_64_RDX, size, 8);
+		x86_64_mov_reg_imm_size(inst, ARGREG3, size, 8);
 	}
 	if(soffset != 0)
 	{
-		x86_64_add_reg_imm_size(inst, X86_64_RSI, soffset, 8);
+		x86_64_add_reg_imm_size(inst, ARGREG2, soffset, 8);
 	}
 	if(doffset != 0)
 	{
-		x86_64_add_reg_imm_size(inst, X86_64_RDI, doffset, 8);
+		x86_64_add_reg_imm_size(inst, ARGREG1, doffset, 8);
 	}
 	inst = x86_64_call_code(inst, (jit_nint)jit_memcpy);
 	return inst;
@@ -3580,6 +3431,9 @@ _jit_init_args(int abi, jit_param_passing_t *passing)
 	passing->word_regs = _jit_word_arg_regs;
 	passing->max_float_regs = _jit_num_float_regs;
 	passing->float_regs = _jit_float_arg_regs;
+#ifdef WIN64
+	passing->stack_size += 32;
+#endif
 }
 
 int
diff --git a/jit/jit-rules-x86-64.h b/jit/jit-rules-x86-64.h
index 37b896d..ca18b8d 100644
--- a/jit/jit-rules-x86-64.h
+++ b/jit/jit-rules-x86-64.h
@@ -36,49 +36,95 @@ extern	"C" {
 	(JIT_REG_FLOAT32 | JIT_REG_FLOAT64)
 #define JIT_REG_X86_64_GENERAL	\
 	(JIT_REG_WORD | JIT_REG_LONG)
+#ifdef WIN64
 #define	JIT_REG_INFO	\
-	{"rax", 0, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
-	{"rcx", 1, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
-	{"rdx", 2, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
-	{"rbx", 3, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
-	{"rsi", 6, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
-	{"rdi", 7, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
-	{"r8",  8, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
-	{"r9",  9, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
-	{"r10", 10, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
-	{"r11", 11, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
-	{"r12", 12, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
-	{"r13", 13, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
-	{"r14", 14, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
-	{"r15", 15, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
-	{"rbp", 5, -1, JIT_REG_FRAME | JIT_REG_FIXED | JIT_REG_CALL_USED}, \
-	{"rsp", 4, -1, JIT_REG_STACK_PTR | JIT_REG_FIXED | JIT_REG_CALL_USED}, \
-	{"xmm0", 0, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm1", 1, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm2", 2, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm3", 3, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm4", 4, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm5", 5, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm6", 6, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm7", 7, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm8", 8, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm9", 9, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm10", 10, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm11", 11, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm12", 12, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm13", 13, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm14", 14, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"xmm15", 15, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
-	{"st0", 0, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st1", 1, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st2", 2, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st3", 3, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st4", 4, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st5", 5, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st6", 6, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st7", 7, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK},
+	{"rax", NULL, 0, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"rcx", "intarg1", 1, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"rdx", "intarg2", 2, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"rbx", NULL, 3, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
+	{"rsi", NULL, 6, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
+	{"rdi", NULL, 7, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
+	{"r8",  "intarg3", 8, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"r9",  "intarg4", 9, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"r10", NULL, 10, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"r11", NULL, 11, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"r12", NULL, 12, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
+	{"r13", NULL, 13, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
+	{"r14", NULL, 14, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
+	{"r15", NULL, 15, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
+	{"rbp", NULL, 5, -1, JIT_REG_FRAME | JIT_REG_FIXED | JIT_REG_CALL_USED}, \
+	{"rsp", NULL, 4, -1, JIT_REG_STACK_PTR | JIT_REG_FIXED | JIT_REG_CALL_USED}, \
+	{"xmm0", "xmmarg1", 0, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm1", "xmmarg2", 1, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm2", "xmmarg3", 2, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm3", "xmmarg4", 3, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm4", NULL, 4, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm5", NULL, 5, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm6", NULL, 6, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm7", NULL, 7, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm8", NULL, 8, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm9", NULL, 9, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm10", NULL, 10, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm11", NULL, 11, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm12", NULL, 12, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm13", NULL, 13, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm14", NULL, 14, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm15", NULL, 15, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"st0", NULL, 0, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st1", NULL, 1, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st2", NULL, 2, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st3", NULL, 3, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st4", NULL, 4, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st5", NULL, 5, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st6", NULL, 6, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st7", NULL, 7, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK},
+#define	JIT_NUM_REGS		40
+#define	JIT_NUM_GLOBAL_REGS	7
+#else
+#define	JIT_REG_INFO	\
+	{"rax", NULL, 0, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"rcx", "intarg4", 1, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"rdx", "intarg3", 2, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"rbx", NULL, 3, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
+	{"rsi", "intarg2", 6, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"rdi", "intarg1", 7, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"r8",  "intarg5", 8, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"r9",  "intarg6", 9, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"r10", NULL, 10, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"r11", NULL, 11, -1, JIT_REG_X86_64_GENERAL | JIT_REG_CALL_USED}, \
+	{"r12", NULL, 12, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
+	{"r13", NULL, 13, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
+	{"r14", NULL, 14, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
+	{"r15", NULL, 15, -1, JIT_REG_X86_64_GENERAL | JIT_REG_GLOBAL}, \
+	{"rbp", NULL, 5, -1, JIT_REG_FRAME | JIT_REG_FIXED | JIT_REG_CALL_USED}, \
+	{"rsp", NULL, 4, -1, JIT_REG_STACK_PTR | JIT_REG_FIXED | JIT_REG_CALL_USED}, \
+	{"xmm0", "xmmarg1", 0, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm1", "xmmarg2", 1, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm2", "xmmarg3", 2, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm3", "xmmarg4", 3, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm4", "xmmarg5", 4, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm5", "xmmarg6", 5, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm6", "xmmarg7", 6, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm7", "xmmarg8", 7, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm8", NULL, 8, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm9", NULL, 9, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm10", NULL, 10, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm11", NULL, 11, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm12", NULL, 12, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm13", NULL, 13, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm14", NULL, 14, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"xmm15", NULL, 15, -1, JIT_REG_X86_64_XMM | JIT_REG_CALL_USED}, \
+	{"st0", NULL, 0, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st1", NULL, 1, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st2", NULL, 2, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st3", NULL, 3, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st4", NULL, 4, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st5", NULL, 5, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st6", NULL, 6, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st7", NULL, 7, -1, JIT_REG_X86_64_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK},
 #define	JIT_NUM_REGS		40
 #define	JIT_NUM_GLOBAL_REGS	5
+#endif
 
 #define JIT_REG_STACK		1
 #define JIT_REG_STACK_START	32
diff --git a/jit/jit-rules-x86-64.ins b/jit/jit-rules-x86-64.ins
index f8a1096..df23dc0 100644
--- a/jit/jit-rules-x86-64.ins
+++ b/jit/jit-rules-x86-64.ins
@@ -499,8 +499,13 @@ JIT_OP_SET_PARAM_NFLOAT: note
 			x86_64_fstp_membase_size(inst, X86_64_RSP, $2, 8);
 		}
 	}
-
+  
 JIT_OP_SET_PARAM_STRUCT: note
+	[reg, imm, scratch reg, scratch xreg,
+		if("$2 <= _JIT_MAX_MEMCPY_INLINE")] -> {
+		jit_nint offset = jit_value_get_nint_constant(insn->dest);
+		inst = small_block_copy(gen, inst, X86_64_RSP, offset, $1, 0, $2, $3, $4, 1);
+	}
 	[reg, imm, clobber(creg), clobber(xreg)] -> {
 		/* Handle arbitrary-sized structures */
 		jit_nint offset = jit_value_get_nint_constant(insn->dest);
@@ -508,7 +513,7 @@ JIT_OP_SET_PARAM_STRUCT: note
 		inst = memory_copy(gen, inst, X86_64_RSP, offset, $1, 0, $2);
 	}
 
-
+  
 /*
  * Opcodes to handle return values
  */
@@ -3000,7 +3005,9 @@ JIT_OP_CALL_TAIL:
 
 JIT_OP_CALL_INDIRECT:
 	[] -> {
+#ifndef WIN64
 		x86_64_mov_reg_imm_size(inst, X86_64_RAX, 8, 4);
+#endif
 		x86_64_call_reg(inst, X86_64_SCRATCH);
 	}
 
@@ -3013,7 +3020,9 @@ JIT_OP_CALL_INDIRECT_TAIL:
 
 JIT_OP_CALL_VTABLE_PTR:
 	[] -> {
+#ifndef WIN64
 		x86_64_mov_reg_imm_size(inst, X86_64_RAX, 8, 4);
+#endif
 		x86_64_call_reg(inst, X86_64_SCRATCH);
 	}
 
@@ -3158,12 +3167,55 @@ JIT_OP_MEMCPY: ternary
 	[reg, reg, imm, clobber(creg), clobber(xreg)] -> {
 		inst = memory_copy(gen, inst, $1, 0, $2, 0, $3);
 	}
-	[reg("rdi"), reg("rsi"), reg("rdx"), clobber(creg), clobber(xreg)] -> {
+	[reg("argreg1"), reg("argreg2"), reg("argreg3"), clobber(creg), clobber(xreg)] -> {
 		inst = x86_64_call_code(inst, (jit_nint)jit_memcpy);
 	}
 
 JIT_OP_MEMSET: ternary
-	[reg("rdi"), reg("rsi"), reg("rdx"), clobber(creg), clobber(xreg)] -> {
+	[any, any, imm, if("$3 <= 0")] -> { }
+	[reg, imm, imm, scratch reg, if("$3 <= 64 && $2 == 0")] -> {
+		int disp;
+		disp = 0;
+		x86_64_xor_reg_reg_size(inst, $4, $4, 8);
+		while($3 >= (disp + 8))
+		{
+			x86_64_mov_membase_reg_size(inst, $1, disp, $4, 8);
+			disp += 8;
+		}
+		if($3 >= (disp + 4))
+		{
+			x86_64_mov_membase_reg_size(inst, $1, disp, $4, 4);
+			disp += 4;
+		}
+		if($3 >= (disp + 2))
+		{
+			x86_64_mov_membase_reg_size(inst, $1, disp, $4, 2);
+			disp += 2;
+		}
+		if(insn->value2->address > disp)
+		{
+			x86_64_mov_membase_reg_size(inst, $1, disp, $4, 1);
+		}
+	}
+	[reg, imm, imm, if("$3 <= 32")] -> {
+		int disp;
+		disp = 0;
+		while($3 >= (disp + 4))
+		{
+			x86_64_mov_membase_imm_size(inst, $1, disp, $2 * 0x01010101, 4);
+			disp += 4;
+		}
+		if($3 >= (disp + 2))
+		{
+			x86_64_mov_membase_imm_size(inst, $1, disp, $2 * 0x0101, 2);
+			disp += 2;
+		}
+		if(insn->value2->address > disp)
+		{
+			x86_64_mov_membase_imm_size(inst, $1, disp, $2, 1);
+		}
+	}
+	[reg("intarg1"), reg("intarg2"), reg("intarg3"), clobber(creg), clobber(xreg)] -> {
 		inst = x86_64_call_code(inst, (jit_nint)jit_memset);
 	}
 
diff --git a/jit/jit-rules-x86.c b/jit/jit-rules-x86.c
index 244e42a..efd3218 100644
--- a/jit/jit-rules-x86.c
+++ b/jit/jit-rules-x86.c
@@ -786,15 +786,15 @@ _jit_gen_load_value(jit_gencode_t gen, int reg, int other_reg, jit_value_t value
 			{
 				jit_float32 float32_value;
 				float32_value = jit_value_get_float32_constant(value);
-				if(IS_WORD_REG(reg))
+				union
 				{
-					union
-					{
-						jit_float32 float32_value;
-						jit_int int_value;
-					} un;
+					jit_float32 float32_value;
+					jit_int int_value;
+				} un;
+				un.float32_value = float32_value;
 
-					un.float32_value = float32_value;
+				if(IS_WORD_REG(reg))
+				{
 					x86_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg, un.int_value);
 				}
 				else
@@ -809,9 +809,9 @@ _jit_gen_load_value(jit_gencode_t gen, int reg, int other_reg, jit_value_t value
 					}
 					else
 					{
-						ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float32));
-						jit_memcpy(ptr, &float32_value, sizeof(float32_value));
-						x86_fld(inst, ptr, 0);
+						x86_push_imm(inst, un.int_value);
+						x86_fld_membase(inst,X86_ESP,0,0);
+						x86_alu_reg_imm(inst, X86_ADD, X86_ESP, sizeof(un));
 					}
 				}
 			}
@@ -821,15 +821,16 @@ _jit_gen_load_value(jit_gencode_t gen, int reg, int other_reg, jit_value_t value
 			{
 				jit_float64 float64_value;
 				float64_value = jit_value_get_float64_constant(value);
-				if(IS_WORD_REG(reg))
+				union
 				{
-					union
-					{
-						jit_float64 float64_value;
-						jit_int int_value[2];
-					} un;
+					jit_float64 float64_value;
+					jit_int int_value[2];
+				} un;
+
+				un.float64_value = float64_value;
 
-					un.float64_value = float64_value;
+				if(IS_WORD_REG(reg))
+				{
 					x86_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg,
 							un.int_value[0]);
 					x86_mov_reg_imm(inst, _jit_reg_info[other_reg].cpu_reg,
@@ -847,9 +848,10 @@ _jit_gen_load_value(jit_gencode_t gen, int reg, int other_reg, jit_value_t value
 					}
 					else
 					{
-						ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_float64));
-						jit_memcpy(ptr, &float64_value, sizeof(float64_value));
-						x86_fld(inst, ptr, 1);
+						x86_push_imm(inst, un.int_value[1]);
+						x86_push_imm(inst, un.int_value[0]);
+						x86_fld_membase(inst,X86_ESP,0,1);
+						x86_alu_reg_imm(inst, X86_ADD, X86_ESP, sizeof(un));
 					}
 				}
 			}
@@ -859,15 +861,15 @@ _jit_gen_load_value(jit_gencode_t gen, int reg, int other_reg, jit_value_t value
 			{
 				jit_nfloat nfloat_value;
 				nfloat_value = jit_value_get_nfloat_constant(value);
-				if(IS_WORD_REG(reg) && sizeof(jit_nfloat) == sizeof(jit_float64))
+				union
 				{
-					union
-					{
-						jit_nfloat nfloat_value;
-						jit_int int_value[2];
-					} un;
+					jit_nfloat nfloat_value;
+					jit_int int_value[2];
+				} un;
+				un.nfloat_value = nfloat_value;
 
-					un.nfloat_value = nfloat_value;
+				if(IS_WORD_REG(reg) && sizeof(jit_nfloat) == sizeof(jit_float64))
+				{
 					x86_mov_reg_imm(inst, _jit_reg_info[reg].cpu_reg,
 							un.int_value[0]);
 					x86_mov_reg_imm(inst, _jit_reg_info[other_reg].cpu_reg,
@@ -885,16 +887,17 @@ _jit_gen_load_value(jit_gencode_t gen, int reg, int other_reg, jit_value_t value
 					}
 					else
 					{
-						ptr = _jit_cache_alloc(&(gen->posn), sizeof(jit_nfloat));
-						jit_memcpy(ptr, &nfloat_value, sizeof(nfloat_value));
+						x86_push_imm(inst, un.int_value[1]);
+						x86_push_imm(inst, un.int_value[0]);
 						if(sizeof(jit_nfloat) == sizeof(jit_float64))
 						{
-							x86_fld(inst, ptr, 1);
+							x86_fld_membase(inst,X86_ESP,0,1);
 						}
 						else
 						{
-							x86_fld80_mem(inst, ptr);
+							x86_fld80_membase(inst,X86_ESP,0);
 						}
+						x86_alu_reg_imm(inst, X86_ADD, X86_ESP, sizeof(un));
 					}
 				}
 			}
diff --git a/jit/jit-rules-x86.h b/jit/jit-rules-x86.h
index 464be64..fef4fa7 100644
--- a/jit/jit-rules-x86.h
+++ b/jit/jit-rules-x86.h
@@ -33,22 +33,22 @@ extern	"C" {
 #define	JIT_REG_X86_FLOAT	\
 	(JIT_REG_FLOAT32 | JIT_REG_FLOAT64 | JIT_REG_NFLOAT)
 #define	JIT_REG_INFO	\
-	{"eax", 0, 2, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_CALL_USED}, \
-	{"ecx", 1, 3, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_CALL_USED}, \
-	{"edx", 2, -1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
-	{"ebx", 3, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
-	{"esi", 6, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
-	{"edi", 7, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
-	{"ebp", 4, -1, JIT_REG_FRAME | JIT_REG_FIXED}, \
-	{"esp", 5, -1, JIT_REG_STACK_PTR | JIT_REG_FIXED | JIT_REG_CALL_USED}, \
-	{"st",  0, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st1", 1, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st2", 2, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st3", 3, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st4", 4, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st5", 5, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st6", 6, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
-	{"st7", 7, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK},
+	{"eax", NULL, 0, 2, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_CALL_USED}, \
+	{"ecx", NULL, 1, 3, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_CALL_USED}, \
+	{"edx", NULL, 2, -1, JIT_REG_WORD | JIT_REG_CALL_USED}, \
+	{"ebx", NULL, 3, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
+	{"esi", NULL, 6, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
+	{"edi", NULL, 7, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
+	{"ebp", NULL, 4, -1, JIT_REG_FRAME | JIT_REG_FIXED}, \
+	{"esp", NULL, 5, -1, JIT_REG_STACK_PTR | JIT_REG_FIXED | JIT_REG_CALL_USED}, \
+	{"st", NULL,  0, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st1", NULL, 1, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st2", NULL, 2, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st3", NULL, 3, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st4", NULL, 4, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st5", NULL, 5, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st6", NULL, 6, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
+	{"st7", NULL, 7, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK},
 #define	JIT_NUM_REGS		16
 #define	JIT_NUM_GLOBAL_REGS	3
 
diff --git a/jit/jit-rules.h b/jit/jit-rules.h
index 3093cdd..904e8d1 100644
--- a/jit/jit-rules.h
+++ b/jit/jit-rules.h
@@ -63,6 +63,7 @@ extern	"C" {
 typedef struct
 {
 	const char		*name;		/* Name of the register, for debugging */
+	const char		*alias;		/* Alias of the register (eg.: "argreg1", "argreg2", etc. */
 	short			cpu_reg;	/* CPU register number */
 	short			other_reg;	/* Other register for a "long" pair, or -1 */
 	int			flags;		/* Flags that define the register type */
@@ -116,6 +117,9 @@ extern jit_reginfo_t const _jit_reg_info[JIT_NUM_REGS];
 /* Get register name. */
 #define jit_reg_name(reg)		(_jit_reg_info[reg].name)
 
+/* Get register alias. */
+#define jit_reg_alias(reg)		(_jit_reg_info[reg].alias)
+
 /* Get register flags. */
 #define jit_reg_flags(reg)		(_jit_reg_info[reg].flags)
 
diff --git a/tools/gen-apply-win64.h b/tools/gen-apply-win64.h
new file mode 100644
index 0000000..473f61c
--- /dev/null
+++ b/tools/gen-apply-win64.h
@@ -0,0 +1,78 @@
+/*
+ * gen-apply-win64.h - Windows X64 definitions.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This file is part of the libjit library.
+ *
+ * The libjit library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * The libjit library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the libjit library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef	_GEN_APPLY_WIN64_H
+#define	_GEN_APPLY_WIN64_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#define JIT_APPLY_NUM_WORD_REGS 4
+#define JIT_APPLY_NUM_FLOAT_REGS 4
+#define JIT_APPLY_ARG_REGISTERS_OVERLAP 1
+#define JIT_APPLY_PASS_STACK_FLOAT_AS_DOUBLE 0
+#define JIT_APPLY_PASS_STACK_FLOAT_AS_NFLOAT 0
+#define JIT_APPLY_PASS_STACK_DOUBLE_AS_NFLOAT 0
+#define JIT_APPLY_PASS_STACK_NFLOAT_AS_DOUBLE 0
+#define JIT_APPLY_PASS_REG_FLOAT_AS_DOUBLE 0
+#define JIT_APPLY_PASS_REG_FLOAT_AS_NFLOAT 0
+#define JIT_APPLY_PASS_REG_DOUBLE_AS_NFLOAT 0
+#define JIT_APPLY_PASS_REG_NFLOAT_AS_DOUBLE 0
+#define JIT_APPLY_RETURN_FLOAT_AS_DOUBLE 0
+#define JIT_APPLY_RETURN_FLOAT_AS_NFLOAT 0
+#define JIT_APPLY_RETURN_DOUBLE_AS_NFLOAT 0
+#define JIT_APPLY_RETURN_NFLOAT_AS_DOUBLE 0
+#define JIT_APPLY_FLOATS_IN_WORD_REGS 0
+#define JIT_APPLY_RETURN_FLOATS_AFTER 8
+#define JIT_APPLY_VARARGS_ON_STACK 1
+#define JIT_APPLY_STRUCT_RETURN_SPECIAL_REG 0
+#define JIT_APPLY_STRUCT_REG_OVERLAPS_WORD_REG 0
+#define JIT_APPLY_ALIGN_LONG_REGS 1
+#define JIT_APPLY_ALIGN_LONG_STACK 1
+#define JIT_APPLY_CAN_SPLIT_LONG 0
+#define JIT_APPLY_STRUCT_RETURN_IN_REG \
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+#define JIT_APPLY_MAX_STRUCT_IN_REG 0
+#define JIT_APPLY_SPLIT_STRUCT_OVER_REGS 0
+#define JIT_APPLY_X86_FASTCALL 0
+#define JIT_APPLY_PARENT_FRAME_OFFSET 0
+#define JIT_APPLY_RETURN_ADDRESS_OFFSET 0
+#define JIT_APPLY_BROKEN_FRAME_BUILTINS 1
+#define JIT_APPLY_X86_POP_STRUCT_RETURN 0
+#define JIT_APPLY_PAD_FLOAT_REGS 1
+
+#define JIT_APPLY_NUM_DOUBLE_REGS 4
+#define JIT_APPLY_NUM_NFLOAT_REGS 0
+#define JIT_APPLY_DOUBLES_IN_WORD_REGS 0
+#define JIT_APPLY_NFLOATS_IN_WORD_REGS 0
+#define JIT_APPLY_RETURN_DOUBLES_AFTER 0
+#define JIT_APPLY_RETURN_NFLOATS_AFTER 0
+
+#ifdef	__cplusplus
+};
+#endif
+
+#endif	/* _GEN_APPLY_WIN64_H */
diff --git a/tools/gen-apply.c b/tools/gen-apply.c
index 2951802..d1239ed 100644
--- a/tools/gen-apply.c
+++ b/tools/gen-apply.c
@@ -98,7 +98,9 @@ the "jit-apply-rules.h" file.
 #if defined(PLATFORM_IS_MACOSX)
 	#include "gen-apply-macosx.h"
 #endif
-
+#if defined(__MINGW64__)
+	#include "gen-apply-win64.h"
+#endif
 /*
  * Values that are detected.
  */
@@ -107,6 +109,7 @@ int num_word_regs = 0;
 int num_float_regs = 0;
 int num_double_regs = 0;
 int num_nfloat_regs = 0;
+int arg_registers_overlap = 0;
 int pass_stack_float_as_double = 0;
 int pass_stack_float_as_nfloat = 0;
 int pass_stack_double_as_nfloat = 0;
@@ -137,6 +140,7 @@ int parent_frame_offset = 0;
 int return_address_offset = 0;
 int broken_frame_builtins = 0;
 int max_struct_in_reg = 0;
+int split_struct_over_regs = 1;
 int x86_pop_struct_return = 0;
 int pad_float_regs = 0;
 #else
@@ -144,6 +148,7 @@ int num_word_regs = JIT_APPLY_NUM_WORD_REGS;
 int num_float_regs = JIT_APPLY_NUM_FLOAT_REGS;
 int num_double_regs = JIT_APPLY_NUM_DOUBLE_REGS;
 int num_nfloat_regs = JIT_APPLY_NUM_NFLOAT_REGS;
+int arg_registers_overlap = JIT_APPLY_ARG_REGISTERS_OVERLAP;
 int pass_stack_float_as_double = JIT_APPLY_PASS_STACK_FLOAT_AS_DOUBLE;
 int pass_stack_float_as_nfloat = JIT_APPLY_PASS_STACK_FLOAT_AS_NFLOAT;
 int pass_stack_double_as_nfloat = JIT_APPLY_PASS_STACK_DOUBLE_AS_NFLOAT;
@@ -174,6 +179,7 @@ int parent_frame_offset = JIT_APPLY_PARENT_FRAME_OFFSET;
 int return_address_offset = JIT_APPLY_RETURN_ADDRESS_OFFSET;
 int broken_frame_builtins = JIT_APPLY_BROKEN_FRAME_BUILTINS;
 int max_struct_in_reg = JIT_APPLY_MAX_STRUCT_IN_REG;
+int split_struct_over_regs = JIT_APPLY_SPLIT_STRUCT_OVER_REGS;
 int x86_pop_struct_return = JIT_APPLY_X86_POP_STRUCT_RETURN;
 int pad_float_regs = JIT_APPLY_PAD_FLOAT_REGS;
 #endif
@@ -1868,6 +1874,10 @@ void dump_apply_macros(void)
 		printf("\t\t{ \\\n");
 		printf("\t\t\t(builder)->apply_args->word_regs[(builder)->word_used] = (jit_nint)(value); \\\n");
 		printf("\t\t\t++((builder)->word_used); \\\n");
+		if (arg_registers_overlap && num_float_regs > 0)
+		{
+			printf("\t\t\t++((builder)->float_used); \\\n");
+		}
 		if(struct_reg_overlaps_word_reg)
 		{
 			/* We need to set the struct register slot as well */
@@ -1899,6 +1909,10 @@ void dump_apply_macros(void)
 		printf("\t\t{ \\\n");
 		printf("\t\t\t(value) = (type)((builder)->apply_args->word_regs[(builder)->word_used]); \\\n");
 		printf("\t\t\t++((builder)->word_used); \\\n");
+		if (arg_registers_overlap && num_float_regs > 0)
+		{
+			printf("\t\t\t++((builder)->float_used); \\\n");
+		}
 		printf("\t\t} \\\n");
 		printf("\t\telse \\\n");
 		printf("\t\t{ \\\n");
@@ -1926,6 +1940,10 @@ void dump_apply_macros(void)
 			printf("\t\t\tif(((builder)->word_used %% 2) == 1) \\\n");
 			printf("\t\t\t{ \\\n");
 			printf("\t\t\t\t++((builder)->word_used); \\\n");
+			if (arg_registers_overlap && num_float_regs > 0)
+			{
+				printf("\t\t\t\t++((builder)->float_used); \\\n");
+			}
 			printf("\t\t\t} \\\n");
 		}
 		if(!can_split_long)
@@ -1933,6 +1951,10 @@ void dump_apply_macros(void)
 			printf("\t\t\tif((%s - (builder)->word_used) < (num_words)) \\\n", word_reg_limit);
 			printf("\t\t\t{ \\\n");
 			printf("\t\t\t\t(builder)->word_used = %s; \\\n", word_reg_limit);
+			if (arg_registers_overlap && num_float_regs > 0)
+			{
+				printf("\t\t\t\t(builder)->float_used = %s; \\\n", word_reg_limit);
+			}
 			printf("\t\t\t} \\\n");
 		}
 		printf("\t\t} \\\n");
@@ -1973,6 +1995,10 @@ void dump_apply_macros(void)
 		printf("\t\t{ \\\n");
 		printf("\t\t\tjit_memcpy((builder)->apply_args->word_regs + (builder)->word_used, (ptr), (size)); \\\n");
 		printf("\t\t\t(builder)->word_used += __num_words; \\\n");
+		if (arg_registers_overlap && num_float_regs > 0)
+		{
+			printf("\t\t\t(builder)->float_used = (builder)->word_used; \\\n");
+		}
 		printf("\t\t} \\\n");
 		printf("\t\telse if((builder)->word_used < %s) \\\n", word_reg_limit);
 		printf("\t\t{ \\\n");
@@ -1980,6 +2006,10 @@ void dump_apply_macros(void)
 		printf("\t\t\tjit_memcpy((builder)->apply_args->word_regs + (builder)->word_used, (ptr), __split * sizeof(jit_nint)); \\\n");
 		printf("\t\t\tjit_memcpy((builder)->apply_args->stack_args, ((jit_nint *)(ptr)) + __split, (size) - __split * sizeof(jit_nint)); \\\n");
 		printf("\t\t\t(builder)->word_used = %s; \\\n", word_reg_limit);
+		if (arg_registers_overlap && num_float_regs > 0)
+		{
+			printf("\t\t\t(builder)->float_used = %s; \\\n", word_reg_limit);
+		}
 		printf("\t\t\t(builder)->stack_used = __num_words - __split; \\\n");
 		printf("\t\t} \\\n");
 		printf("\t\telse \\\n");
@@ -1988,6 +2018,10 @@ void dump_apply_macros(void)
 		printf("\t\t\tjit_memcpy((builder)->apply_args->stack_args + (builder)->stack_used, (ptr), (size)); \\\n");
 		printf("\t\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
 		printf("\t\t\t(builder)->word_used = %s; \\\n", word_reg_limit);
+		if (arg_registers_overlap && num_float_regs > 0)
+		{
+			printf("\t\t\t(builder)->float_used = %s; \\\n", word_reg_limit);
+		}
 		printf("\t\t} \\\n");
 	}
 	else
@@ -2022,6 +2056,10 @@ void dump_apply_macros(void)
 		printf("\t\t\tjit_memcpy(&__temp, (builder)->apply_args->word_regs + (builder)->word_used, __split * sizeof(jit_nint)); \\\n");
 		printf("\t\t\tjit_memcpy(((jit_nint *)&__temp) + __split, (builder)->apply_args->stack_args, (__num_words - __split) * sizeof(jit_nint)); \\\n");
 		printf("\t\t\t(builder)->word_used = %s; \\\n", word_reg_limit);
+		if (arg_registers_overlap && num_float_regs > 0)
+		{
+			printf("\t\t\t(builder)->float_used = %s; \\\n", word_reg_limit);
+		}
 		printf("\t\t\t(builder)->stack_used = __num_words - __split; \\\n");
 		printf("\t\t} \\\n");
 		printf("\t\telse \\\n");
@@ -2030,6 +2068,10 @@ void dump_apply_macros(void)
 		printf("\t\t\tjit_memcpy(&__temp, (builder)->apply_args->stack_args + (builder)->stack_used, sizeof(__temp)); \\\n");
 		printf("\t\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
 		printf("\t\t\t(builder)->word_used = %s; \\\n", word_reg_limit);
+		if (arg_registers_overlap && num_float_regs > 0)
+		{
+			printf("\t\t\t(builder)->float_used = %s; \\\n", word_reg_limit);
+		}
 		printf("\t\t} \\\n");
 	}
 	else
@@ -2173,6 +2215,10 @@ void dump_apply_macros(void)
 		printf("\t\t{ \\\n");
 		printf("\t\t\t(builder)->apply_args->float_regs[(builder)->float_used].float_value = (jit_reg_float)(value); \\\n");
 		printf("\t\t\t++((builder)->float_used); \\\n");
+		if (arg_registers_overlap && num_word_regs > 0)
+		{
+			printf("\t\t\t++((builder)->word_used); \\\n");
+		}
 		printf("\t\t} \\\n");
 		printf("\t\telse \\\n");
 		printf("\t\t{ \\\n");
@@ -2220,6 +2266,10 @@ void dump_apply_macros(void)
 		printf("\t\t{ \\\n");
 		printf("\t\t\t(builder)->apply_args->float_regs[(builder)->float_used].double_value = (jit_reg_double)(value); \\\n");
 		printf("\t\t\t++((builder)->float_used); \\\n");
+		if (arg_registers_overlap && num_word_regs > 0)
+		{
+			printf("\t\t\t++((builder)->word_used); \\\n");
+		}
 		printf("\t\t} \\\n");
 		printf("\t\telse \\\n");
 		if(pass_stack_double_as_nfloat)
@@ -2261,6 +2311,10 @@ void dump_apply_macros(void)
 		printf("\t\t{ \\\n");
 		printf("\t\t\t(builder)->apply_args->float_regs[(builder)->float_used].nfloat_value = (jit_reg_nfloat)(value); \\\n");
 		printf("\t\t\t++((builder)->float_used); \\\n");
+		if (arg_registers_overlap && num_word_regs > 0)
+		{
+			printf("\t\t\t++((builder)->word_used); \\\n");
+		}
 		printf("\t\t} \\\n");
 		printf("\t\telse \\\n");
 		if(pass_stack_nfloat_as_double)
@@ -2340,6 +2394,10 @@ void dump_apply_macros(void)
 		printf("\t\t{ \\\n");
 		printf("\t\t\t(value) = (jit_float32)((builder)->apply_args->float_regs[(builder)->float_used].float_value); \\\n");
 		printf("\t\t\t++((builder)->float_used); \\\n");
+		if (arg_registers_overlap && num_word_regs > 0)
+		{
+			printf("\t\t\t++((builder)->word_used); \\\n");
+		}
 		printf("\t\t} \\\n");
 		printf("\t\telse \\\n");
 		printf("\t\t{ \\\n");
@@ -2389,6 +2447,10 @@ void dump_apply_macros(void)
 		printf("\t\t{ \\\n");
 		printf("\t\t\t(value) = (jit_float64)((builder)->apply_args->float_regs[(builder)->float_used].double_value); \\\n");
 		printf("\t\t\t++((builder)->float_used); \\\n");
+		if (arg_registers_overlap && num_word_regs > 0)
+		{
+			printf("\t\t\t++((builder)->word_used); \\\n");
+		}
 		printf("\t\t} \\\n");
 		printf("\t\telse \\\n");
 		if(pass_stack_double_as_nfloat)
@@ -2432,6 +2494,10 @@ void dump_apply_macros(void)
 		printf("\t\t{ \\\n");
 		printf("\t\t\t(value) = (jit_nfloat)((builder)->apply_args->float_regs[(builder)->float_used].nfloat_value); \\\n");
 		printf("\t\t\t++((builder)->float_used); \\\n");
+		if (arg_registers_overlap && num_word_regs > 0)
+		{
+			printf("\t\t\t++((builder)->word_used); \\\n");
+		}
 		printf("\t\t} \\\n");
 		printf("\t\telse \\\n");
 		if(pass_stack_nfloat_as_double)
@@ -2494,6 +2560,10 @@ void dump_apply_macros(void)
 		printf("\t\t\t(builder)->stack_used += __num_words * sizeof(jit_nint); \\\n");
 		printf("\t\t\t(builder)->word_used = %s; \\\n", word_reg_limit);
 		printf("\t\t} \\\n");
+		if (arg_registers_overlap && num_float_regs > 0)
+		{
+			printf("\t\t(builder)->float_used = (builder)->word_used; \\\n");
+		}
 	}
 	else
 	{
@@ -2636,6 +2706,7 @@ int main(int argc, char *argv[])
 	printf("#define JIT_APPLY_NUM_FLOAT_REGS %d\n", num_float_regs);
 	printf("#define JIT_APPLY_NUM_DOUBLE_REGS %d\n", num_double_regs);
 	printf("#define JIT_APPLY_NUM_NFLOAT_REGS %d\n", num_nfloat_regs);
+	printf("#define JIT_APPLY_ARG_REGISTERS_OVERLAP %d\n", arg_registers_overlap);
 	printf("#define JIT_APPLY_PASS_STACK_FLOAT_AS_DOUBLE %d\n",
 		   pass_stack_float_as_double);
 	printf("#define JIT_APPLY_PASS_STACK_FLOAT_AS_NFLOAT %d\n",
@@ -2725,6 +2796,7 @@ int main(int argc, char *argv[])
 	}
 	printf("}\n");
 	printf("#define JIT_APPLY_MAX_STRUCT_IN_REG %d\n", max_struct_in_reg);
+	printf("#define JIT_APPLY_SPLIT_STRUCT_OVER_REGS %d\n", split_struct_over_regs);
 	printf("#define JIT_APPLY_MAX_APPLY_SIZE %d\n", max_apply_size);
 	printf("#define JIT_APPLY_X86_FASTCALL %d\n", x86_fastcall);
 	printf("#define JIT_APPLY_PARENT_FRAME_OFFSET %d\n", parent_frame_offset);
