From ca5a73c049856b08332a94ddcb3d0e475bbaa886 Mon Sep 17 00:00:00 2001
From: Stephen Bennett <sbennett@accelrys.com>
Date: Tue, 16 Mar 2010 13:38:05 +0000
Subject: [PATCH 1/3] Split the platform-specific parts of Call() into a separate header, so that it can be easily replaced by an x86_64 version

---
 API.xs      |  265 ++++-------------------------------------------------------
 call_i686.h |  227 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 243 insertions(+), 249 deletions(-)
 create mode 100644 call_i686.h

diff --git a/API.xs b/API.xs
index 33f3cb3..8755182 100755
--- a/API.xs
+++ b/API.xs
@@ -21,33 +21,6 @@
 #pragma optimize("", off)
 
 /*
-   "I have a dream."
-   Define one assembler macro for everyone: gcc, Borland C & MSVC
-   Is it possible?
-*/
-
-/* Borland C */
-#if (defined(__BORLANDC__) && __BORLANDC__ >= 452)
-    #define ASM_LOAD_EAX(param,type) \
-        __asm {                      \
-            mov    eax, type param ; \
-            push   eax             ; \
-        }
-/* MSVC compilers */
-#elif defined _MSC_VER
-    /* Disable warning about one missing macro parameter.
-       TODO: How we define a macro with an optional (empty) parameter? */
-    #pragma warning( disable : 4003 )
-    #define ASM_LOAD_EAX(param,type) { \
-    	__asm { mov eax, type param }; \
-    	__asm { push eax };            \
-    }
-/* GCC-MinGW Compiler */
-#elif (defined(__GNUC__))
-    #define ASM_LOAD_EAX(param,...)  asm ("push %0" :: "g" (param));
-#endif
-
-/*
  * some Perl macros for backward compatibility
  */
 #ifdef NT_BUILD_NUMBER
@@ -70,6 +43,8 @@
 #	define call_method(name, flags) perl_call_method(name, flags)
 #endif
 
+#include "call_i686.h"
+
 void pointerCallPack(SV* param, int idx, AV* types) {
 	dSP;
 	SV* type;
@@ -229,32 +204,11 @@ Call(api, ...)
 PPCODE:
     FARPROC ApiFunction;
     APIPARAM *params;
+	APIPARAM retval;
     // APISTRUCT *structs;
     // APICALLBACK *callbacks;
     SV** origST;
 
-    ApiPointer  *ApiFunctionPointer;
-    ApiNumber   *ApiFunctionNumber;
-    ApiFloat    *ApiFunctionFloat;
-    ApiDouble   *ApiFunctionDouble;
-    ApiVoid     *ApiFunctionVoid;
-    ApiInteger  *ApiFunctionInteger;
-
-    /* int    iParam; */
-    long   lParam;
-    float  fParam;
-    double dParam;
-    /* char   cParam; */
-    char  *pParam;
-    LPBYTE ppParam;
-
-    int    iReturn;
-    long   lReturn;
-    float  fReturn;
-    double dReturn;
-    char  *pReturn;
-    char  *cReturn; // a copy of pReturn
-
     HV*		obj;
     SV**	obj_proc;
     SV**	obj_proto;
@@ -504,183 +458,10 @@ PPCODE:
 #endif
 			}
 		}
