[Vm-dev] [commit][3398] Add skeleton files for ARM implementation of the misnamed IA32ABI plugin.

commits at squeakvm.org commits at squeakvm.org
Tue Jul 7 19:03:12 UTC 2015


Revision: 3398
Author:   eliot
Date:     2015-07-07 12:03:10 -0700 (Tue, 07 Jul 2015)
Log Message:
-----------
Add skeleton files for ARM implementation of the misnamed IA32ABI plugin.

Modified Paths:
--------------
    trunk/platforms/Cross/plugins/IA32ABI/ia32abi.h
    trunk/platforms/Cross/plugins/IA32ABI/xabicc.c

Added Paths:
-----------
    trunk/platforms/Cross/plugins/IA32ABI/arm32ia32abicc.c
    trunk/platforms/Cross/plugins/IA32ABI/dabusinessARM.h

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

Added: trunk/platforms/Cross/plugins/IA32ABI/arm32ia32abicc.c
===================================================================
--- trunk/platforms/Cross/plugins/IA32ABI/arm32ia32abicc.c	                        (rev 0)
+++ trunk/platforms/Cross/plugins/IA32ABI/arm32ia32abicc.c	2015-07-07 19:03:10 UTC (rev 3398)
@@ -0,0 +1,272 @@
+/*
+ *  armia32abicc.c
+ *
+ * Support for Call-outs and Call-backs from the Plugin on ARM.
+ *  Written by Eliot Miranda 07/15.
+ */
+
+#include <stdlib.h> /* for valloc */
+#include <sys/mman.h> /* for mprotect */
+
+#include <string.h> /* for memcpy et al */
+#include <setjmp.h>
+#include <stdio.h> /* for fprintf(stderr,...) */
+
+#include "vmCallback.h"
+#include "sqAssert.h"
+#include "sqMemoryAccess.h"
+#include "sqVirtualMachine.h"
+#include "ia32abi.h"
+
+#if !defined(min)
+# define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifdef SQUEAK_BUILTIN_PLUGIN
+extern
+#endif 
+struct VirtualMachine* interpreterProxy;
+
+#ifdef _MSC_VER
+# define alloca _alloca
+#endif
+#if __GNUC__
+# define setsp(sp) asm volatile ("ldr %%sp, %0" : : "m"(sp))
+# define getsp() ({ void *sp; asm volatile ("movl %%sp,%0" : "=r"(sp) : ); sp;})
+#endif
+#if __linux__
+# define STACK_ALIGN_BYTES 16
+#endif
+
+#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 objIsAlien(anOop) (interpreterProxy->includesBehaviorThatOf(interpreterProxy->fetchClassOf(anOop), interpreterProxy->classAlien()))
+#define objIsUnsafeAlien(anOop) (interpreterProxy->includesBehaviorThatOf(interpreterProxy->fetchClassOf(anOop), interpreterProxy->classUnsafeAlien()))
+
+#define sizeField(alien) (*(long *)pointerForOop((sqInt)(alien) + BaseHeaderSize))
+#define dataPtr(alien) pointerForOop((sqInt)(alien) + BaseHeaderSize + BytesPerOop)
+#if 0 /* obsolete after adding pointer Aliens with size field == 0 */
+# define isIndirectOrPointer(alien) (sizeField(alien) <= 0)
+# define startOfData(alien) (isIndirectOrPointer(alien)		\
+								? *(void **)dataPtr(alien)	\
+								:  (void  *)dataPtr(alien))
+#endif
+#define isIndirect(alien) (sizeField(alien) < 0)
+#define startOfParameterData(alien) (isIndirect(alien)	\
+									? *(void **)dataPtr(alien)	\
+									:  (void  *)dataPtr(alien))
+#define isIndirectSize(size) ((size) < 0)
+#define startOfDataWithSize(alien,size) (isIndirectSize(size)	\
+								? *(void **)dataPtr(alien)		\
+								:  (void  *)dataPtr(alien))
+
+#define isSmallInt(oop) ((oop)&1)
+#define intVal(oop) (((long)(oop))>>1)
+
+/*
+ * Call a foreign function that answers an integral result in %eax (and
+ * possibly %edx) according to IA32-ish ABI rules.
+ */
+sqInt
+callIA32IntegralReturn(SIGNATURE) {
+long long (*f)(long a,long b,long c,long d), r;
+#include "dabusinessARM.h"
+}
+
+/*
+ * Call a foreign function that answers a single-precision floating-point
+ * result in %f0 according to IA32-ish ABI rules.
+ */
+sqInt
+callIA32FloatReturn(SIGNATURE) {
+float (*f)(long a,long b,long c,long d), r;
+#include "dabusinessARM.h"
+}
+
+/*
+ * Call a foreign function that answers a double-precision floating-point
+ * result in %f0 according to IA32-ish ABI rules.
+ */
+sqInt
+callIA32DoubleReturn(SIGNATURE) {
+double (*f)(long a,long b,long c,long d), r;
+#include "dabusinessARM.h"
+}
+
+/* Queueing order for callback returns.  To ensure that callback returns occur
+ * in LIFO order we provide mostRecentCallbackContext which is tested by the
+ * return primitive primReturnFromContextThrough.  Note that in the threaded VM
+ * this does not have to be thread-specific or locked since it is within the
+ * bounds of the ownVM/disownVM pair.
+ */
+static VMCallbackContext *mostRecentCallbackContext = 0;
+
+VMCallbackContext *
+getMostRecentCallbackContext() { return mostRecentCallbackContext; }
+
+#define getRMCC(t) mostRecentCallbackContext
+#define setRMCC(t) (mostRecentCallbackContext = (void *)(t))
+
+/*
+ * Entry-point for call-back thunks.  Args are thunk address and stack pointer,
+ * where the stack pointer is pointing one word below the return address of the
+ * thunk's callee, 4 bytes below the thunk's first argument.  The stack is:
+ *		callback
+ *		arguments
+ *		retpc (thunk) <--\
+ *		address of retpc-/        <--\
+ *		address of address of ret pc-/
+ *		thunkp
+ * esp->retpc (thunkEntry)
+ *
+ * The stack pointer is pushed twice to keep the stack alignment to 16 bytes, a
+ * requirement on platforms using SSE2 such as Mac OS X, and harmless elsewhere.
+ *
+ * This function's roles are to use setjmp/longjmp to save the call point
+ * and return to it, to correct C stack pointer alignment if necessary (see
+ * STACK_ALIGN_HACK), and to return any of the various values from the callback.
+ *
+ * Looking forward to support for x86-64, which typically has 6 register
+ * arguments, the function would take 8 arguments, the 6 register args as
+ * longs, followed by the thunkp and stackp passed on the stack.  The register
+ * args would get copied into a struct on the stack. A pointer to the struct
+ * is then passed as an element of the VMCallbackContext.
+ */
+long
+thunkEntry(long r0, long r1, long r2, long r3, void *thunkp, long *stackp)
+{
+	VMCallbackContext vmcc;
+	VMCallbackContext *previousCallbackContext;
+	int flags, returnType;
+	long regArgs[4];
+
+#if STACK_ALIGN_HACK
+  { void *sp = getsp();
+    int offset = (unsigned long)sp & (STACK_ALIGN_BYTES - 1);
+	if (offset) {
+# if __GNUC__
+		asm("sub %0,%%sp" : : "m"(offset));
+# else
+#  error need to subtract offset from esp
+# endif
+		sp = getsp();
+		assert(!((unsigned long)sp & (STACK_ALIGN_BYTES - 1)));
+	}
+  }
+#endif /* STACK_ALIGN_HACK */
+
+	regArgs[0] = r0; regArgs[1] = r1; regArgs[2] = r2; regArgs[3] = r3;
+
+	if ((flags = interpreterProxy->ownVM(0)) < 0) {
+		fprintf(stderr,"Warning; callback failed to own the VM\n");
+		return -1;
+	}
+
+	if (!(returnType = setjmp(vmcc.trampoline))) {
+		previousCallbackContext = getRMCC();
+		setRMCC(&vmcc);
+		vmcc.thunkp = thunkp;
+		vmcc.stackp = stackp + 2; /* skip address of retpc & retpc (thunk) */
+		vmcc.intregargsp = regArgs;
+		vmcc.floatregargsp = 0;
+		interpreterProxy->sendInvokeCallbackContext(&vmcc);
+		fprintf(stderr,"Warning; callback failed to invoke\n");
+		setRMCC(previousCallbackContext);
+		interpreterProxy->disownVM(flags);
+		return -1;
+	}
+	setRMCC(previousCallbackContext);
+	interpreterProxy->disownVM(flags);
+
+	switch (returnType) {
+
+	case retword:	return vmcc.rvs.valword;
+
+	case retword64: {
+		long vhigh = vmcc.rvs.valleint64.high;
+#if __GNUC__
+				asm("ldr %%r1,%0" : : "m"(vhigh));
+#else
+# error need to load r1 with vmcc.rvs.valleint64.high on this compiler
+#endif
+				return vmcc.rvs.valleint64.low;
+	}
+
+	case retdouble: {
+		double valflt64 = vmcc.rvs.valflt64;
+#if 0
+# error need to load float return register with vmcc.rvs.valflt64 on this compiler
+#else
+		extern void error(char *s);
+		error("need to load float return register with vmcc.rvs.valflt64 on this compiler");
+#endif
+				return 0;
+	}
+
+	case retstruct:	memcpy( (void *)(stackp[1]),
+							vmcc.rvs.valstruct.addr,
+							vmcc.rvs.valstruct.size);
+					return stackp[1];
+	}
+	fprintf(stderr,"Warning; invalid callback return type\n");
+	return 0;
+}
+
+/*
+ * Thunk allocation support.  Since thunks must be exectuable and some OSs
+ * may not provide default execute permission on memory returned by malloc
+ * we must provide memory that is guaranteed to be executable.  The abstraction
+ * is to answer an Alien that references an executable piece of memory that
+ * is some (possiby unitary) multiple of the pagesize.
+ *
+ * We assume the Smalltalk image code will manage subdividing the executable
+ * page amongst thunks so there is no need to free these pages, since the image
+ * will recycle parts of the page for reclaimed thunks.
+ */
+#if defined(_MSC_VER) || defined(__MINGW32__)
+static unsigned long pagesize = 0;
+#endif
+
+void *
+allocateExecutablePage(long *size)
+{
+	void *mem;
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#if !defined(MEM_TOP_DOWN)
+# define MEM_TOP_DOWN 0x100000
+#endif
+	if (!pagesize) {
+		SYSTEM_INFO	sysinf;
+
+		GetSystemInfo(&sysinf);
+
+		pagesize = sysinf.dwPageSize;
+	}
+	/* N.B. VirtualAlloc MEM_COMMIT initializes the memory returned to zero. */
+	mem = VirtualAlloc(	0,
+						pagesize,
+						MEM_COMMIT | MEM_TOP_DOWN,
+						PAGE_EXECUTE_READWRITE);
+	if (mem)
+		*size = pagesize;
+#else
+	long pagesize = getpagesize();
+
+	if (!(mem = valloc(pagesize)))
+		return 0;
+
+	memset(mem, 0, pagesize);
+	if (mprotect(mem, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) {
+		free(mem);
+		return 0;
+	}
+	*size = pagesize;
+#endif
+	return mem;
+}

Added: trunk/platforms/Cross/plugins/IA32ABI/dabusinessARM.h
===================================================================
--- trunk/platforms/Cross/plugins/IA32ABI/dabusinessARM.h	                        (rev 0)
+++ trunk/platforms/Cross/plugins/IA32ABI/dabusinessARM.h	2015-07-07 19:03:10 UTC (rev 3398)
@@ -0,0 +1,159 @@
+/*
+ *  dabusinessARM.h
+ *
+ * Body of the various callIA32XXXReturn functions.
+ * Call a foreign function according to ARM-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, regs[4];
+	sqInt funcAlien, resultMaybeAlien;
+	char *argvec;
+#if STACK_ALIGN_BYTES
+	char *argstart;
+#endif
+
+#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);
+	}
+  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);
+	}
+
+#if STACK_ALIGN_BYTES
+	/* 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;
+#else
+	argvec = alloca(moduloPOT(sizeof(long),size));
+# if defined(__MINGW32__) && (__GNUC__ >= 3)
+	/*
+	 * cygwin & MinGW's gcc 3.4.x's alloca is a library routine that answers
+	 * %esp + 4, so the outgoing stack is offset by one word if uncorrected.
+	 * Grab the actual stack pointer to correct.
+	 */
+	argvec = getsp();
+# endif
+#endif
+
+#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;
+
+			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;
+			}
+			*(long *)argvec = v;
+			argvec += sizeof(long);
+		}
+	}
+  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;
+			}
+			*(long *)argvec = v;
+			argvec += sizeof(long);
+		}
+	}
+
+	funcAlien = interpreterProxy->stackValue(funcOffset);
+	f = *(void **)startOfParameterData(funcAlien);
+#if STACK_ALIGN_BYTES
+	/* cut stack back to start of aligned args */
+	setsp(argstart);
+#endif
+	r = f(regs[0],regs[1],regs[2],regs[3]);
+	/* 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)));
+	}
+
+	return PrimNoErr;

Modified: trunk/platforms/Cross/plugins/IA32ABI/ia32abi.h
===================================================================
--- trunk/platforms/Cross/plugins/IA32ABI/ia32abi.h	2015-07-06 18:56:39 UTC (rev 3397)
+++ trunk/platforms/Cross/plugins/IA32ABI/ia32abi.h	2015-07-07 19:03:10 UTC (rev 3398)
@@ -40,6 +40,8 @@
 # define INT_REG_ARGS long,long,long,long,long,long,
 #elif defined(__powerpc__) || defined(PPC) || defined(_POWER) || defined(_IBMR2) || defined(__ppc__)
 # define INT_REG_ARGS long,long,long,long,long,long,long,long,
+#elif defined(__ARM_ARCH__) || defined(__arm__) || defined(__arm32__) || defined(ARM32)
+# define INT_REG_ARGS long,long,long,long,
 #endif
 extern long  thunkEntry (INT_REG_ARGS void *,long *);
 extern void *allocateExecutablePage(long *pagesize);

Modified: trunk/platforms/Cross/plugins/IA32ABI/xabicc.c
===================================================================
--- trunk/platforms/Cross/plugins/IA32ABI/xabicc.c	2015-07-06 18:56:39 UTC (rev 3397)
+++ trunk/platforms/Cross/plugins/IA32ABI/xabicc.c	2015-07-07 19:03:10 UTC (rev 3398)
@@ -2,7 +2,7 @@
  *  xabicc.c - platform-agnostic root for ALien call-outs and callbacks.
  *
  * Support for Call-outs and Call-backs from the IA32ABI Plugin.
- * The plgin is misnamed.  It should be the AlienPlugin, but its history
+ * The plugin is misnamed.  It should be the AlienPlugin, but its history
  * dictates otherwise.
  */
 #if i386|i486|i586|i686
@@ -11,4 +11,6 @@
 # include "ppcia32abicc.c"
 #elif x86_64|x64|__x86_64|__x86_64__
 # include "x64ia32abicc.c"
+#elif defined(__ARM_ARCH__) || defined(__arm__) || defined(__arm32__) || defined(ARM32)
+# include "arm32ia32abicc.c"
 #endif


Property changes on: trunk/platforms/Cross/plugins/sqPluginsSCCSVersion.h
___________________________________________________________________
Modified: checkindate
   - Sun May 17 13:13:27 PDT 2015
   + Tue Jul  7 12:02:30 PDT 2015



More information about the Vm-dev mailing list