[Vm-dev] [commit][3443] Provide functional verisons of the Alien plugin for 64-bit unix ( Windows will

commits at squeakvm.org commits at squeakvm.org
Wed Sep 23 18:09:54 UTC 2015


Revision: 3443
Author:   eliot
Date:     2015-09-23 11:09:52 -0700 (Wed, 23 Sep 2015)
Log Message:
-----------
Provide functional verisons of the Alien plugin for 64-bit unix (Windows will
take a little more work).

Modified Paths:
--------------
    trunk/platforms/Cross/plugins/IA32ABI/dax64business.h
    trunk/platforms/Cross/plugins/IA32ABI/x64ia32abicc.c

Property Changed:
----------------
    trunk/platforms/Cross/plugins/sqPluginsSCCSVersion.h

Modified: trunk/platforms/Cross/plugins/IA32ABI/dax64business.h
===================================================================
--- trunk/platforms/Cross/plugins/IA32ABI/dax64business.h	2015-09-21 17:49:53 UTC (rev 3442)
+++ trunk/platforms/Cross/plugins/IA32ABI/dax64business.h	2015-09-23 18:09:52 UTC (rev 3443)
@@ -1,145 +1,194 @@
 /*
  *  dax64business.h
  *
- *  Written by Eliot Miranda 12/14
+ *  Written by Eliot Miranda 12/14, Ryan Macnak 9/15
  *
  * Body of the various callIA32XXXReturn functions.
  * Call a foreign function according to x64-ish ABI rules.
  * N.B. In Cog Stack and Cogit VMs numArgs is negative to access args from
  * the downward-growing stack.
  */
-	long i, size;
-	sqInt funcAlien, resultMaybeAlien;
-	char *argvec;
-	char *argstart;
 
-#if STACKVM /* Need to access args downwards from first arg */
-  if (numArgs < 0)
-	for (i = size = 0; --i >= numArgs;) {
-		sqInt arg = argVector[i+1];
-		if (objIsAlien(arg) && sizeField(arg))
-			size += moduloPOT(sizeof(long),abs(sizeField(arg)));
-		else if (interpreterProxy->isFloatObject(arg))
-			size += sizeof(double);
-		else /* assume an integer or pointer.  check below. */
-			size += sizeof(long);
+	long i;
+	long size;
+	long nextReg;
+	long nextDReg;
+	long regs[NUM_REG_ARGS];
+	double dregs[NUM_DREG_ARGS];
+	sqInt funcAlien;
+	sqInt resultMaybeAlien;
+	long argvec;
+	long argstart;
+
+        assert(sizeof(long) == sizeof(void*)); /* Will need to fix for Windows. */
+
+	if (numArgs < 0) {
+		/* Stack or Cog VM. Need to access args downwards from first arg. */
+		for (i = size = 0; --i >= numArgs;) {
+			sqInt arg = argVector[i + 1];
+			if (objIsAlien(arg) && (sizeField(arg) != 0))
+				/* Direct or indirect Alien. */
+                        	size += RoundUpPowerOfTwo(abs(sizeField(arg)), 8);
+			else if (interpreterProxy->isFloatObject(arg))
+				size += sizeof(double);
+			else 
+				/* Assume an integer or pointer Alien. Check below. */
+				size += sizeof(long);
+		}
 	}
-  else
-#endif /* STACKVM */
-	for (i = numArgs, size = 0; --i >= 0;) {
-		sqInt arg = argVector[i];
-		if (objIsAlien(arg) && sizeField(arg))
-			size += moduloPOT(sizeof(long),abs(sizeField(arg)));
-		else if (interpreterProxy->isFloatObject(arg))
-			size += sizeof(double);
-		else /* assume an integer or pointer.  check below. */
-			size += sizeof(long);
+	else {
+		/* Context Interpreter or array version of callout primitive. */
+		for (i = numArgs, size = 0; --i >= 0;) {
+			sqInt arg = argVector[i];
+			if (objIsAlien(arg) && (sizeField(arg) != 0))
+				/* Direct or indirect Alien. */
+                          size += RoundUpPowerOfTwo(abs(sizeField(arg)), 8);
+			else if (interpreterProxy->isFloatObject(arg))
+				size += sizeof(double);
+			else
+				/* Assume an integer or pointer Alien. Check below. */
+				size += sizeof(long);
+		}
 	}
 
-	/* At point of call stack must be aligned to STACK_ALIGN_BYTES.  So alloca
-	 * at least enough for this plus the argvector, and start writing argvector
-	 * at aligned point.  Then just prior to call cut-back stack to aligned.
-	 */
-	argvec = alloca(STACK_ALIGN_BYTES + moduloPOT(STACK_ALIGN_BYTES,size));
-	argvec = alignModuloPOT(STACK_ALIGN_BYTES, argvec);
-	argstart = argvec;
+	size = RoundUpPowerOfTwo(size, STACK_ALIGN_BYTES);
 
-#if STACKVM /* Need to access args downwards from first arg */
-  if (numArgs < 0)
-	for (i = size = 0; --i >= numArgs;) {
-		sqInt arg = argVector[i+1];
-		if (isSmallInt(arg)) {
-			*(long *)argvec = intVal(arg);
-			argvec += sizeof(long);
-		}
-		else if (objIsAlien(arg)) {
-			long  argByteSize;
+	argstart = argvec = (long)alloca(size);
 
-			if (!(size = sizeField(arg)))
-				size = argByteSize = sizeof(void *);
-			else
-				argByteSize = abs(size);
-			memcpy(argvec, startOfDataWithSize(arg,size), argByteSize);
-			argvec += moduloPOT(sizeof(long), argByteSize);
-		}
-		else if (objIsUnsafeAlien(arg)) {
-			sqInt bitsObj = interpreterProxy->fetchPointerofObject(0,arg);
-			void *v = interpreterProxy->firstIndexableField(bitsObj);
-			*(void **)argvec = v;
-			argvec += sizeof(long);
-		}
-		else if (interpreterProxy->isFloatObject(arg)) {
-			double d = interpreterProxy->floatValueOf(arg);
-			*(double *)argvec = d;
-			argvec += sizeof(double);
-		}
-		else {
-			long v = interpreterProxy->signed32BitValueOf(arg);
-			if (interpreterProxy->failed()) {
-				interpreterProxy->primitiveFailFor(0);
-				v = interpreterProxy->positive32BitValueOf(arg);
-				if (interpreterProxy->failed())
-					return PrimErrBadArgument;
+	nextReg = 0;
+	nextDReg = 0;
+
+#define MaybePassAsRegArg(expr) \
+	if (nextReg < NUM_REG_ARGS) \
+		regs[nextReg++] = expr; \
+	else { \
+        	*(long*)argvec = expr;        \
+		argvec += sizeof(long); \
+	}
+
+#define MaybePassAsDRegArg(expr) \
+	if (nextDReg < NUM_DREG_ARGS) \
+		dregs[nextDReg++] = expr; \
+	else { \
+ 		argvec = RoundUpPowerOfTwo(argvec, 8);  \
+		*(double*) argvec = expr; \
+		argvec += sizeof(double); \
+	}
+
+	if (numArgs < 0) {
+		/* Stack or Cog VM. Need to access args downwards from first arg. */
+		for (i = size = 0; --i >= numArgs;) {
+			sqInt arg = argVector[i+1];
+			if (isSmallInt(arg)) {
+				MaybePassAsRegArg(intVal(arg))
 			}
-			*(long *)argvec = v;
-			argvec += sizeof(long);
+			else if (objIsAlien(arg)) {
+				long argByteSize;
+				if ((size = sizeField(arg)) == 0) /* Pointer Alien. */
+					size = argByteSize = sizeof(void *);
+				else /* Direct or indirect Alien. */
+					argByteSize = abs(size);
+				if ((argByteSize <= sizeof(long)) && (nextReg < NUM_REG_ARGS)) {
+					regs[nextReg++] = *(long*)startOfDataWithSize(arg, size);
+				}
+				else {
+					memcpy((void*)argvec, startOfDataWithSize(arg, size), argByteSize);
+					argvec += RoundUpPowerOfTwo(argByteSize, 8);
+				}
+			}
+			else if (objIsUnsafeAlien(arg)) {
+				sqInt bitsObj = interpreterProxy->fetchPointerofObject(0,arg);
+				long v = (long)interpreterProxy->firstIndexableField(bitsObj);
+				MaybePassAsRegArg(v)
+			}
+			else if (interpreterProxy->isFloatObject(arg)) {
+				double d = interpreterProxy->floatValueOf(arg);
+				MaybePassAsDRegArg(d)
+			}
+			else {
+				long v = interpreterProxy->signed64BitValueOf(arg);
+				if (interpreterProxy->failed()) {
+					interpreterProxy->primitiveFailFor(0);
+					v = interpreterProxy->positive64BitValueOf(arg);
+					if (interpreterProxy->failed()) {
+						return PrimErrBadArgument;
+					}
+				}
+				MaybePassAsDRegArg(v)
+			}
 		}
 	}
-  else
-#endif /* STACKVM */
-	for (i = 0; i < numArgs; i++) {
-		sqInt arg = argVector[i];
-		if (isSmallInt(arg)) {
-			*(long *)argvec = intVal(arg);
-			argvec += sizeof(long);
-		}
-		else if (objIsAlien(arg)) {
-			long  argByteSize;
-
-			if (!(size = sizeField(arg)))
-				size = argByteSize = sizeof(void *);
-			else
-				argByteSize = abs(size);
-			memcpy(argvec, startOfDataWithSize(arg,size), argByteSize);
-			argvec += moduloPOT(sizeof(long), argByteSize);
-		}
-		else if (objIsUnsafeAlien(arg)) {
-			sqInt bitsObj = interpreterProxy->fetchPointerofObject(0,arg);
-			void *v = interpreterProxy->firstIndexableField(bitsObj);
-			*(void **)argvec = v;
-			argvec += sizeof(long);
-		}
-		else if (interpreterProxy->isFloatObject(arg)) {
-			double d = interpreterProxy->floatValueOf(arg);
-			*(double *)argvec = d;
-			argvec += sizeof(double);
-		}
-		else {
-			long v = interpreterProxy->signed32BitValueOf(arg);
-			if (interpreterProxy->failed()) {
-				interpreterProxy->primitiveFailFor(0);
-				v = interpreterProxy->positive32BitValueOf(arg);
-				if (interpreterProxy->failed())
-					return PrimErrBadArgument;
+	else {
+		/* Context Interpreter or array version of callout primitive. */
+		for (i = 0; i < numArgs; i++) {
+			sqInt arg = argVector[i];
+			if (isSmallInt(arg))
+				MaybePassAsDRegArg(intVal(arg))
+			else if (objIsAlien(arg)) {
+				long argByteSize;
+				if ((size = sizeField(arg)) == 0) /* Pointer Alien. */
+					size = argByteSize = sizeof(void *);
+				else /* Direct or indirect Alien. */
+					argByteSize = abs(size);
+				if ((argByteSize <= sizeof(long)) && (nextReg < NUM_REG_ARGS)) {
+					regs[nextReg++] = *(long*)startOfDataWithSize(arg, size);
+				}
+				else {
+					memcpy((void*)argvec, startOfDataWithSize(arg, size), argByteSize);
+					argvec += RoundUpPowerOfTwo(argByteSize, 8);
+				}
 			}
-			*(long *)argvec = v;
-			argvec += sizeof(long);
+			else if (objIsUnsafeAlien(arg)) {
+				sqInt bitsObj = interpreterProxy->fetchPointerofObject(0,arg);
+				long v = (long)interpreterProxy->firstIndexableField(bitsObj);
+				MaybePassAsRegArg(v)
+			}
+			else if (interpreterProxy->isFloatObject(arg)) {
+				double d = interpreterProxy->floatValueOf(arg);
+				MaybePassAsDRegArg(d)
+			}
+			else {
+				long v = interpreterProxy->signed64BitValueOf(arg);
+				if (interpreterProxy->failed()) {
+					interpreterProxy->primitiveFailFor(0);
+					v = interpreterProxy->positive64BitValueOf(arg);
+					if (interpreterProxy->failed()) {
+						return PrimErrBadArgument;
+					}
+				}
+				MaybePassAsRegArg(v)
+			}
 		}
 	}
 
 	funcAlien = interpreterProxy->stackValue(funcOffset);
-	f = *(void **)startOfParameterData(funcAlien);
-	/* cut stack back to start of aligned args */
-	setsp(argstart);
-	r = f();
-	/* post call need to refresh stack pointer in case of call-back and GC. */
+	f = *(void**)startOfParameterData(funcAlien);
+
+	/* Note that this call a) passes the integer reg args in regs in the core
+	 * integer registers, and b) passes the floating point args in dregs in the
+	 * floating-point co-processor registers.  Neat.
+     *
+	 * But this trick WILL NOT WORK on the Windows ABI. The first integer
+	 * argument allocates both the first integer register and the first float
+	 * register, and vice versa. This means the call below would pass all the
+	 * double arguments on the stack, which is not correct if there are double
+	 * arguments among the first four arguments.  Instead we will have to make
+	 * two separate calls, the first a call of a dummy function to load the
+	 * double arguments (if any) and the second to make the actual call.
+	 */
+	r = f(regs[0], regs[1], regs[2], regs[3], regs[4], regs[5],
+		  dregs[0], dregs[1], dregs[2], dregs[3],
+		  dregs[4], dregs[5], dregs[6], dregs[7]);
+
+	/* Post call need to refresh stack pointer in case of call-back and GC. */
 	resultMaybeAlien = interpreterProxy->stackValue(resultOffset);
 	if (objIsAlien(resultMaybeAlien)) {
-		if (!(size = sizeField(resultMaybeAlien)))
-			size = sizeof(void *);
-		memcpy(startOfDataWithSize(resultMaybeAlien,size),
-				&r,
-				min((unsigned)abs(size), sizeof(r)));
+		size = sizeField(resultMaybeAlien);
+		if (size == 0) /* Pointer Alien. */
+			size = sizeof(long);
+		memcpy(startOfDataWithSize(resultMaybeAlien, size),
+			   &r,
+			   min((unsigned)abs(size), sizeof(r)));
 	}
 
 	return PrimNoErr;

Modified: trunk/platforms/Cross/plugins/IA32ABI/x64ia32abicc.c
===================================================================
--- trunk/platforms/Cross/plugins/IA32ABI/x64ia32abicc.c	2015-09-21 17:49:53 UTC (rev 3442)
+++ trunk/platforms/Cross/plugins/IA32ABI/x64ia32abicc.c	2015-09-23 18:09:52 UTC (rev 3443)
@@ -2,7 +2,7 @@
  *  x86ia32abicc.c
  *
  * Support for Call-outs and Call-backs from the Plugin on x86_64.
- *  Written by Eliot Miranda 12/14
+ *  Written by Eliot Miranda 12/14, Ryan Macnak 9/15
  *
  * Based on
  *      System V Application Binary Interface
@@ -13,6 +13,7 @@
 
 #if defined(_MSC_VER) || defined(__MINGW32__)
 # include "windows.h" /* for GetSystemInfo & VirtualAlloc */
+# error Windows doesn't use the SystemV ABI
 #elif __APPLE__ && __MACH__
 # include <sys/mman.h> /* for mprotect */
 # if OBJC_DEBUG /* define this to get debug info for struct objc_class et al */
@@ -45,6 +46,9 @@
 # define min(a,b) ((a) < (b) ? (a) : (b))
 #endif
 
+#define NUM_REG_ARGS 6
+#define NUM_DREG_ARGS 8
+
 #ifdef SQUEAK_BUILTIN_PLUGIN
 extern
 #endif 
@@ -54,15 +58,18 @@
 # define setsp(sp) asm volatile ("movq %0,%%rsp" : : "m"(sp))
 # define getsp() ({ void *sp; asm volatile ("movq %%rsp,%0" : "=r"(sp) : ); sp;})
 #endif
-#define STACK_ALIGN_BYTES 32 /* x64ABI 3.2.2 */
+#define STACK_ALIGN_BYTES 32 /* 32 if a 256-bit argument is passed; 16 otherwise */
 
 #if !defined(setsp)
 # define setsp(ignored) 0
 #endif
 
-#define moduloPOT(m,v) (((v)+(m)-1) & ~((m)-1))
-#define alignModuloPOT(m,v) ((void *)moduloPOT(m,(unsigned long)(v)))
+#define RoundUpPowerOfTwo(value, modulus)                                      \
+  (((value) + (modulus) - 1) & ~((modulus) - 1))
 
+#define IsAlignedPowerOfTwo(value, modulus)                                    \
+  (((value) & ((modulus) - 1)) == 0)
+
 #define objIsAlien(anOop) (interpreterProxy->includesBehaviorThatOf(interpreterProxy->fetchClassOf(anOop), interpreterProxy->classAlien()))
 #define objIsUnsafeAlien(anOop) (interpreterProxy->includesBehaviorThatOf(interpreterProxy->fetchClassOf(anOop), interpreterProxy->classUnsafeAlien()))
 
@@ -84,9 +91,11 @@
  * Call a foreign function that answers an integral result in %rax (and
  * possibly %rdx?) according to x64-ish ABI rules.
  */
-sqInt
-callIA32IntegralReturn(SIGNATURE) {
-long (*f)(), r;
+sqInt callIA32IntegralReturn(SIGNATURE) {
+  long (*f)(long rdi, long rsi, long rdx, long rcx, long r8, long r9,
+            double xmm0, double xmm1, double xmm2, double xmm3,
+            double xmm4, double xmm5, double xmm6, double xmm7);
+  long r;
 #include "dax64business.h"
 }
 
@@ -94,8 +103,11 @@
  * Call a foreign function that answers a single-precision floating-point
  * result in %xmm0 according to x64-ish ABI rules.
  */
-sqInt
-callIA32FloatReturn(SIGNATURE) { float (*f)(), r;
+sqInt callIA32FloatReturn(SIGNATURE) {
+  float (*f)(long rdi, long rsi, long rdx, long rcx, long r8, long r9,
+             double xmm0, double xmm1, double xmm2, double xmm3,
+             double xmm4, double xmm5, double xmm6, double xmm7);
+  float r;
 #include "dax64business.h"
 }
 
@@ -103,8 +115,11 @@
  * Call a foreign function that answers a double-precision floating-point
  * result in %xmm0 according to x64-ish ABI rules.
  */
-sqInt
-callIA32DoubleReturn(SIGNATURE) { double (*f)(), r;
+sqInt callIA32DoubleReturn(SIGNATURE) {
+  double (*f)(long rdi, long rsi, long rdx, long rcx, long r8, long r9,
+              double xmm0, double xmm1, double xmm2, double xmm3,
+              double xmm4, double xmm5, double xmm6, double xmm7);
+  double r;
 #include "dax64business.h"
 }
 


Property changes on: trunk/platforms/Cross/plugins/sqPluginsSCCSVersion.h
___________________________________________________________________
Modified: checkindate
   - Mon Sep 21 10:49:22 PDT 2015
   + Wed Sep 23 11:09:06 PDT 2015



More information about the Vm-dev mailing list