-
-		/* #### PUSH THE PARAMETER ON THE (ASSEMBLER) STACK #### */
-        words_pushed = 0;
-        for(i = nin; i >= 0; i--) {
-            switch(params[i].t) {
-            case T_POINTER:
-            case T_STRUCTURE:
-                pParam = params[i].p;
-#ifdef WIN32_API_DEBUG
-                printf("(XS)Win32::API::Call: parameter %d (P) is %s\n", i, pParam);
-#endif
-                ASM_LOAD_EAX(pParam, dword ptr);
-                words_pushed++;
-                break;
-            case T_POINTERPOINTER:
-                ppParam = params[i].b;
-#ifdef WIN32_API_DEBUG
-                printf("(XS)Win32::API::Call: parameter %d (P) is %s\n", i, ppParam);
-#endif
-                ASM_LOAD_EAX(ppParam, dword ptr);
-                words_pushed++;
-                break;
-            case T_NUMBER:
-            case T_CHAR:
-                lParam = params[i].l;
-#ifdef WIN32_API_DEBUG
-                printf("(XS)Win32::API::Call: parameter %d (N) is %ld\n", i, lParam);
-#endif
-                ASM_LOAD_EAX(lParam);
-                words_pushed++;
-                break;
-            case T_FLOAT:
-                fParam = params[i].f;
-#ifdef WIN32_API_DEBUG
-                printf("(XS)Win32::API::Call: parameter %d (F) is %f\n", i, fParam);
-#endif
-                ASM_LOAD_EAX(fParam);
-                words_pushed++;
-                break;
-            case T_DOUBLE:
-                dParam = params[i].d;
-#ifdef WIN32_API_DEBUG
-                printf("(XS)Win32::API::Call: parameter %d (D) is %f\n", i, dParam);
-#endif
-#if (defined(_MSC_VER) || defined(BORLANDC))
-                __asm {
-                    mov   eax, dword ptr [dParam + 4]  ;
-                    push  eax                          ;
-                    mov   eax, dword ptr [dParam]      ;
-                    push  eax                          ;
-                };
-#elif (defined(__GNUC__))
-		/* probably uglier than necessary, but works */
-		asm ("pushl %0":: "g" (((unsigned int*)&dParam)[1]));
-		asm ("pushl %0":: "g" (((unsigned int*)&dParam)[0]));
-		/* { 
-		  int idc;
-		  printf ("dParam = ");
-		  for (idc = 0; idc < sizeof(dParam); idc++) {
-		    printf(" %2.2x",((unsigned char*)&dParam)[idc]);
-		  } 
-		  printf("   %f\n", dParam);
-		} */
-#endif
-                words_pushed++;
-                words_pushed++;
-                break;
-            case T_CODE:
-                lParam = params[i].l;
-#ifdef WIN32_API_DEBUG
-                printf("(XS)Win32::API::Call: parameter %d (K) is 0x%x\n", i, lParam);
-#endif
-                ASM_LOAD_EAX(lParam);
-                words_pushed++;
-                break;
-            }
-        }
     }
 
