[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