-	/* #### NOW CALL THE FUNCTION #### */
-    switch(tout) {
-    case T_NUMBER:
-        ApiFunctionNumber = (ApiNumber *) ApiFunction;
-#ifdef WIN32_API_DEBUG
-    	printf("(XS)Win32::API::Call: Calling ApiFunctionNumber()\n");
-#endif
-        lReturn = ApiFunctionNumber();
-        break;
-    case T_FLOAT:
-        ApiFunctionFloat = (ApiFloat *) ApiFunction;
-#ifdef WIN32_API_DEBUG
-    	printf("(XS)Win32::API::Call: Calling ApiFunctionFloat()\n");
-#endif
-#ifdef WIN32_API_DEBUG
-        printf("(XS)Win32::API::Call: ApiFunctionFloat returned %f\n", fReturn);
-#endif
-        break;
-    case T_DOUBLE:
-        ApiFunctionDouble = (ApiDouble *) ApiFunction;
-#ifdef WIN32_API_DEBUG
-    	printf("(XS)Win32::API::Call: Calling ApiFunctionDouble()\n");
-#endif
-#if (defined(_MSC_VER) || defined(__BORLANDC__))
-		/*
-			_asm {
-			call    dword ptr [ApiFunctionDouble]
-			fstp    qword ptr [dReturn]
-		}
-		*/
-	    dReturn = ApiFunctionDouble();
-#elif (defined(__GNUC__))
-	    dReturn = ApiFunctionDouble();
-            /*
-              asm ("call *%0"::"g" (ApiFunctionDouble));
-              asm ("fstpl %st(0)");
-              asm ("movl %0,(%esp)");
-            */
-	/* XST_mNV(0, (double) dReturn); */
-#endif
-#ifdef WIN32_API_DEBUG
-       printf("(XS)Win32::API::Call: ApiFunctionDouble returned %f\n", dReturn);
-#endif
-        break;
-    case T_POINTER:
-        ApiFunctionPointer = (ApiPointer *) ApiFunction;
-#ifdef WIN32_API_DEBUG
-    	printf("(XS)Win32::API::Call: Calling ApiFunctionPointer()\n");
-#endif
-        pReturn = ApiFunctionPointer();
-#ifdef WIN32_API_DEBUG
-        printf("(XS)Win32::API::Call: ApiFunctionPointer returned 0x%x '%s'\n", pReturn, pReturn);
-#endif
-		/* #### only works with strings... #### */
-		cReturn = (char *) safemalloc(strlen(pReturn));
-		strcpy(cReturn, pReturn);
-
-        break;
-    case T_INTEGER:
-        ApiFunctionInteger = (ApiInteger *) ApiFunction;
-#ifdef WIN32_API_DEBUG
-    	printf("(XS)Win32::API::Call: Calling ApiFunctionInteger()\n");
-#endif
-        iReturn = ApiFunctionInteger();
-#ifdef WIN32_API_DEBUG
-    	printf("(XS)Win32::API::Call: ApiFunctionInteger returned %d\n", iReturn);
-#endif
-        break;
-    case T_VOID:
-    default:
-#ifdef WIN32_API_DEBUG
-    	printf("(XS)Win32::API::Call: Calling ApiFunctionVoid() (tout=%d)\n", tout);
-#endif
-        ApiFunctionVoid = (ApiVoid *) ApiFunction;
-        ApiFunctionVoid();
-        break;
-    }
-
-    // cleanup stack for _cdecl type functions.
-    if (c_call) {
-#if (defined(_MSC_VER) || defined(__BORLANDC__))
-        _asm {
-            mov eax, dword ptr words_pushed
-            shl eax, 2
-            add esp, eax
-        }
-#elif (defined(__GNUC__))
-        asm ( 
-            "movl %0, %%eax\n" 
-            "shll $2, %%eax\n" 
-            "addl %%eax, %%esp\n" 
-
-            : /* no output */ 
-            : "m" (words_pushed) /* input */ 
-            : "%eax" /* modified registers */ 
-        );
-#endif
-    }
+	retval.t = tout;
+	Call_asm(ApiFunction, params, nin, &retval, c_call);
 
 	/* #### THIRD PASS: postfix pointers/structures #### */
     for(i = 0; i <= nin; i++) {
@@ -724,54 +505,40 @@ PPCODE:
     switch(tout) {
     case T_NUMBER:
 #ifdef WIN32_API_DEBUG
-	   	printf("(XS)Win32::API::Call: returning %d.\n", lReturn);
+	   	printf("(XS)Win32::API::Call: returning %d.\n", retval.l);
 #endif
-        XSRETURN_IV(lReturn);
+        XSRETURN_IV(retval.l);
         break;
     case T_FLOAT:
 #ifdef WIN32_API_DEBUG
-	   	printf("(XS)Win32::API::Call: returning %f.\n", fReturn);
+	   	printf("(XS)Win32::API::Call: returning %f.\n", retval.f);
 #endif
-        XSRETURN_NV((double) fReturn);
+        XSRETURN_NV((double) retval.f);
         break;
     case T_DOUBLE:
 #ifdef WIN32_API_DEBUG
-	   	printf("(XS)Win32::API::Call: returning %f.\n", dReturn);
-#endif
-#if (defined(_MSC_VER) || defined(__BORLANDC__))
-	_asm {
-	    call    dword ptr [ApiFunctionDouble] ;
-	    fstp    qword ptr [dReturn]           ;
-    	}
-    	/*  XSRETURN_NV(dReturn); */
-#elif (defined(__GNUC__))
-        dReturn = ApiFunctionDouble();
-        /*
-              asm ("call *%0"::"g" (ApiFunctionDouble));
-              asm ("fstpl %st(0)");
-              asm ("movl %0,(%esp)");
-        */
- 	/* XST_mNV(0, dReturn); */
+	   	printf("(XS)Win32::API::Call: returning %f.\n", retval.d);
 #endif
+		XSRETURN_NV(retval.d);
         break;
     case T_POINTER:
-		if(pReturn == NULL) {
+		if(retval.p == NULL) {
 #ifdef WIN32_API_DEBUG
 	   	printf("(XS)Win32::API::Call: returning NULL.\n");
 #endif
 			XSRETURN_IV(0);
 		} else {
 #ifdef WIN32_API_DEBUG
-		printf("(XS)Win32::API::Call: returning 0x%x '%s'\n", cReturn, cReturn);
+		printf("(XS)Win32::API::Call: returning 0x%x '%s'\n", retval.p, retval.p);
 #endif
-	        XSRETURN_PV(cReturn);
+	        XSRETURN_PV(retval.p);
 	    }
         break;
     case T_INTEGER:
 #ifdef WIN32_API_DEBUG
-	   	printf("(XS)Win32::API::Call: returning %d.\n", iReturn);
+	   	printf("(XS)Win32::API::Call: returning %d.\n", retval.l);
 #endif
-        XSRETURN_IV(iReturn);
+        XSRETURN_IV(retval.l);
         break;
     case T_VOID:
     default:
diff --git a/call_i686.h b/call_i686.h
new file mode 100644
index 0000000..54a8d90
--- /dev/null
+++ b/call_i686.h
@@ -0,0 +1,227 @@
+
+/*
+   "I have a dream."
+   Define one assembler macro for everyone: gcc, Borland C & MSVC
+   Is it possible?
+*/
+
+/* Borland C */
+#if (defined(__BORLANDC__) && __BORLANDC__ >= 452)
+    #define ASM_LOAD_EAX(param,type) \
+        __asm {                      \
+            mov    eax, type param ; \
+            push   eax             ; \
+        }
+/* MSVC compilers */
+#elif defined _MSC_VER
+    /* Disable warning about one missing macro parameter.
+       TODO: How we define a macro with an optional (empty) parameter? */
+    #pragma warning( disable : 4003 )
+    #define ASM_LOAD_EAX(param,type) { \
+    	__asm { mov eax, type param }; \
+    	__asm { push eax };            \
+    }
+/* GCC-MinGW Compiler */
+#elif (defined(__GNUC__))
+    #define ASM_LOAD_EAX(param,...)  asm ("push %0" :: "g" (param));
+#endif
+
+void Call_asm(FARPROC ApiFunction, APIPARAM *params, int nparams, APIPARAM *retval, BOOL c_call)
+{
+    ApiPointer  *ApiFunctionPointer;
+    ApiNumber   *ApiFunctionNumber;
+    ApiFloat    *ApiFunctionFloat;
+    ApiDouble   *ApiFunctionDouble;
+    ApiVoid     *ApiFunctionVoid;
+    ApiInteger  *ApiFunctionInteger;
+
+    /* int    iParam; */
+    long   lParam;
+    float  fParam;
+    double dParam;
+    /* char   cParam; */
+    char  *pParam;
+    LPBYTE ppParam;
+
+	char *pReturn;
+
+	int words_pushed;
+	int i;
+
+	/* #### PUSH THE PARAMETER ON THE (ASSEMBLER) STACK #### */
+	words_pushed = 0;
+	for(i = nparams; i >= 0; i--) {
+		switch(params[i].t) {
+		case T_POINTER:
+		case T_STRUCTURE:
+			pParam = params[i].p;
+#ifdef WIN32_API_DEBUG
+			printf("(XS)Win32::API::Call: parameter %d (P) is %s\n", i, pParam);
+#endif
+			ASM_LOAD_EAX(pParam, dword ptr);
+			words_pushed++;
+			break;
+		case T_POINTERPOINTER:
+			ppParam = params[i].b;
+#ifdef WIN32_API_DEBUG
+			printf("(XS)Win32::API::Call: parameter %d (P) is %s\n", i, ppParam);
+#endif
+			ASM_LOAD_EAX(ppParam, dword ptr);
+			words_pushed++;
+			break;
+		case T_NUMBER:
+		case T_CHAR:
+			lParam = params[i].l;
+#ifdef WIN32_API_DEBUG
+			printf("(XS)Win32::API::Call: parameter %d (N) is %ld\n", i, lParam);
+#endif
+			ASM_LOAD_EAX(lParam);
+			words_pushed++;
+			break;
+		case T_FLOAT:
+			fParam = params[i].f;
+#ifdef WIN32_API_DEBUG
+			printf("(XS)Win32::API::Call: parameter %d (F) is %f\n", i, fParam);
+#endif
+			ASM_LOAD_EAX(fParam);
+			words_pushed++;
+			break;
+		case T_DOUBLE:
+			dParam = params[i].d;
+#ifdef WIN32_API_DEBUG
+			printf("(XS)Win32::API::Call: parameter %d (D) is %f\n", i, dParam);
+#endif
+#if (defined(_MSC_VER) || defined(BORLANDC))
+			__asm {
+				mov   eax, dword ptr [dParam + 4]  ;
+				push  eax                          ;
+				mov   eax, dword ptr [dParam]      ;
+				push  eax                          ;
+			};
+#elif (defined(__GNUC__))
+	/* probably uglier than necessary, but works */
+	asm ("pushl %0":: "g" (((unsigned int*)&dParam)[1]));
+	asm ("pushl %0":: "g" (((unsigned int*)&dParam)[0]));
+	/* { 
+	  int idc;
+	  printf ("dParam = ");
+	  for (idc = 0; idc < sizeof(dParam); idc++) {
+		printf(" %2.2x",((unsigned char*)&dParam)[idc]);
+	  } 
+	  printf("   %f\n", dParam);
+	} */
+#endif
+			words_pushed++;
+			words_pushed++;
+			break;
+		case T_CODE:
+			lParam = params[i].l;
+#ifdef WIN32_API_DEBUG
+			printf("(XS)Win32::API::Call: parameter %d (K) is 0x%x\n", i, lParam);
+#endif
+			ASM_LOAD_EAX(lParam);
+			words_pushed++;
+			break;
+		}
+	}
+
+	/* #### NOW CALL THE FUNCTION #### */
+    switch(retval->t) {
+    case T_NUMBER:
+        ApiFunctionNumber = (ApiNumber *) ApiFunction;
+#ifdef WIN32_API_DEBUG
+    	printf("(XS)Win32::API::Call: Calling ApiFunctionNumber()\n");
+#endif
+        retval->l = ApiFunctionNumber();
+        break;
+    case T_FLOAT:
+        ApiFunctionFloat = (ApiFloat *) ApiFunction;
+#ifdef WIN32_API_DEBUG
+    	printf("(XS)Win32::API::Call: Calling ApiFunctionFloat()\n");
+#endif
+#ifdef WIN32_API_DEBUG
+        printf("(XS)Win32::API::Call: ApiFunctionFloat returned %f\n", retval->f);
+#endif
+        break;
+    case T_DOUBLE:
+        ApiFunctionDouble = (ApiDouble *) ApiFunction;
+#ifdef WIN32_API_DEBUG
+    	printf("(XS)Win32::API::Call: Calling ApiFunctionDouble()\n");
+#endif
+#if (defined(_MSC_VER) || defined(__BORLANDC__))
+		/*
+			_asm {
+			call    dword ptr [ApiFunctionDouble]
+			fstp    qword ptr [dReturn]
+		}
+		*/
+	    retval->d = ApiFunctionDouble();
+#elif (defined(__GNUC__))
+	    retval->d = ApiFunctionDouble();
+            /*
+              asm ("call *%0"::"g" (ApiFunctionDouble));
+              asm ("fstpl %st(0)");
+              asm ("movl %0,(%esp)");
+            */
+	/* XST_mNV(0, (double) dReturn); */
+#endif
+#ifdef WIN32_API_DEBUG
+       printf("(XS)Win32::API::Call: ApiFunctionDouble returned %f\n", retval->d);
+#endif
+        break;
+    case T_POINTER:
+        ApiFunctionPointer = (ApiPointer *) ApiFunction;
+#ifdef WIN32_API_DEBUG
+    	printf("(XS)Win32::API::Call: Calling ApiFunctionPointer()\n");
+#endif
+        pReturn = ApiFunctionPointer();
+#ifdef WIN32_API_DEBUG
+        printf("(XS)Win32::API::Call: ApiFunctionPointer returned 0x%x '%s'\n", pReturn, pReturn);
+#endif
+		/* #### only works with strings... #### */
+		retval->p = (char *) safemalloc(strlen(pReturn));
+		strcpy(retval->p, pReturn);
+
+        break;
+    case T_INTEGER:
+        ApiFunctionInteger = (ApiInteger *) ApiFunction;
+#ifdef WIN32_API_DEBUG
+    	printf("(XS)Win32::API::Call: Calling ApiFunctionInteger()\n");
+#endif
+        retval->l = ApiFunctionInteger();
+#ifdef WIN32_API_DEBUG
+    	printf("(XS)Win32::API::Call: ApiFunctionInteger returned %d\n", retval->l);
+#endif
+        break;
+    case T_VOID:
+    default:
+#ifdef WIN32_API_DEBUG
+    	printf("(XS)Win32::API::Call: Calling ApiFunctionVoid() (tout=%d)\n", retval->t);
+#endif
+        ApiFunctionVoid = (ApiVoid *) ApiFunction;
+        ApiFunctionVoid();
+        break;
+    }
+
+    // cleanup stack for _cdecl type functions.
+    if (c_call) {
+#if (defined(_MSC_VER) || defined(__BORLANDC__))
+        _asm {
+            mov eax, dword ptr words_pushed
+            shl eax, 2
+            add esp, eax
+        }
+#elif (defined(__GNUC__))
+        asm ( 
+            "movl %0, %%eax\n" 
+            "shll $2, %%eax\n" 
+            "addl %%eax, %%esp\n" 
+
+            : /* no output */ 
+            : "m" (words_pushed) /* input */ 
+            : "%eax" /* modified registers */ 
+        );
+#endif
+    }
+}
+
-- 
1.7.0.2.276.g60daf

