text: /* Automatically generated by
  	VMPluginCodeGenerator VMMaker.oscog-eem.2520 uuid: 6031f286-1f25-45df-ba77-ee65f80df015
     from
  	ThreadedARM64FFIPlugin VMMaker.oscog-eem.2520 uuid: 6031f286-1f25-45df-ba77-ee65f80df015
   */
  static char __buildInfo[] = "ThreadedARM64FFIPlugin VMMaker.oscog-eem.2520 uuid: 6031f286-1f25-45df-ba77-ee65f80df015 " __DATE__ ;
  
  
  
  #include "config.h"
  #include <math.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <time.h>
  
  /* Default EXPORT macro that does nothing (see comment in sq.h): */
  #define EXPORT(returnType) returnType
  
  /* Do not include the entire sq.h file but just those parts needed. */
  #include "sqConfig.h"			/* Configuration options */
  #include "sqVirtualMachine.h"	/*  The virtual machine proxy definition */
  #include "sqPlatformSpecific.h"	/* Platform specific definitions */
  
  #include "pharovm/debug.h"
  
  #define true 1
  #define false 0
  #define null 0  /* using 'null' because nil is predefined in Think C */
  #ifdef SQUEAK_BUILTIN_PLUGIN
  # undef EXPORT
  # define EXPORT(returnType) static returnType
  #endif
  
  #include "sqMemoryAccess.h"
  
  
  /* ThreadedFFIPlugin class>>preambleCCode */
  
  #include "sqAssert.h" /* for assert */
  #define ThreadedFFIPlugin 1 /* to filter-out unwanted declarations from sqFFI.h */
  #include "sqFFI.h" /* for logging and surface functions */
  #include "sqCogStackAlignment.h" /* for STACK_ALIGN_BYTES and getsp() */
  
  #ifdef _MSC_VER
  # define alloca _alloca
  #endif
  #if defined(__GNUC__) && (defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__))
  # define setsp(sp) asm volatile ("movl %0,%%esp" : : "m"(sp))
  # elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__) ||  defined(__amd64) || defined(__x86_64))
  # define setsp(sp) asm volatile ("movq %0,%%rsp" : : "m"(sp))
  # elif defined(__arm64__) || defined(__aarch64__) || defined(ARM64)
          /* https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Extended-Asm
           * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/index.html
           */
  #  if __GNUC__
  #   define getfp() ({ usqIntptr_t fp;                                                           \
                                            asm volatile ("mov x0, x29" : "=r"(x29) : );  \
                                            fp; })
  #   define getsp() ({ usqIntptr_t sp;                                                           \
                                            asm volatile ("mov x0, sp" : "=r"(sp) : );    \
                                            sp; })
  # define setsp(sp) asm volatile ("ldr x16, %0 \n\t" "mov sp, x16"  : : "m"(sp) )
  #  endif
  # elif defined(__GNUC__) && (defined(__arm__))
  # define setsp(sp) asm volatile ("ldr %%sp, %0" : : "m"(sp))
  #endif
  #if !defined(getsp)
  # define getsp() 0
  #endif 
  #if !defined(setsp)
  # define setsp(ignored) 0
  #endif 
  
  #if !defined(STACK_ALIGN_BYTES)
  #  define STACK_ALIGN_BYTES 0
  #endif /* !defined(STACK_ALIGN_BYTES) */
  
  /* For ABI that require stack alignment greater than natural word size */
  #define MUST_ALIGN_STACK (STACK_ALIGN_BYTES > sizeof(void*))
  
  #if defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__)
  /* Both Mac OS X x86 and Win32 x86 return structs of a power of two in size
   * less than or equal to eight bytes in length in registers. Linux never does so.
   */
  # if __linux__
  #	define WIN32_X86_STRUCT_RETURN 0
  # else
  #	define WIN32_X86_STRUCT_RETURN 1
  # endif
  # if _WIN32
  #	define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 1
  # endif
  # elif defined(__amd64__) || defined(__x86_64__) ||  defined(__amd64) || defined(__x86_64)
  # if _WIN32 | _WIN64
  #	define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 1
  # endif
  #endif /* defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__) */
  
  #if !defined(ALLOCA_LIES_SO_SETSP_BEFORE_CALL)
  # if defined(__MINGW32__) && !defined(__clang__) && (__GNUC__ >= 3) && (defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__))
      /*
       * cygwin -mno-cygwin (MinGW) gcc 3.4.x's alloca is a library routine that answers
       * %esp + xx, so the outgoing stack is offset by one or more word if uncorrected.
       * Grab the actual stack pointer to correct.
       */
  #	define ALLOCA_LIES_SO_SETSP_BEFORE_CALL 1
  # else
  #	define ALLOCA_LIES_SO_SETSP_BEFORE_CALL 0
  # endif
  #endif /* !defined(ALLOCA_LIES_SO_SETSP_BEFORE_CALL) */
  
  #if !defined(PLATFORM_API_USES_CALLEE_POPS_CONVENTION)
  # define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 0
  #endif
  
  /* This alignment stuff is a hack for integerAt:put:size:signed:/primitiveFFIIntegerAt[Put].
   * The assumption right now is that all processors support unaligned access.  That only
   * holds true for x86, x86-64 & ARMv6 & later.  But this keeps us going until we can address
   * it properly.
   */
  #define unalignedShortAt(a) shortAt(a)
  #define unalignedShortAtput(a,v) shortAtput(a,v)
  #define unalignedLong32At(a) long32At(a)
  #define unalignedLong32Atput(a,v) long32Atput(a,v)
  #define unalignedLong64At(a) long64At(a)
  #define unalignedLong64Atput(a,v) long64Atput(a,v)
  
  /* The dispatchOn:in:with:with: generates an unwanted call on error.  Just squash it. */
  #define error(foo) 0
  #ifndef SQUEAK_BUILTIN_PLUGIN
  /* but print assert failures. */
  void
  warning(char *s) { /* Print an error message but don't exit. */
  	logWarn("\n%s\n", s);
  }
  #endif
  
  /* sanitize */
  #ifdef SQUEAK_BUILTIN_PLUGIN
  # define EXTERN 
  #else
  # define EXTERN extern
  #endif
  
  /* end ThreadedFFIPlugin class>>preambleCCode */
  
  
  /*** Constants ***/
  #define DefaultMaxStackSize 16384
  #define DisownVMForFFICall 16
  #define DisownVMForThreading 32
  #define ExternalFunctionArgTypesIndex 2
  #define ExternalFunctionFlagsIndex 1
  #define ExternalFunctionStackSizeIndex 3
  #define FFIAtomicTypeMask 0xF000000
  #define FFIAtomicTypeShift 24
  #define FFICallFlagThreaded 0x100
  #define FFICallTypeApi 1
  #define FFICallTypeCDecl 0
  #define FFICallTypesMask 0xFF
  #define FFIErrorAddressNotFound 13
  #define FFIErrorAttemptToPassVoid 14
  #define FFIErrorBadAddress 11
  #define FFIErrorBadArg 3
  #define FFIErrorBadArgs 2
  #define FFIErrorBadAtomicType 5
  #define FFIErrorBadExternalFunction 17
  #define FFIErrorBadExternalLibrary 16
  #define FFIErrorBadReturn 10
  #define FFIErrorCallFrameTooBig 19
  #define FFIErrorCallType 9
  #define FFIErrorCoercionFailed 6
  #define FFIErrorIntAsPointer 4
  #define FFIErrorInvalidPointer 18
  #define FFIErrorModuleNotFound 15
  #define FFIErrorNoModule 12
  #define FFIErrorNotFunction 1
  #define FFIErrorStructSize 8
  #define FFIErrorWrongType 7
  #define FFIFlagAtomic 0x40000
  #define FFIFlagPointer 0x20000
  #define FFIFlagStructure 0x10000
  #define FFINoCalloutAvailable -1
  #define FFIStructSizeMask 0xFFFF
  #define FFITypeBool 1
  #define FFITypeDoubleFloat 13
  #define FFITypeSignedByte 3
  #define FFITypeSignedChar 11
  #define FFITypeSignedInt 7
  #define FFITypeSignedLongLong 9
  #define FFITypeSignedShort 5
  #define FFITypeSingleFloat 12
  #define FFITypeUnsignedByte 2
  #define FFITypeUnsignedInt 6
  #define FFITypeVoid 0
  #define MaxNumArgs 15
  #define NumFloatRegArgs 8
  #define NumIntRegArgs 8
  #define PrimErrBadArgument 3
  #define PrimErrBadMethod 12
  #define PrimErrBadNumArgs 5
  #define PrimErrBadReceiver 2
  #define PrimErrFFIException 22
  #define PrimErrNoCMemory 10
  #define PrimErrNotFound 11
  #define PrimErrObjectMayMove 14
  #if !defined(SPURVM) /* Allow this to be overridden on the compiler command line */
  # define SPURVM 1
  #endif
  
  typedef struct {
  	char *argVector;
  	char *currentArg;
  	char *limit;
  	sqInt	structReturnSize;
  	sqInt	callFlags;
  	void *ffiArgSpec;
  	sqInt	ffiArgSpecSize;
  	sqInt	ffiArgHeader;
  	sqInt	ffiRetHeader;
  	sqInt	stringArgIndex;
  	char *stringArgs [MaxNumArgs];
  	sqInt	integerRegisterIndex;
  	sqInt	floatRegisterIndex;
  	sqInt		integerRegisters [NumIntRegArgs];
  	double		floatRegisters [NumFloatRegArgs];
   } CalloutState;
  
  #define ThreadedFFICalloutStateForARM64 CalloutState
  #define ThreadedFFICalloutState CalloutState
  
  
  
  /*** Function Prototypes ***/
  static sqInt atomicTypeOf(sqInt typeSpec);
  static void cleanupCalloutState(CalloutState *calloutState);
  static sqInt externalFunctionHasStackSizeSlot(void);
  static void * ffiAddressOfstartingAtsize(sqInt rcvr, sqInt byteOffset, sqInt byteSize);
  static sqInt ffiArgByValuein(sqInt oop, CalloutState *calloutState);
  static sqInt ffiArgumentSpecClassin(sqInt oop, sqInt argSpec, sqInt argClass, CalloutState *calloutState);
  static sqInt ffiAtomicArgByReferenceClassin(sqInt oop, sqInt oopClass, CalloutState *calloutState);
  static sqInt ffiAtomicStructByReferenceClassin(sqInt oop, sqInt oopClass, CalloutState *calloutState);
  static sqInt ffiCalloutToSpecOnStackin(void *procAddr, sqInt specOnStack, CalloutState *calloutState);
  static sqInt ffiCallArgArrayOrNilNumArgs(sqInt externalFunction, sqInt argArrayOrNil, sqInt nArgs);
  static sqInt ffiCheckReturnWithin(sqInt retSpec, sqInt retClass, CalloutState *calloutState);
  static sqInt ffiContentsOfHandleerrCode(sqInt oop, sqInt errCode);
  static sqInt ffiCreateIntegralResultOopofAtomicTypein(usqLong retVal, sqInt atomicType, CalloutState *calloutState);
  static sqInt ffiFail(sqInt reason);
  static double ffiFloatValueOf(sqInt oop);
  static sqInt ffiIntegerValueOf(sqInt oop);
  static sqInt ffiLoadCalloutAddressFrom(sqInt oop);
  static sqInt ffiLoadCalloutAddress(sqInt lit);
  static sqInt ffiLoadCalloutModule(sqInt module);
  static void ffiLogCallout(sqInt lit);
  EXPORT(sqInt) ffiLogCallsTo(char *fileName);
  static sqInt ffiPushPointerContentsOfin(sqInt oop, CalloutState *calloutState);
  static sqInt ffiPushPointerin(void *pointer, CalloutState *calloutState);
  static sqInt ffiPushSignedBytein(sqInt value, CalloutState *calloutState);
  static sqInt ffiPushSignedCharin(sqInt value, CalloutState *calloutState);
  static sqInt ffiPushSignedIntin(sqInt value, CalloutState *calloutState);
  static sqInt ffiPushSignedLongLongOopin(sqInt oop, CalloutState *calloutState);
  static sqInt ffiPushSignedLongLongin(sqLong value, CalloutState *calloutState);
  static sqInt ffiPushSignedShortin(sqInt value, CalloutState *calloutState);
  static sqInt ffiPushStringOfLengthin(char *pointer, sqInt length, CalloutState *calloutState);
  static sqInt ffiPushStructureContentsOfin(sqInt oop, CalloutState *calloutState);
  static sqInt ffiPushStructureofSizetypeSpecofLengthin(void *pointer, sqInt structSize, sqInt *argSpec, sqInt argSpecSize, CalloutState *calloutState);
  static sqInt ffiPushUnsignedBytein(sqInt value, CalloutState *calloutState);
  static sqInt ffiPushUnsignedCharin(sqInt value, CalloutState *calloutState);
  static sqInt ffiPushUnsignedIntin(sqInt value, CalloutState *calloutState);
  static sqInt ffiPushUnsignedLongLongOopin(sqInt oop, CalloutState *calloutState);
  static sqInt ffiPushUnsignedLongLongin(usqLong value, CalloutState *calloutState);
  static sqInt ffiPushUnsignedShortin(sqInt value, CalloutState *calloutState);
  static sqInt ffiPushVoidin(sqInt ignored, CalloutState *calloutState);
  static sqInt ffiReturnCStringFrom(sqInt cPointer);
  static sqInt ffiReturnPointerofTypein(usqLong retVal, sqInt retType, CalloutState *calloutState);
  static sqInt ffiReturnStructofTypein(usqLong longLongRet, sqInt ffiRetType, CalloutState *calloutState);
  static sqInt ffiReturnType(sqInt specOnStack);
  static sqInt ffiSupportsCallingConvention(sqInt aCallingConvention);
  static sqInt ffiValidateExternalDataAtomicType(sqInt oop, sqInt atomicType);
  EXPORT(const char *) getModuleName(void);
  static sqInt getX1register(void);
  EXPORT(sqInt) initialiseModule(void);
  static sqInt isAlien(sqInt anOop);
  static sqInt isAtomicType(sqInt typeSpec);
  static sqInt isDirectAlien(sqInt oop);
  static sqInt msg(char *s);
  static sqInt mustReturnStructOnStack(sqInt returnStructSize);
  static sqInt nonRegisterStructReturnIsViaImplicitFirstArgument(void);
  EXPORT(void) primitiveCallout(void);
  EXPORT(void) primitiveCalloutWithArgs(void);
  EXPORT(sqInt) primitiveCreateManualSurface(void);
  EXPORT(sqInt) primitiveDestroyManualSurface(void);
  EXPORT(sqInt) primitiveFFIAllocate(void);
  EXPORT(sqInt) primitiveFFIDoubleAt(void);
  EXPORT(sqInt) primitiveFFIDoubleAtPut(void);
  EXPORT(sqInt) primitiveFFIFloatAt(void);
  EXPORT(sqInt) primitiveFFIFloatAtPut(void);
  EXPORT(sqInt) primitiveFFIFree(void);
  EXPORT(sqInt) primitiveFFIGetLastError(void);
  EXPORT(sqInt) primitiveFFIIntegerAt(void);
  EXPORT(sqInt) primitiveFFIIntegerAtPut(void);
  EXPORT(sqInt) primitiveForceLoad(void);
  EXPORT(sqInt) primitiveLoadSymbolFromModule(void);
  EXPORT(sqInt) primitiveLogCallsTo(void);
  EXPORT(sqInt) primitiveSetManualSurfacePointer(void);
  static sqInt returnStructInRegisters(sqInt returnStructSize);
  EXPORT(sqInt) setInterpreter(struct VirtualMachine *anInterpreter);
  static sqInt setReturnRegisterandCallwithArgsArray(sqLong structAddr, sqLong procAddr, sqLong arrayAddr);
  static sqInt sizeField(sqInt oop);
  static sqInt startOfData(sqInt oop);
  
  
  /*** Variables ***/
  static sqInt externalFunctionInstSize;
  static sqInt ffiLastError;
  static sqInt ffiLogEnabled;
  
  #if defined(SQUEAK_BUILTIN_PLUGIN)
  
  # define isIntegerObject(oop) ((oop) & 1)
  
  # if SPURVM
  extern sqInt classIndexOf(sqInt);
  #	define LargeNegativeIntegerClassIndex 32
  #	define LargePositiveIntegerClassIndex 33
  #	if BytesPerOop == 4
  #	  define isImmediate(oop) ((oop) & 3)
  #	else
  #	  define isImmediate(oop) ((oop) & 7)
  #	endif
  #	define isKindOfInteger(oop) (isImmediate(oop) ? isIntegerObject(oop) : (unsigned)(classIndexOf(oop) - LargeNegativeIntegerClassIndex) <= 1)
  #	define isLargeIntegerObject(oop) (!isImmediate(oop) && (unsigned)(classIndexOf(oop) - LargeNegativeIntegerClassIndex) <= 1)
  #	define isLargeNegativeIntegerObject(oop) (!isImmediate(oop) && classIndexOf(oop) == LargeNegativeIntegerClassIndex)
  #	define isLargePositiveIntegerObject(oop) (!isImmediate(oop) && classIndexOf(oop) == LargePositiveIntegerClassIndex)
  # endif /* SPURVM */
  #endif /* defined(SQUEAK_BUILTIN_PLUGIN) */
  
  #if !defined(isKindOfInteger)
  # define isLargeNegativeIntegerObject(oop) (fetchClassOf(oop) == classLargeNegativeInteger())
  # define isLargePositiveIntegerObject(oop) (fetchClassOf(oop) == classLargePositiveInteger())
  # define isLargeIntegerObject(oop) (isLargeNegativeIntegerObject(oop) || isLargePositiveIntegerObject(oop))
  # define isKindOfInteger(oop) (isIntegerObject(oop) || isLargeNegativeIntegerObject(oop) || isLargePositiveIntegerObject(oop))
  #endif
  
  #if !defined(SQUEAK_BUILTIN_PLUGIN)
  static sqInt (*booleanValueOf)(sqInt obj);
  static sqInt (*byteSizeOf)(sqInt oop);
  static sqInt (*characterObjectOf)(sqInt characterCode);
  static sqInt (*characterValueOf)(sqInt aCharacter);
  static sqInt (*classAlien)(void);
  static sqInt (*classByteArray)(void);
  static sqInt (*classExternalAddress)(void);
  static sqInt (*classExternalData)(void);
  static sqInt (*classExternalFunction)(void);
  static sqInt (*classExternalLibrary)(void);
  static sqInt (*classExternalStructure)(void);
  static sqInt (*classLargePositiveInteger)(void);
  static sqInt (*classString)(void);
  static sqInt (*disownVM)(sqInt flags);
  static sqInt (*failed)(void);
  static sqInt (*falseObject)(void);
  static sqInt (*fetchClassOf)(sqInt oop);
  static sqInt (*fetchIntegerofObject)(sqInt fieldIndex, sqInt objectPointer);
  static sqInt (*fetchLong32ofObject)(sqInt fieldIndex, sqInt oop);
  static sqInt (*fetchPointerofObject)(sqInt index, sqInt oop);
  static void * (*firstIndexableField)(sqInt oop);
  static sqInt (*floatObjectOf)(double aFloat);
  static double (*floatValueOf)(sqInt oop);
  static sqInt (*includesBehaviorThatOf)(sqInt aClass, sqInt aSuperclass);
  static sqInt (*instanceSizeOf)(sqInt classObj);
  static sqInt (*instantiateClassindexableSize)(sqInt classPointer, sqInt size);
  static sqInt (*integerObjectOf)(sqInt value);
  static sqInt (*integerValueOf)(sqInt oop);
  static void * (*ioLoadModuleOfLength)(sqInt moduleNameIndex, sqInt moduleLength);
  static void * (*ioLoadSymbolOfLengthFromModule)(sqInt functionNameIndex, sqInt functionLength, sqInt moduleHandle);
  static sqInt (*isKindOfClass)(sqInt oop, sqInt aClass);
  static sqInt (*isArray)(sqInt oop);
  static sqInt (*isBytes)(sqInt oop);
  static sqInt (*isCharacterObject)(sqInt oop);
  static sqInt (*isFloatObject)(sqInt oop);
  static sqInt (*isImmediate)(sqInt anObject);
  static sqInt (*isInMemory)(sqInt address);
  static sqInt (*isIntegerObject)(sqInt objectPointer);
  static sqInt (*isPointers)(sqInt oop);
  static sqInt (*isWords)(sqInt oop);
  static sqInt (*isYoung)(sqInt anOop);
  static sqInt (*literalofMethod)(sqInt offset, sqInt methodPointer);
  static sqInt (*literalCountOf)(sqInt methodPointer);
  static sqInt (*methodArgumentCount)(void);
  static sqInt (*methodReturnInteger)(sqInt integer);
  static sqInt (*methodReturnValue)(sqInt oop);
  static sqInt (*nilObject)(void);
  static sqInt (*ownVM)(sqInt flags);
  static sqInt (*pop)(sqInt nItems);
  static sqInt (*popthenPush)(sqInt nItems, sqInt oop);
  static sqInt (*popRemappableOop)(void);
  static sqInt (*positive32BitIntegerFor)(unsigned int integerValue);
  static usqInt (*positive32BitValueOf)(sqInt oop);
  static sqInt (*positive64BitIntegerFor)(usqLong integerValue);
  static usqLong (*positive64BitValueOf)(sqInt oop);
  static usqIntptr_t (*positiveMachineIntegerValueOf)(sqInt oop);
  static sqInt (*primitiveErrorTable)(void);
  static sqInt (*primitiveFail)(void);
  static sqInt (*primitiveFailFor)(sqInt reasonCode);
  static sqInt (*primitiveMethod)(void);
  static sqInt (*pushFloat)(double f);
  static sqInt (*pushRemappableOop)(sqInt oop);
  static sqInt (*signed32BitIntegerFor)(sqInt integerValue);
  static sqInt (*signed64BitIntegerFor)(sqLong integerValue);
  static sqLong (*signed64BitValueOf)(sqInt oop);
  static sqIntptr_t (*signedMachineIntegerValueOf)(sqInt oop);
  static sqInt (*slotSizeOf)(sqInt oop);
  static sqInt (*stackIntegerValue)(sqInt offset);
  static sqInt (*stackObjectValue)(sqInt offset);
  static sqInt (*stackValue)(sqInt offset);
  static sqInt (*storeIntegerofObjectwithValue)(sqInt index, sqInt oop, sqInt integer);
  static sqInt (*storePointerofObjectwithValue)(sqInt index, sqInt oop, sqInt valuePointer);
  static void (*tenuringIncrementalGC)(void);
  static sqInt (*trueObject)(void);
  #else /* !defined(SQUEAK_BUILTIN_PLUGIN) */
  extern sqInt booleanValueOf(sqInt obj);
  extern sqInt byteSizeOf(sqInt oop);
  #if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
  extern sqInt characterObjectOf(sqInt characterCode);
  #else
  # define characterObjectOf(characterCode) 0
  #endif
  #if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
  extern sqInt characterValueOf(sqInt aCharacter);
  #else
  # define characterValueOf(aCharacter) 0
  #endif
  extern sqInt classAlien(void);
  extern sqInt classByteArray(void);
  extern sqInt classExternalAddress(void);
  extern sqInt classExternalData(void);
  extern sqInt classExternalFunction(void);
  extern sqInt classExternalLibrary(void);
  extern sqInt classExternalStructure(void);
  extern sqInt classLargePositiveInteger(void);
  extern sqInt classString(void);
  extern sqInt disownVM(sqInt flags);
  extern sqInt failed(void);
  extern sqInt falseObject(void);
  extern sqInt fetchClassOf(sqInt oop);
  extern sqInt fetchIntegerofObject(sqInt fieldIndex, sqInt objectPointer);
  extern sqInt fetchLong32ofObject(sqInt fieldIndex, sqInt oop);
  extern sqInt fetchPointerofObject(sqInt index, sqInt oop);
  extern void * firstIndexableField(sqInt oop);
  extern sqInt floatObjectOf(double aFloat);
  extern double floatValueOf(sqInt oop);
  extern sqInt includesBehaviorThatOf(sqInt aClass, sqInt aSuperclass);
  extern sqInt instanceSizeOf(sqInt classObj);
  extern sqInt instantiateClassindexableSize(sqInt classPointer, sqInt size);
  extern sqInt integerObjectOf(sqInt value);
  extern sqInt integerValueOf(sqInt oop);
  extern void * ioLoadModuleOfLength(sqInt moduleNameIndex, sqInt moduleLength);
  extern void * ioLoadSymbolOfLengthFromModule(sqInt functionNameIndex, sqInt functionLength, sqInt moduleHandle);
  extern sqInt isKindOfClass(sqInt oop, sqInt aClass);
  extern sqInt isArray(sqInt oop);
  extern sqInt isBytes(sqInt oop);
  #if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
  extern sqInt isCharacterObject(sqInt oop);
  #else
  # define isCharacterObject(oop) 0
  #endif
  extern sqInt isFloatObject(sqInt oop);
  #if !defined(isImmediate)
  #if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
  extern sqInt isImmediate(sqInt anObject);
  #else
  # define isImmediate(anObject) 0
  #endif
  #endif /* !defined(isImmediate) */
  extern sqInt isInMemory(sqInt address);
  #if !defined(isIntegerObject)
  extern sqInt isIntegerObject(sqInt objectPointer);
  #endif
  extern sqInt isPointers(sqInt oop);
  extern sqInt isWords(sqInt oop);
  extern sqInt isYoung(sqInt anOop);
  extern sqInt literalofMethod(sqInt offset, sqInt methodPointer);
  extern sqInt literalCountOf(sqInt methodPointer);
  extern sqInt methodArgumentCount(void);
  extern sqInt methodReturnInteger(sqInt integer);
  extern sqInt methodReturnValue(sqInt oop);
  extern sqInt nilObject(void);
  extern sqInt ownVM(sqInt flags);
  extern sqInt pop(sqInt nItems);
  extern sqInt popthenPush(sqInt nItems, sqInt oop);
  extern sqInt popRemappableOop(void);
  extern sqInt positive32BitIntegerFor(unsigned int integerValue);
  extern usqInt positive32BitValueOf(sqInt oop);
  extern sqInt positive64BitIntegerFor(usqLong integerValue);
  extern usqLong positive64BitValueOf(sqInt oop);
  extern usqIntptr_t positiveMachineIntegerValueOf(sqInt oop);
  extern sqInt primitiveErrorTable(void);
  extern sqInt primitiveFail(void);
  extern sqInt primitiveFailFor(sqInt reasonCode);
  extern sqInt primitiveMethod(void);
  extern sqInt pushFloat(double f);
  extern sqInt pushRemappableOop(sqInt oop);
  extern sqInt signed32BitIntegerFor(sqInt integerValue);
  extern sqInt signed64BitIntegerFor(sqLong integerValue);
  extern sqLong signed64BitValueOf(sqInt oop);
  extern sqIntptr_t signedMachineIntegerValueOf(sqInt oop);
  extern sqInt slotSizeOf(sqInt oop);
  extern sqInt stackIntegerValue(sqInt offset);
  extern sqInt stackObjectValue(sqInt offset);
  extern sqInt stackValue(sqInt offset);
  extern sqInt storeIntegerofObjectwithValue(sqInt index, sqInt oop, sqInt integer);
  extern sqInt storePointerofObjectwithValue(sqInt index, sqInt oop, sqInt valuePointer);
  extern void tenuringIncrementalGC(void);
  extern sqInt trueObject(void);
  extern
  #endif
  struct VirtualMachine* interpreterProxy;
  static const char *moduleName =
  #ifdef SQUEAK_BUILTIN_PLUGIN
  	"ARM64FFIPlugin VMMaker.oscog-eem.2520 (i)"
  #else
  	"ARM64FFIPlugin VMMaker.oscog-eem.2520 (e)"
  #endif
  ;
  
  
  /*** Macros ***/
  #define allocaLiesSoSetSpBeforeCall() ALLOCA_LIES_SO_SETSP_BEFORE_CALL
  #define cStackAlignment() STACK_ALIGN_BYTES
  #define dispatchFunctionPointer(aFunctionPointer) (aFunctionPointer)()
  #define dispatchFunctionPointerwithwithwithwith(aFunctionPointer, int1, int2, int3, int4) (aFunctionPointer)(int1, int2, int3, int4)
  #define dispatchFunctionPointerwithwithwithwithwithwith(aFunctionPointer, int1, int2, int3, int4, int5, int6) (aFunctionPointer)(int1, int2, int3, int4, int5, int6)
  #define dispatchFunctionPointerwithwithwithwithwithwithwithwith(aFunctionPointer, int1, int2, int3, int4, int5, int6, int7, int8) (aFunctionPointer)(int1, int2, int3, int4, int5, int6, int7, int8)
  #define ffiAlloc(bytes) (usqInt)malloc(bytes)
  #define ffiFree(pointer) free((void *)(pointer))
  #define isCalleePopsConvention(callType) (PLATFORM_API_USES_CALLEE_POPS_CONVENTION && (callType) == FFICallTypeApi)
  #define mustAlignStack() MUST_ALIGN_STACK
  
  
  	/* ThreadedFFIPlugin>>#atomicTypeOf: */
  static sqInt
  atomicTypeOf(sqInt typeSpec)
  {
  	return ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  }
  
  
  /*	Free any temporary arg strings. */
  
  	/* ThreadedFFIPlugin>>#cleanupCalloutState: */
  static void
  cleanupCalloutState(CalloutState *calloutState)
  {
  	while (((calloutState->stringArgIndex)) > 0) {
  		free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
  	}
  }
  
  	/* ThreadedFFIPlugin>>#externalFunctionHasStackSizeSlot */
  static sqInt
  externalFunctionHasStackSizeSlot(void)
  {
  	return externalFunctionInstSize > ExternalFunctionStackSizeIndex;
  }
  
  
  /*	Answer a long of the address of the byteSize slot (byte, short, int,
  	whatever) at byteOffset in rcvr.
  	Nominally intended for use with ExternalAddress objects, this code will
  	work (for obscure historical
  	reasons) with plain Byte or Word Arrays as well. Answer 0 on error. */
  
  	/* ThreadedFFIPlugin>>#ffiAddressOf:startingAt:size: */
  static void *
  ffiAddressOfstartingAtsize(sqInt rcvr, sqInt byteOffset, sqInt byteSize)
  {
      sqInt addr;
      sqInt rcvrClass;
      sqInt rcvrSize;
  
  	if (!(isBytes(rcvr))) {
  		return 0;
  	}
  	if (!(byteOffset > 0)) {
  		return 0;
  	}
  	rcvrClass = fetchClassOf(rcvr);
  	rcvrSize = byteSizeOf(rcvr);
  	if (rcvrClass == (classExternalAddress())) {
  		if (!(rcvrSize == BytesPerWord)) {
  			return 0;
  		}
  
  		/* Hack!! */
  		/* don't you dare to read from object memory (unless is pinned)! */
  		addr = fetchPointerofObject(0, rcvr);
  		if (addr == 0) {
  
  			/* or: [(interpreterProxy isInMemory: addr) or: [(interpreterProxy isPinned: rcvr) not]] */
  			return 0;
  		}
  	}
  	else {
  		if (!(((byteOffset + byteSize) - 1) <= rcvrSize)) {
  			return 0;
  		}
  		addr = ((sqIntptr_t) (firstIndexableField(rcvr)));
  	}
  	addr = (addr + byteOffset) - 1;
  	return ((void *)addr);
  }
  
  
  /*	Support for generic callout. Prepare an argument by value for a callout. */
  
  	/* ThreadedFFIPlugin>>#ffiArgByValue:in: */
  static sqInt
  ffiArgByValuein(sqInt oop, CalloutState *calloutState)
  {
      sqInt atomicType;
      double floatValue;
      sqInt intValue;
      sqInt typeSpec;
  
  	/* begin atomicTypeOf: */
  	typeSpec = (calloutState->ffiArgHeader);
  	atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  	if ((atomicType < 0)
  	 || (atomicType > FFITypeDoubleFloat)) {
  		return FFIErrorBadAtomicType;
  	}
  	if (atomicType < FFITypeSingleFloat) {
  
  		/* integer types */
  		if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)) {
  
  			/* ffi support code must coerce longlong */
  			intValue = oop;
  		}
  		else {
  			/* begin ffiIntegerValueOf: */
  			if (oop & (BytesPerWord - 1)) {
  				if (isIntegerObject(oop)) {
  					intValue = integerValueOf(oop);
  					goto l2;
  				}
  				
  #        if SPURVM
  				if (isCharacterObject(oop)) {
  
  					/* Immediate in Spur */
  					intValue = characterValueOf(oop);
  					goto l2;
  				}
  				if (isFloatObject(oop)) {
  
  					/* Immediate in 64-bit Spur */
  					intValue = floatValueOf(oop);
  					goto l2;
  				}
  #        endif /* SPURVM */
  			}
  			else {
  				
  #        if SPURVM
  
  				/* No non-immediate characters in Spur */
  #        else /* SPURVM */
  				if (isCharacterObject(oop)) {
  					intValue = characterValueOf(oop);
  					goto l2;
  				}
  #        endif /* SPURVM */
  				if (isFloatObject(oop)) {
  					intValue = floatValueOf(oop);
  					goto l2;
  				}
  				if (oop == (nilObject())) {
  					intValue = 0;
  					goto l2;
  				}
  				if (oop == (falseObject())) {
  					intValue = 0;
  					goto l2;
  				}
  				if (oop == (trueObject())) {
  					intValue = 1;
  					goto l2;
  				}
  				if (isLargePositiveIntegerObject(oop)) {
  					
  #          if BytesPerWord == 8
  
  					/* Use cppIf: to get the return type of the function right.  Should be sqInt on 32-bits. */
  					intValue = positive64BitValueOf(oop);
  					goto l2;
  #          else /* BytesPerWord == 8 */
  					intValue = positive32BitValueOf(oop);
  					goto l2;
  #          endif /* BytesPerWord == 8 */
  				}
  			}
  			intValue = signedMachineIntegerValueOf(oop);
  	l2:	/* end ffiIntegerValueOf: */;
  		}
  		if (failed()) {
  			return FFIErrorCoercionFailed;
  		}
  		
  		switch (atomicType) {
  		case 0:
  			return FFIErrorAttemptToPassVoid;
  		case 1:
  			return ffiPushUnsignedIntin(intValue, calloutState);
  		case 2:
  			return ffiPushUnsignedBytein(intValue, calloutState);
  		case 3:
  			return ffiPushSignedBytein(intValue, calloutState);
  		case 4:
  			return ffiPushUnsignedShortin(intValue, calloutState);
  		case 5:
  			return ffiPushSignedShortin(intValue, calloutState);
  		case 6:
  			return ffiPushUnsignedIntin(intValue, calloutState);
  		case 7:
  			return ffiPushSignedIntin(intValue, calloutState);
  		case 8:
  			return ffiPushUnsignedLongLongOopin(intValue, calloutState);
  		case 9:
  			return ffiPushSignedLongLongOopin(intValue, calloutState);
  		case 10:
  			return ffiPushUnsignedCharin(intValue, calloutState);
  		case 11:
  			return ffiPushSignedCharin(intValue, calloutState);
  
  		default:
  			error("Case not found");
  			return -1;
  		}
  	}
  	/* begin ffiFloatValueOf: */
  	if (isFloatObject(oop)) {
  		floatValue = floatValueOf(oop);
  		goto l3;
  	}
  	floatValue = ((double) (ffiIntegerValueOf(oop)) );
  	l3:	/* end ffiFloatValueOf: */;
  	if (failed()) {
  		return FFIErrorCoercionFailed;
  	}
  	if (atomicType == FFITypeSingleFloat) {
  		/* begin ffiPushSingleFloat:in: */
  		if (((calloutState->floatRegisterIndex)) < NumFloatRegArgs) {
  
  			/* Note: this is a 'memcopy', so size is preserved. Casting to #double changes the size */
  			(((float*) ((&(((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)])))))[0] = floatValue;
  			(calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + 1);
  		}
  		else {
  			if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  				return FFIErrorCallFrameTooBig;
  			}
  			storeSingleFloatAtPointerfrom((calloutState->currentArg), floatValue);
  			(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  		}
  		return 0;
  	}
  	else {
  		/* begin ffiPushDoubleFloat:in: */
  		if (((calloutState->floatRegisterIndex)) < NumFloatRegArgs) {
  			((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)] = floatValue;
  			(calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + 1);
  		}
  		else {
  			if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  				return FFIErrorCallFrameTooBig;
  			}
  			(calloutState->floatRegisterIndex = NumFloatRegArgs);
  			storeFloatAtPointerfrom((calloutState->currentArg), floatValue);
  			(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  		}
  		return 0;
  	}
  }
  
  
  /*	Callout support. Prepare the given oop as argument.
  	argSpec defines the compiled spec for the argument.
  	argClass (if non-nil) defines the required (super)class for the argument. */
  
  	/* ThreadedFFIPlugin>>#ffiArgument:Spec:Class:in: */
  static sqInt
  ffiArgumentSpecClassin(sqInt oop, sqInt argSpec, sqInt argClass, CalloutState *calloutState)
  {
      sqInt *argSpec1;
      sqInt *argSpec2;
      sqInt argSpecSize;
      sqInt argSpecSize1;
      sqInt atomicType;
      sqInt atomicType1;
      sqInt atomicType2;
      sqInt availableRegisterSpace;
      sqInt availableRegisterSpace1;
      char *copy;
      sqInt err;
      double floatValue;
      sqInt intValue;
      sqInt isAlien;
      sqInt isString;
      sqInt isStruct;
      sqInt length;
      sqInt nilOop;
      sqInt oopClass;
      char *pointer;
      void *pointer1;
      void *pointer2;
      void *pointer3;
      void *pointer4;
      void *pointer5;
      void *pointer6;
      void * ptrAddress;
      sqInt ptrClass;
      sqInt ptrType;
      sqInt roundedSize;
      sqInt roundedSize1;
      sqInt spec;
      sqInt specOop;
      sqInt specType;
      sqInt stackPartSize;
      sqInt stackPartSize1;
      sqInt structSize;
      sqInt structSize1;
      sqInt typeSpec;
      sqInt typeSpec1;
      sqInt typeSpec2;
      sqInt valueOop;
      sqInt valueOop1;
  
  
  	/* Prefetch class (we'll need it) */
  	oopClass = fetchClassOf(oop);
  
  	/* Do the necessary type checks */
  	nilOop = nilObject();
  	if (!(argClass == nilOop)) {
  
  		/* Type check 1:
  		   Is the required class of the argument a subclass of ExternalStructure? */
  		if (!(includesBehaviorThatOf(argClass, classExternalStructure()))) {
  			return FFIErrorWrongType;
  		}
  		if (!((nilOop == oop)
  			 || (includesBehaviorThatOf(oopClass, argClass)))) {
  			return FFIErrorCoercionFailed;
  		}
  	}
  	isStruct = 0;
  	if ((oop != nilOop)
  	 && (isPointers(oop))) {
  
  		/* #isPointers: will fail if oop is immediate so don't even attempt to use it */
  		isStruct = includesBehaviorThatOf(oopClass, classExternalStructure());
  		if (!((argClass == nilOop)
  			 || (isStruct))) {
  			return FFIErrorCoercionFailed;
  		}
  	}
  	if (isStruct) {
  		valueOop = fetchPointerofObject(0, oop);
  	}
  	else {
  		valueOop = oop;
  	}
  	if (!(isWords(argSpec))) {
  		return FFIErrorWrongType;
  	}
  	(calloutState->ffiArgSpecSize = slotSizeOf(argSpec));
  	if (((calloutState->ffiArgSpecSize)) == 0) {
  		return FFIErrorWrongType;
  	}
  	(calloutState->ffiArgSpec = firstIndexableField(argSpec));
  	(calloutState->ffiArgHeader = longAt((calloutState->ffiArgSpec)));
  	if (((calloutState->ffiArgHeader)) & FFIFlagStructure) {
  
  		/* argument must be ExternalStructure */
  		if (!isStruct) {
  			return FFIErrorCoercionFailed;
  		}
  		if (((calloutState->ffiArgHeader)) & FFIFlagAtomic) {
  			return FFIErrorWrongType;
  		}
  		/* begin ffiPushStructureContentsOf:in: */
  		ptrClass = fetchClassOf(valueOop);
  		if (ptrClass == (classExternalAddress())) {
  
  			/* ExternalAddress is bytes */
  
  			/* There is no way we can make sure the structure is valid.
  			   But we can at least check for attempts to pass pointers to ST memory. */
  			ptrAddress = ((void *)(fetchPointerofObject(0, valueOop)));
  			if (isInMemory(ptrAddress)) {
  				return FFIErrorInvalidPointer;
  			}
  			/* begin ffiPushStructure:ofSize:typeSpec:ofLength:in: */
  			structSize = ((calloutState->ffiArgHeader)) & FFIStructSizeMask;
  			argSpec2 = (calloutState->ffiArgSpec);
  			argSpecSize = (calloutState->ffiArgSpecSize);
  			availableRegisterSpace = (NumIntRegArgs - ((calloutState->integerRegisterIndex))) * BytesPerWord;
  			stackPartSize = structSize;
  			if (availableRegisterSpace > 0) {
  				if (structSize <= availableRegisterSpace) {
  
  					/* all in registers */
  					stackPartSize = 0;
  					memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ptrAddress, structSize);
  					(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + (((usqInt) (structSize + 3) >> 3)));
  				}
  				else {
  
  					/* If no previous co-processor candidate arg has already been pushed on the stack, then split the struct between registers and stack.
  					   Otherwise push entire struct on stack. */
  					if (((calloutState->currentArg)) == ((calloutState->argVector))) {
  						stackPartSize = structSize - availableRegisterSpace;
  						memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ptrAddress, availableRegisterSpace);
  					}
  					else {
  						availableRegisterSpace = 0;
  					}
  					(calloutState->integerRegisterIndex = NumIntRegArgs);
  				}
  			}
  			if (stackPartSize > 0) {
  				roundedSize = (((stackPartSize + 3) | 3) - 3);
  				if ((((calloutState->currentArg)) + roundedSize) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				memcpy((calloutState->currentArg), (&((((char *) ptrAddress))[availableRegisterSpace])), stackPartSize);
  				(calloutState->currentArg = ((calloutState->currentArg)) + roundedSize);
  			}
  			return 0;
  		}
  		if (ptrClass == (classByteArray())) {
  
  			/* The following is a somewhat pessimistic test but I like being sure... */
  			if (!((byteSizeOf(valueOop)) == (((calloutState->ffiArgHeader)) & FFIStructSizeMask))) {
  				return FFIErrorStructSize;
  			}
  			ptrAddress = firstIndexableField(valueOop);
  			if (!(((calloutState->ffiArgHeader)) & FFIFlagPointer)) {
  
  				/* Since this involves passing the address of the first indexable field we need to fail
  				   the call if it is threaded and the object is young, since it may move during the call. */
  				
  #        if COGMTVM
  				if ((((calloutState->callFlags)) & FFICallFlagThreaded)
  				 && (isYoung(valueOop))) {
  					return -PrimErrObjectMayMove;
  				}
  #        endif /* COGMTVM */
  				/* begin ffiPushStructure:ofSize:typeSpec:ofLength:in: */
  				structSize1 = ((calloutState->ffiArgHeader)) & FFIStructSizeMask;
  				argSpec1 = (calloutState->ffiArgSpec);
  				argSpecSize1 = (calloutState->ffiArgSpecSize);
  				availableRegisterSpace1 = (NumIntRegArgs - ((calloutState->integerRegisterIndex))) * BytesPerWord;
  				stackPartSize1 = structSize1;
  				if (availableRegisterSpace1 > 0) {
  					if (structSize1 <= availableRegisterSpace1) {
  
  						/* all in registers */
  						stackPartSize1 = 0;
  						memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ptrAddress, structSize1);
  						(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + (((usqInt) (structSize1 + 3) >> 3)));
  					}
  					else {
  
  						/* If no previous co-processor candidate arg has already been pushed on the stack, then split the struct between registers and stack.
  						   Otherwise push entire struct on stack. */
  						if (((calloutState->currentArg)) == ((calloutState->argVector))) {
  							stackPartSize1 = structSize1 - availableRegisterSpace1;
  							memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ptrAddress, availableRegisterSpace1);
  						}
  						else {
  							availableRegisterSpace1 = 0;
  						}
  						(calloutState->integerRegisterIndex = NumIntRegArgs);
  					}
  				}
  				if (stackPartSize1 > 0) {
  					roundedSize1 = (((stackPartSize1 + 3) | 3) - 3);
  					if ((((calloutState->currentArg)) + roundedSize1) > ((calloutState->limit))) {
  						return FFIErrorCallFrameTooBig;
  					}
  					memcpy((calloutState->currentArg), (&((((char *) ptrAddress))[availableRegisterSpace1])), stackPartSize1);
  					(calloutState->currentArg = ((calloutState->currentArg)) + roundedSize1);
  				}
  				return 0;
  			}
  			if (!((((calloutState->ffiArgHeader)) & FFIStructSizeMask) == BytesPerWord)) {
  				return FFIErrorStructSize;
  			}
  			ptrAddress = ((void *)(fetchPointerofObject(0, valueOop)));
  			if (isInMemory(ptrAddress)) {
  				return FFIErrorInvalidPointer;
  			}
  			/* begin ffiPushPointer:in: */
  			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
  				(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  			}
  			else {
  				if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				longAtput((calloutState->currentArg), ptrAddress);
  				(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  			}
  			return 0;
  		}
  		return FFIErrorBadArg;
  	}
  	if (((calloutState->ffiArgHeader)) & FFIFlagPointer) {
  
  		/* no integers (or characters) for pointers please */
  		if (isImmediate(oop)) {
  			return FFIErrorIntAsPointer;
  		}
  		if (oop == nilOop) {
  			/* begin ffiPushPointer:in: */
  			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)null));
  				(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  			}
  			else {
  				if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				longAtput((calloutState->currentArg), null);
  				(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  			}
  			return 0;
  		}
  		if (((calloutState->ffiArgHeader)) & FFIFlagAtomic) {
  
  			/* e.g., ExternalData */
  			if (isStruct) {
  				/* begin ffiAtomicStructByReference:Class:in: */
  				if (!(oopClass == (classExternalData()))) {
  					return FFIErrorCoercionFailed;
  				}
  				/* begin atomicTypeOf: */
  				typeSpec = (calloutState->ffiArgHeader);
  				atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  				if (atomicType != FFITypeVoid) {
  					/* begin ffiValidateExternalData:AtomicType: */
  					ptrType = fetchPointerofObject(1, oop);
  					if (!((isPointers(ptrType))
  						 && ((slotSizeOf(ptrType)) >= 2))) {
  						err = FFIErrorWrongType;
  						goto l3;
  					}
  					specOop = fetchPointerofObject(0, ptrType);
  					if (!((isWords(specOop))
  						 && ((slotSizeOf(specOop)) > 0))) {
  						err = FFIErrorWrongType;
  						goto l3;
  					}
  					spec = fetchPointerofObject(0, specOop);
  					if (!(spec & FFIFlagAtomic)) {
  						err = FFIErrorWrongType;
  						goto l3;
  					}
  					/* begin atomicTypeOf: */
  					specType = ((usqInt) (spec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  					if (specType != atomicType) {
  
  						/* Allow for signed/unsigned conversion but nothing else.
  						   See FFIConstants class>>#initializeTypeConstants */
  						if (!((atomicType >= FFITypeUnsignedByte)
  							 && ((atomicType <= FFITypeSignedChar)
  							 && ((((usqInt) atomicType) >> 1) == (((usqInt) specType) >> 1))))) {
  							err = FFIErrorCoercionFailed;
  							goto l3;
  						}
  					}
  					err = 0;
  	l3:	/* end ffiValidateExternalData:AtomicType: */;
  					if (err != 0) {
  						return err;
  					}
  				}
  				valueOop1 = fetchPointerofObject(0, oop);
  				return ffiPushPointerContentsOfin(valueOop1, calloutState);
  			}
  			else {
  				/* begin ffiAtomicArgByReference:Class:in: */
  				typeSpec1 = (calloutState->ffiArgHeader);
  				atomicType1 = ((usqInt) (typeSpec1 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  				if (atomicType1 == FFITypeBool) {
  
  					/* No bools on input */
  					return FFIErrorCoercionFailed;
  				}
  				isAlien = ((isString = includesBehaviorThatOf(oopClass, classString()))
  					? 0
  					: includesBehaviorThatOf(oopClass, classAlien()));
  				if ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {
  
  					/* string value (char*) */
  					/* note: the only types allowed for passing into char* types are
  					   ByteArray, String, Symbol, Alien and *no* other byte indexed objects
  					   (e.g., CompiledMethod, LargeInteger). We only check for strings
  					   here and fall through to the byte* check otherwise. */
  					if (isString) {
  
  						/* String/Symbol */
  						/* Strings must be allocated by the ffi support code */
  						/* begin ffiPushString:OfLength:in: */
  						pointer = ((char *) (firstIndexableField(oop)));
  						length = byteSizeOf(oop);
  						if (((calloutState->stringArgIndex)) >= MaxNumArgs) {
  							return -PrimErrBadNumArgs;
  						}
  						copy = malloc(length + 1);
  						if (copy == null) {
  							return -PrimErrNoCMemory;
  						}
  						memcpy(copy, pointer, length);
  						copy[length] = 0;
  						((calloutState->stringArgs))[(calloutState->stringArgIndex)] = copy;
  						(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) + 1);
  						/* begin ffiPushPointer:in: */
  						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)copy));
  							(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  						}
  						else {
  							if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  								return FFIErrorCallFrameTooBig;
  							}
  							longAtput((calloutState->currentArg), copy);
  							(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  						}
  						return 0;
  					}
  					atomicType1 = FFITypeUnsignedByte;
  				}
  				
  #        if COGMTVM
  
  				/* Since all the following pass the address of the first indexable field we need to fail
  				   the call if it is threaded and the object is young, since it may move during the call. */
  				if ((((calloutState->callFlags)) & FFICallFlagThreaded)
  				 && (((!isAlien)
  				 || ((assert(isAlien(oop)),
  				(longAt(oop + BaseHeaderSize)) > 0)))
  				 && (isYoung(oop)))) {
  					return -PrimErrObjectMayMove;
  				}
  #        endif /* COGMTVM */
  				if ((atomicType1 == FFITypeVoid)
  				 || ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedByte) >> 1))) {
  
  					/* byte* -- see comment on string above */
  					if (isString
  					 || (oopClass == (classByteArray()))) {
  
  						/* String/Symbol/ByteArray */
  						/* begin ffiPushPointer:in: */
  						pointer1 = ((void *) (firstIndexableField(oop)));
  						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer1));
  							(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  						}
  						else {
  							if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  								return FFIErrorCallFrameTooBig;
  							}
  							longAtput((calloutState->currentArg), pointer1);
  							(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  						}
  						return 0;
  					}
  					if (oopClass == (classExternalAddress())) {
  						/* begin ffiPushPointer:in: */
  						pointer2 = ((void *) (longAt(oop + BaseHeaderSize)));
  						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer2));
  							(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  						}
  						else {
  							if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  								return FFIErrorCallFrameTooBig;
  							}
  							longAtput((calloutState->currentArg), pointer2);
  							(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  						}
  						return 0;
  					}
  					if (isAlien) {
  						/* begin ffiPushPointer:in: */
  						pointer3 = pointerForOop(((longAt(oop + BaseHeaderSize)) > 0
  							? (oop + BaseHeaderSize) + BytesPerOop
  							: longAt((oop + BaseHeaderSize) + BytesPerOop)));
  						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer3));
  							(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  						}
  						else {
  							if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  								return FFIErrorCallFrameTooBig;
  							}
  							longAtput((calloutState->currentArg), pointer3);
  							(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  						}
  						return 0;
  					}
  					if (!(atomicType1 == FFITypeVoid)) {
  						return FFIErrorCoercionFailed;
  					}
  				}
  				if (atomicType1 <= FFITypeDoubleFloat) {
  					if ((isWords(oop))
  					 || (oopClass == (classByteArray()))) {
  						/* begin ffiPushPointer:in: */
  						pointer4 = ((void *) (firstIndexableField(oop)));
  						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer4));
  							(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  						}
  						else {
  							if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  								return FFIErrorCallFrameTooBig;
  							}
  							longAtput((calloutState->currentArg), pointer4);
  							(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  						}
  						return 0;
  					}
  					if (oopClass == (classExternalAddress())) {
  						/* begin ffiPushPointer:in: */
  						pointer5 = ((void *) (longAt(oop + BaseHeaderSize)));
  						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer5));
  							(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  						}
  						else {
  							if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  								return FFIErrorCallFrameTooBig;
  							}
  							longAtput((calloutState->currentArg), pointer5);
  							(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  						}
  						return 0;
  					}
  					if (isAlien) {
  						/* begin ffiPushPointer:in: */
  						pointer6 = pointerForOop(((longAt(oop + BaseHeaderSize)) > 0
  							? (oop + BaseHeaderSize) + BytesPerOop
  							: longAt((oop + BaseHeaderSize) + BytesPerOop)));
  						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer6));
  							(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  						}
  						else {
  							if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  								return FFIErrorCallFrameTooBig;
  							}
  							longAtput((calloutState->currentArg), pointer6);
  							(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  						}
  						return 0;
  					}
  				}
  				return FFIErrorCoercionFailed;
  			}
  		}
  		if (!isStruct) {
  			return FFIErrorCoercionFailed;
  		}
  		return ffiPushPointerContentsOfin(valueOop, calloutState);
  	}
  	if (((calloutState->ffiArgHeader)) & FFIFlagAtomic) {
  
  		/* argument is atomic value */
  		/* begin ffiArgByValue:in: */
  		typeSpec2 = (calloutState->ffiArgHeader);
  		atomicType2 = ((usqInt) (typeSpec2 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  		if ((atomicType2 < 0)
  		 || (atomicType2 > FFITypeDoubleFloat)) {
  			return FFIErrorBadAtomicType;
  		}
  		if (atomicType2 < FFITypeSingleFloat) {
  
  			/* integer types */
  			if ((((usqInt) atomicType2) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)) {
  
  				/* ffi support code must coerce longlong */
  				intValue = valueOop;
  			}
  			else {
  				/* begin ffiIntegerValueOf: */
  				if (valueOop & (BytesPerWord - 1)) {
  					if (isIntegerObject(valueOop)) {
  						intValue = integerValueOf(valueOop);
  						goto l7;
  					}
  					
  #          if SPURVM
  					if (isCharacterObject(valueOop)) {
  
  						/* Immediate in Spur */
  						intValue = characterValueOf(valueOop);
  						goto l7;
  					}
  					if (isFloatObject(valueOop)) {
  
  						/* Immediate in 64-bit Spur */
  						intValue = floatValueOf(valueOop);
  						goto l7;
  					}
  #          endif /* SPURVM */
  				}
  				else {
  					
  #          if SPURVM
  
  					/* No non-immediate characters in Spur */
  #          else /* SPURVM */
  					if (isCharacterObject(valueOop)) {
  						intValue = characterValueOf(valueOop);
  						goto l7;
  					}
  #          endif /* SPURVM */
  					if (isFloatObject(valueOop)) {
  						intValue = floatValueOf(valueOop);
  						goto l7;
  					}
  					if (valueOop == (nilObject())) {
  						intValue = 0;
  						goto l7;
  					}
  					if (valueOop == (falseObject())) {
  						intValue = 0;
  						goto l7;
  					}
  					if (valueOop == (trueObject())) {
  						intValue = 1;
  						goto l7;
  					}
  					if (isLargePositiveIntegerObject(valueOop)) {
  						
  #            if BytesPerWord == 8
  
  						/* Use cppIf: to get the return type of the function right.  Should be sqInt on 32-bits. */
  						intValue = positive64BitValueOf(valueOop);
  						goto l7;
  #            else /* BytesPerWord == 8 */
  						intValue = positive32BitValueOf(valueOop);
  						goto l7;
  #            endif /* BytesPerWord == 8 */
  					}
  				}
  				intValue = signedMachineIntegerValueOf(valueOop);
  	l7:	/* end ffiIntegerValueOf: */;
  			}
  			if (failed()) {
  				return FFIErrorCoercionFailed;
  			}
  			
  			switch (atomicType2) {
  			case 0:
  				return FFIErrorAttemptToPassVoid;
  			case 1:
  				return ffiPushUnsignedIntin(intValue, calloutState);
  			case 2:
  				return ffiPushUnsignedBytein(intValue, calloutState);
  			case 3:
  				return ffiPushSignedBytein(intValue, calloutState);
  			case 4:
  				return ffiPushUnsignedShortin(intValue, calloutState);
  			case 5:
  				return ffiPushSignedShortin(intValue, calloutState);
  			case 6:
  				return ffiPushUnsignedIntin(intValue, calloutState);
  			case 7:
  				return ffiPushSignedIntin(intValue, calloutState);
  			case 8:
  				return ffiPushUnsignedLongLongOopin(intValue, calloutState);
  			case 9:
  				return ffiPushSignedLongLongOopin(intValue, calloutState);
  			case 10:
  				return ffiPushUnsignedCharin(intValue, calloutState);
  			case 11:
  				return ffiPushSignedCharin(intValue, calloutState);
  
  			default:
  				error("Case not found");
  				return -1;
  			}
  		}
  		/* begin ffiFloatValueOf: */
  		if (isFloatObject(valueOop)) {
  			floatValue = floatValueOf(valueOop);
  			goto l5;
  		}
  		floatValue = ((double) (ffiIntegerValueOf(valueOop)) );
  	l5:	/* end ffiFloatValueOf: */;
  		if (failed()) {
  			return FFIErrorCoercionFailed;
  		}
  		if (atomicType2 == FFITypeSingleFloat) {
  			/* begin ffiPushSingleFloat:in: */
  			if (((calloutState->floatRegisterIndex)) < NumFloatRegArgs) {
  
  				/* Note: this is a 'memcopy', so size is preserved. Casting to #double changes the size */
  				(((float*) ((&(((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)])))))[0] = floatValue;
  				(calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + 1);
  			}
  			else {
  				if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				storeSingleFloatAtPointerfrom((calloutState->currentArg), floatValue);
  				(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  			}
  			return 0;
  		}
  		else {
  			/* begin ffiPushDoubleFloat:in: */
  			if (((calloutState->floatRegisterIndex)) < NumFloatRegArgs) {
  				((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)] = floatValue;
  				(calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + 1);
  			}
  			else {
  				if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				(calloutState->floatRegisterIndex = NumFloatRegArgs);
  				storeFloatAtPointerfrom((calloutState->currentArg), floatValue);
  				(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  			}
  			return 0;
  		}
  	}
  	return FFIErrorWrongType;
  }
  
  
  /*	Support for generic callout. Prepare a pointer reference to an atomic type
  	for callout.
  	Note: 
  	for type 'void*' we allow ByteArray/String/Symbol, wordVariableSubclass,
  	Alien or ExternalAddress.
  	for other types we allow ByteArray, wordVariableSubclass, Alien or
  	ExternalAddress. 
   */
  
  	/* ThreadedFFIPlugin>>#ffiAtomicArgByReference:Class:in: */
  static sqInt
  ffiAtomicArgByReferenceClassin(sqInt oop, sqInt oopClass, CalloutState *calloutState)
  {
      sqInt atomicType;
      char *copy;
      sqInt isAlien;
      sqInt isString;
      sqInt length;
      char *pointer;
      void *pointer1;
      void *pointer2;
      void *pointer3;
      void *pointer4;
      void *pointer5;
      void *pointer6;
      sqInt typeSpec;
  
  	/* begin atomicTypeOf: */
  	typeSpec = (calloutState->ffiArgHeader);
  	atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  	if (atomicType == FFITypeBool) {
  
  		/* No bools on input */
  		return FFIErrorCoercionFailed;
  	}
  	isAlien = ((isString = includesBehaviorThatOf(oopClass, classString()))
  		? 0
  		: includesBehaviorThatOf(oopClass, classAlien()));
  	if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {
  
  		/* string value (char*) */
  		/* note: the only types allowed for passing into char* types are
  		   ByteArray, String, Symbol, Alien and *no* other byte indexed objects
  		   (e.g., CompiledMethod, LargeInteger). We only check for strings
  		   here and fall through to the byte* check otherwise. */
  		if (isString) {
  
  			/* String/Symbol */
  			/* Strings must be allocated by the ffi support code */
  			/* begin ffiPushString:OfLength:in: */
  			pointer = ((char *) (firstIndexableField(oop)));
  			length = byteSizeOf(oop);
  			if (((calloutState->stringArgIndex)) >= MaxNumArgs) {
  				return -PrimErrBadNumArgs;
  			}
  			copy = malloc(length + 1);
  			if (copy == null) {
  				return -PrimErrNoCMemory;
  			}
  			memcpy(copy, pointer, length);
  			copy[length] = 0;
  			((calloutState->stringArgs))[(calloutState->stringArgIndex)] = copy;
  			(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) + 1);
  			/* begin ffiPushPointer:in: */
  			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)copy));
  				(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  			}
  			else {
  				if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				longAtput((calloutState->currentArg), copy);
  				(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  			}
  			return 0;
  		}
  		atomicType = FFITypeUnsignedByte;
  	}
  	
  #  if COGMTVM
  
  	/* Since all the following pass the address of the first indexable field we need to fail
  	   the call if it is threaded and the object is young, since it may move during the call. */
  	if ((((calloutState->callFlags)) & FFICallFlagThreaded)
  	 && (((!isAlien)
  	 || ((assert(isAlien(oop)),
  	(longAt(oop + BaseHeaderSize)) > 0)))
  	 && (isYoung(oop)))) {
  		return -PrimErrObjectMayMove;
  	}
  #  endif /* COGMTVM */
  	if ((atomicType == FFITypeVoid)
  	 || ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedByte) >> 1))) {
  
  		/* byte* -- see comment on string above */
  		if (isString
  		 || (oopClass == (classByteArray()))) {
  
  			/* String/Symbol/ByteArray */
  			/* begin ffiPushPointer:in: */
  			pointer1 = ((void *) (firstIndexableField(oop)));
  			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer1));
  				(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  			}
  			else {
  				if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				longAtput((calloutState->currentArg), pointer1);
  				(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  			}
  			return 0;
  		}
  		if (oopClass == (classExternalAddress())) {
  			/* begin ffiPushPointer:in: */
  			pointer2 = ((void *) (longAt(oop + BaseHeaderSize)));
  			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer2));
  				(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  			}
  			else {
  				if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				longAtput((calloutState->currentArg), pointer2);
  				(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  			}
  			return 0;
  		}
  		if (isAlien) {
  			/* begin ffiPushPointer:in: */
  			pointer3 = pointerForOop(((longAt(oop + BaseHeaderSize)) > 0
  				? (oop + BaseHeaderSize) + BytesPerOop
  				: longAt((oop + BaseHeaderSize) + BytesPerOop)));
  			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer3));
  				(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  			}
  			else {
  				if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				longAtput((calloutState->currentArg), pointer3);
  				(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  			}
  			return 0;
  		}
  		if (!(atomicType == FFITypeVoid)) {
  			return FFIErrorCoercionFailed;
  		}
  	}
  	if (atomicType <= FFITypeDoubleFloat) {
  		if ((isWords(oop))
  		 || (oopClass == (classByteArray()))) {
  			/* begin ffiPushPointer:in: */
  			pointer4 = ((void *) (firstIndexableField(oop)));
  			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer4));
  				(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  			}
  			else {
  				if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				longAtput((calloutState->currentArg), pointer4);
  				(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  			}
  			return 0;
  		}
  		if (oopClass == (classExternalAddress())) {
  			/* begin ffiPushPointer:in: */
  			pointer5 = ((void *) (longAt(oop + BaseHeaderSize)));
  			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer5));
  				(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  			}
  			else {
  				if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				longAtput((calloutState->currentArg), pointer5);
  				(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  			}
  			return 0;
  		}
  		if (isAlien) {
  			/* begin ffiPushPointer:in: */
  			pointer6 = pointerForOop(((longAt(oop + BaseHeaderSize)) > 0
  				? (oop + BaseHeaderSize) + BytesPerOop
  				: longAt((oop + BaseHeaderSize) + BytesPerOop)));
  			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer6));
  				(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  			}
  			else {
  				if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				longAtput((calloutState->currentArg), pointer6);
  				(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  			}
  			return 0;
  		}
  	}
  	return FFIErrorCoercionFailed;
  }
  
  
  /*	Support for generic callout. Prepare an external pointer reference to an
  	atomic type for callout.
   */
  
  	/* ThreadedFFIPlugin>>#ffiAtomicStructByReference:Class:in: */
  static sqInt
  ffiAtomicStructByReferenceClassin(sqInt oop, sqInt oopClass, CalloutState *calloutState)
  {
      sqInt atomicType;
      sqInt err;
      sqInt ptrType;
      sqInt spec;
      sqInt specOop;
      sqInt specType;
      sqInt typeSpec;
      sqInt valueOop;
  
  
  	/* must be external data to pass pointers to atomic type */
  	if (!(oopClass == (classExternalData()))) {
  		return FFIErrorCoercionFailed;
  	}
  	/* begin atomicTypeOf: */
  	typeSpec = (calloutState->ffiArgHeader);
  	atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  	if (atomicType != FFITypeVoid) {
  		/* begin ffiValidateExternalData:AtomicType: */
  		ptrType = fetchPointerofObject(1, oop);
  		if (!((isPointers(ptrType))
  			 && ((slotSizeOf(ptrType)) >= 2))) {
  			err = FFIErrorWrongType;
  			goto l3;
  		}
  		specOop = fetchPointerofObject(0, ptrType);
  		if (!((isWords(specOop))
  			 && ((slotSizeOf(specOop)) > 0))) {
  			err = FFIErrorWrongType;
  			goto l3;
  		}
  		spec = fetchPointerofObject(0, specOop);
  		if (!(spec & FFIFlagAtomic)) {
  			err = FFIErrorWrongType;
  			goto l3;
  		}
  		/* begin atomicTypeOf: */
  		specType = ((usqInt) (spec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  		if (specType != atomicType) {
  
  			/* Allow for signed/unsigned conversion but nothing else.
  			   See FFIConstants class>>#initializeTypeConstants */
  			if (!((atomicType >= FFITypeUnsignedByte)
  				 && ((atomicType <= FFITypeSignedChar)
  				 && ((((usqInt) atomicType) >> 1) == (((usqInt) specType) >> 1))))) {
  				err = FFIErrorCoercionFailed;
  				goto l3;
  			}
  		}
  		err = 0;
  	l3:	/* end ffiValidateExternalData:AtomicType: */;
  		if (err != 0) {
  			return err;
  		}
  	}
  	valueOop = fetchPointerofObject(0, oop);
  	return ffiPushPointerContentsOfin(valueOop, calloutState);
  }
  
  
  /*	Go out, call this guy and create the return value. This *must* be inlined
  	because of
  	the alloca of the outgoing stack frame in
  	ffiCall:WithFlags:NumArgs:Args:AndTypes: 
   */
  
  	/* ThreadedARM64FFIPlugin>>#ffiCalloutTo:SpecOnStack:in: */
  static sqInt
  ffiCalloutToSpecOnStackin(void *procAddr, sqInt specOnStack, CalloutState *calloutState)
  {
      sqInt argTypes;
      sqInt argTypes1;
      sqLong arrayAddr;
      sqInt atomicType;
      sqInt atomicType1;
      sqInt byteSize;
      extern void callAndReturnWithStructAddr(sqLong structAddr,sqLong procAddr,sqLong arrayAddr);
      sqInt classOop;
      sqInt cPointer;
      char *cString;
      sqInt ffiRetType;
      double floatRet;
      sqInt i;
      usqLong intRet;
      extern void loadFloatRegs(double, double, double, double, double, double, double, double);
      usqLong mask;
      sqInt myThreadIndex;
      sqInt oop;
      sqInt oop1;
      sqInt *ptr;
      sqInt retClass;
      sqInt retClass1;
      sqInt retOop;
      sqInt retOop1;
      sqInt retType;
      extern sqLong returnX1value();
      sqInt shift;
      sqInt specLiteral;
      sqInt specLiteral1;
      sqInt strLen;
      sqInt strOop;
      char *strPtr;
      sqLong structAddr;
      sqInt typeSpec;
      sqInt typeSpec1;
      usqLong value;
      usqLong x1Ret;
  
  	x1Ret = 0;
  	myThreadIndex = disownVM(
  #  if COGMTVM
  		(((calloutState->callFlags)) & FFICallFlagThreaded
  				? DisownVMForFFICall + DisownVMForThreading
  				: DisownVMForFFICall)
  #  else /* COGMTVM */
  		DisownVMForFFICall
  #  endif /* COGMTVM */
  		);
  	if (((calloutState->floatRegisterIndex)) > 0) {
  		loadFloatRegs(((calloutState->floatRegisters))[0], ((calloutState->floatRegisters))[1], ((calloutState->floatRegisters))[2], ((calloutState->floatRegisters))[3], ((calloutState->floatRegisters))[4], ((calloutState->floatRegisters))[5], ((calloutState->floatRegisters))[6], ((calloutState->floatRegisters))[7]);
  	}
  	if ((allocaLiesSoSetSpBeforeCall())
  	 || (mustAlignStack())) {
  		setsp((calloutState->argVector));
  	}
  	/* begin atomicTypeOf: */
  	typeSpec = (calloutState->ffiRetHeader);
  	atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  	if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSingleFloat) >> 1)) {
  		if (atomicType == FFITypeSingleFloat) {
  			floatRet = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) procAddr), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3], ((calloutState->integerRegisters))[4], ((calloutState->integerRegisters))[5], ((calloutState->integerRegisters))[6], ((calloutState->integerRegisters))[7]);
  		}
  		else {
  
  			/* atomicType = FFITypeDoubleFloat */
  			floatRet = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) procAddr), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3], ((calloutState->integerRegisters))[4], ((calloutState->integerRegisters))[5], ((calloutState->integerRegisters))[6], ((calloutState->integerRegisters))[7]);
  		}
  		if (isCalleePopsConvention((calloutState->callFlags))) {
  			setsp((calloutState->argVector));
  		}
  		ownVM(myThreadIndex);
  		return floatObjectOf(floatRet);
  	}
  	if (((calloutState->structReturnSize)) > (2 * BytesPerWord)) {
  		intRet = 0;
  		/* begin setReturnRegister:andCall:withArgsArray: */
  		structAddr = ((sqLong) ((calloutState->limit)));
  		arrayAddr = ((sqLong) ((&((calloutState->integerRegisters)))));
  		callAndReturnWithStructAddr(structAddr, ((sqLong) procAddr), arrayAddr);
  	}
  	else {
  		intRet = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) procAddr), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3], ((calloutState->integerRegisters))[4], ((calloutState->integerRegisters))[5], ((calloutState->integerRegisters))[6], ((calloutState->integerRegisters))[7]);
  		x1Ret = returnX1value();
  	}
  	if ((((calloutState->structReturnSize)) > 0)
  	 && (((calloutState->structReturnSize)) <= (2 * BytesPerWord))) {
  
  		/* Only 2 regs used in ARMv8/Aarch64 current */
  		((calloutState->integerRegisters))[0] = intRet;
  		((calloutState->integerRegisters))[1] = x1Ret;
  	}
  	if (isCalleePopsConvention((calloutState->callFlags))) {
  		setsp((calloutState->argVector));
  	}
  	ownVM(myThreadIndex);
  	if (((calloutState->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) {
  
  		/* Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
  		   'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct. */
  		if (((calloutState->ffiRetHeader)) & FFIFlagPointer) {
  			/* begin ffiReturnPointer:ofType:in: */
  			specLiteral = (specOnStack
  				? stackValue(1)
  				: literalofMethod(0, primitiveMethod()));
  			argTypes = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral);
  			retType = fetchPointerofObject(0, argTypes);
  			retClass = fetchPointerofObject(1, retType);
  			if (retClass == (nilObject())) {
  
  				/* Create ExternalData upon return */
  				/* begin atomicTypeOf: */
  				typeSpec1 = (calloutState->ffiRetHeader);
  				atomicType1 = ((usqInt) (typeSpec1 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  				if ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {
  
  					/* String return */
  					/* begin ffiReturnCStringFrom: */
  					cPointer = ((usqInt) intRet);
  					if (!(cPointer)) {
  						retOop = nilObject();
  						goto l3;
  					}
  					cString = ((char *) cPointer);
  					strLen = 0;
  					while (!((cString[strLen]) == 0)) {
  						strLen += 1;
  					}
  					strOop = instantiateClassindexableSize(classString(), strLen);
  					strPtr = firstIndexableField(strOop);
  					for (i = 0; i < strLen; i += 1) {
  						strPtr[i] = (cString[i]);
  					}
  					retOop = strOop;
  	l3:	/* end ffiReturnCStringFrom: */;
  					return retOop;
  				}
  				
  #if SPURVM
  				oop = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  				ptr = firstIndexableField(oop);
  				ptr[0] = (((sqInt) intRet));
  				retOop = instantiateClassindexableSize(classExternalData(), 0);
  				storePointerofObjectwithValue(0, retOop, oop);
  
  #else /* SPURVM */
  				pushRemappableOop(retType);
  				oop = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  				ptr = firstIndexableField(oop);
  				ptr[0] = (((sqInt) intRet));
  								pushRemappableOop(oop);
  				retOop = instantiateClassindexableSize(classExternalData(), 0);
  				oop = popRemappableOop();
  				storePointerofObjectwithValue(0, retOop, oop);
  				retType = popRemappableOop()
  #endif /* SPURVM */
  ;
  				storePointerofObjectwithValue(1, retOop, retType);
  				return retOop;
  			}
  			classOop = (((calloutState->ffiRetHeader)) & FFIFlagStructure
  				? classByteArray()
  				: classExternalAddress());
  			
  #if SPURVM
  			oop = instantiateClassindexableSize(classOop, BytesPerWord);
  
  #else /* SPURVM */
  			pushRemappableOop(retClass);
  			oop = instantiateClassindexableSize(classOop, BytesPerWord);
  			retClass = popRemappableOop()
  #endif /* SPURVM */
  ;
  			ptr = firstIndexableField(oop);
  			ptr[0] = (((sqInt) intRet));
  			
  #if SPURVM
  			retOop = instantiateClassindexableSize(retClass, 0);
  
  #else /* SPURVM */
  			pushRemappableOop(oop);
  			retOop = instantiateClassindexableSize(retClass, 0);
  			oop = popRemappableOop()
  #endif /* SPURVM */
  ;
  			storePointerofObjectwithValue(0, retOop, oop);
  			return retOop;
  		}
  		/* begin ffiReturnStruct:ofType:in: */
  		specLiteral1 = (specOnStack
  			? stackValue(1)
  			: literalofMethod(0, primitiveMethod()));
  		argTypes1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral1);
  		ffiRetType = fetchPointerofObject(0, argTypes1);
  		retClass1 = fetchPointerofObject(1, ffiRetType);
  		retOop1 = instantiateClassindexableSize(retClass1, 0);
  		
  #if SPURVM
  		oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  
  #else /* SPURVM */
  		pushRemappableOop(retOop1);
  		oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  		retOop1 = popRemappableOop()
  #endif /* SPURVM */
  ;
  		memcpy(firstIndexableField(oop1), (((calloutState->structReturnSize)) <= (2 * BytesPerWord)
  			? (&((calloutState->integerRegisters)))
  			: (calloutState->limit)), (calloutState->structReturnSize));
  		storePointerofObjectwithValue(0, retOop1, oop1);
  		return retOop1;
  	}
  	/* begin ffiCreateIntegralResultOop:ofAtomicType:in: */
  	assert(atomicType < FFITypeSingleFloat);
  	if (atomicType == FFITypeBool) {
  
  		/* Make sure bool honors the byte size requested */
  		byteSize = ((calloutState->ffiRetHeader)) & FFIStructSizeMask;
  		value = (byteSize == (sizeof(intRet))
  			? intRet
  			: intRet & (((((unsigned long long)1)) << (byteSize * 8)) - 1));
  		return (value == 0
  			? falseObject()
  			: trueObject());
  	}
  	if (atomicType <= FFITypeSignedInt) {
  
  		/* these are all generall integer returns */
  		if (atomicType <= ((BytesPerWord == 8
  			? FFITypeSignedInt
  			: FFITypeSignedShort))) {
  
  			/* byte/short. first extract partial word, then sign extend */
  
  			/* # of significant bits */
  			shift = ((BytesPerWord == 8)
  			 && (atomicType >= FFITypeUnsignedInt)
  				? 32
  				: (((usqInt) atomicType) >> 1) * 8);
  			value = intRet & (((((unsigned long long)1)) << shift) - 1);
  			if (atomicType & 1) {
  
  				/* make the guy signed */
  				mask = (((unsigned long long)1)) << (shift - 1);
  				value = (value & (mask - 1)) - (value & mask);
  			}
  			return integerObjectOf(value);
  		}
  		return (atomicType & 1
  			? (BytesPerWord == 8
  					? signed64BitIntegerFor(intRet)
  					: signed32BitIntegerFor(intRet))
  			: (BytesPerWord == 8
  					? positive64BitIntegerFor(intRet)
  					: positive32BitIntegerFor(intRet)));
  	}
  	return ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
  		? (atomicType & 1
  				? signed64BitIntegerFor(intRet)
  				: positive64BitIntegerFor(intRet))
  		: characterObjectOf(intRet & 0xFF));
  }
  
  
  /*	Generic callout. Does the actual work. If argArrayOrNil is nil it takes
  	args from the stack
  	and the spec from the method. If argArrayOrNil is not nil takes args from
  	argArrayOrNil and the spec from the receiver. */
  
  	/* ThreadedARM64FFIPlugin>>#ffiCall:ArgArrayOrNil:NumArgs: */
  static sqInt
  ffiCallArgArrayOrNilNumArgs(sqInt externalFunction, sqInt argArrayOrNil, sqInt nArgs)
  {
      sqInt address;
      sqInt address1;
      sqInt addressPtr;
      char *allocation;
      sqInt argClass;
      sqInt argSpec;
      sqInt argType;
      sqInt argTypeArray;
      sqInt argTypes;
      sqInt argTypes1;
      sqLong arrayAddr;
      sqInt atomicType;
      sqInt atomicType1;
      sqInt byteSize;
      extern void callAndReturnWithStructAddr(sqLong structAddr,sqLong procAddr,sqLong arrayAddr);
      CalloutState *calloutState;
      sqInt classOop;
      sqInt cPointer;
      char *cString;
      sqInt err;
      sqInt ffiRetType;
      sqInt flags;
      double floatRet;
      sqInt functionName;
      sqInt i;
      sqInt i1;
      usqLong intRet;
      extern void loadFloatRegs(double, double, double, double, double, double, double, double);
      usqLong mask;
      sqInt myThreadIndex;
      sqInt oop;
      sqInt oop1;
      sqInt oop2;
      sqInt primNumArgs;
      sqIntptr_t *ptr;
      sqInt *ptr1;
      sqInt requiredStackSize;
      sqInt result;
      sqInt retClass;
      sqInt retClass1;
      sqInt retOop;
      sqInt retOop1;
      sqInt retType;
      extern sqLong returnX1value();
      sqInt shift;
      sqInt specLiteral;
      sqInt specLiteral1;
      sqInt stackSize;
      sqInt strLen;
      sqInt strOop;
      char *strPtr;
      sqLong structAddr;
      CalloutState theCalloutState;
      sqInt typeSpec;
      sqInt typeSpec1;
      usqLong value;
      usqLong x1Ret;
  
  	x1Ret = 0;
  	primNumArgs = methodArgumentCount();
  	if (!(isKindOfClass(externalFunction, classExternalFunction()))) {
  		return ffiFail(FFIErrorNotFunction);
  	}
  	flags = fetchIntegerofObject(ExternalFunctionFlagsIndex, externalFunction);
  	if (failed()) {
  		return ffiFail(FFIErrorBadArgs);
  	}
  	/* begin ffiLoadCalloutAddress: */
  
  	/* Make sure it's an external handle */
  	addressPtr = fetchPointerofObject(0, externalFunction);
  	if (!((isBytes(addressPtr))
  		 && ((byteSizeOf(addressPtr)) == (sizeof(sqInt))))) {
  		address1 = ffiFail(FFIErrorBadAddress);
  		goto l1;
  	}
  	address1 = fetchPointerofObject(0, addressPtr);
  	l1:	/* end ffiContentsOfHandle:errCode: */;
  	if (failed()) {
  		address = 0;
  		goto l2;
  	}
  	if (address1 == 0) {
  
  		/* Go look it up in the module */
  		if (externalFunctionInstSize > ExternalFunctionStackSizeIndex) {
  			storePointerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, integerObjectOf(-1));
  		}
  		if ((slotSizeOf(externalFunction)) < 5) {
  			address = ffiFail(FFIErrorNoModule);
  			goto l2;
  		}
  		address1 = ffiLoadCalloutAddressFrom(externalFunction);
  		if (failed()) {
  			address = 0;
  			goto l2;
  		}
  		ptr = firstIndexableField(addressPtr);
  		ptr[0] = address1;
  	}
  	address = address1;
  	l2:	/* end ffiLoadCalloutAddress: */;
  	if (failed()) {
  		return 0;
  	}
  
  	/* must be array of arg types */
  	argTypeArray = fetchPointerofObject(ExternalFunctionArgTypesIndex, externalFunction);
  	if (!((isArray(argTypeArray))
  		 && ((slotSizeOf(argTypeArray)) == (nArgs + 1)))) {
  		return ffiFail(FFIErrorBadArgs);
  	}
  	
  #  if COGMTVM
  	if (!(((flags & FFICallTypesMask) == FFICallTypeCDecl)
  		 || ((flags & FFICallTypesMask) == FFICallTypeApi))) {
  		return ffiFail(FFIErrorCallType);
  	}
  #  else /* COGMTVM */
  
  	/* not masking causes threaded calls to fail, which is as they should if the plugin is not threaded. */
  	if (!((flags == FFICallTypeCDecl)
  		 || (flags == FFICallTypeApi))) {
  		return ffiFail(FFIErrorCallType);
  	}
  #  endif /* COGMTVM */
  	requiredStackSize = (externalFunctionInstSize > ExternalFunctionStackSizeIndex
  		? fetchIntegerofObject(ExternalFunctionStackSizeIndex, externalFunction)
  		: -1);
  	if (failed()) {
  		return primitiveFailFor((argArrayOrNil == null
  			? PrimErrBadMethod
  			: PrimErrBadReceiver));
  	}
  	stackSize = (requiredStackSize < 0
  		? DefaultMaxStackSize
  		: requiredStackSize);
  	calloutState = (&theCalloutState);
  	memset(calloutState, 0, sizeof(CalloutState));
  	(calloutState->callFlags = flags);
  	argType = fetchPointerofObject(0, argTypeArray);
  	argSpec = fetchPointerofObject(0, argType);
  	argClass = fetchPointerofObject(1, argType);
  	if (((err = ffiCheckReturnWithin(argSpec, argClass, calloutState))) != 0) {
  		return ffiFail(err);
  	}
  	allocation = alloca((stackSize + ((calloutState->structReturnSize))) + (cStackAlignment()));
  	if (mustAlignStack()) {
  		allocation = ((char *) ((((((usqIntptr_t)allocation)) | ((cStackAlignment()) - 1)) - ((cStackAlignment()) - 1))));
  	}
  	(calloutState->argVector = allocation);
  	(calloutState->currentArg = allocation);
  	(calloutState->limit = allocation + stackSize);
  	for (i = 1; i <= nArgs; i += 1) {
  		argType = fetchPointerofObject(i, argTypeArray);
  		argSpec = fetchPointerofObject(0, argType);
  		argClass = fetchPointerofObject(1, argType);
  		oop = (argArrayOrNil == null
  			? stackValue(nArgs - i)
  			: fetchPointerofObject(i - 1, argArrayOrNil));
  		err = ffiArgumentSpecClassin(oop, argSpec, argClass, calloutState);
  		if (err != 0) {
  			/* begin cleanupCalloutState: */
  			while (((calloutState->stringArgIndex)) > 0) {
  				free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
  			}
  			
  #      if COGMTVM
  			if (err == (-PrimErrObjectMayMove)) {
  				return PrimErrObjectMayMove;
  			}
  #      endif /* COGMTVM */
  			return ffiFail(err);
  		}
  	}
  	assert(!(failed()));
  	/* begin ffiLogCallout: */
  	if (ffiLogEnabled) {
  		functionName = fetchPointerofObject(externalFunctionInstSize, externalFunction);
  		if (!(isBytes(functionName))) {
  			goto l3;
  		}
  		ffiLogCallOfLength(firstIndexableField(functionName), byteSizeOf(functionName));
  	}
  	l3:	/* end ffiLogCallout: */;
  	if ((requiredStackSize < 0)
  	 && (externalFunctionInstSize > ExternalFunctionStackSizeIndex)) {
  		stackSize = ((calloutState->currentArg)) - ((calloutState->argVector));
  		storeIntegerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, stackSize);
  	}
  	/* begin ffiCalloutTo:SpecOnStack:in: */
  	myThreadIndex = disownVM(
  #  if COGMTVM
  		(((calloutState->callFlags)) & FFICallFlagThreaded
  				? DisownVMForFFICall + DisownVMForThreading
  				: DisownVMForFFICall)
  #  else /* COGMTVM */
  		DisownVMForFFICall
  #  endif /* COGMTVM */
  		);
  	if (((calloutState->floatRegisterIndex)) > 0) {
  		loadFloatRegs(((calloutState->floatRegisters))[0], ((calloutState->floatRegisters))[1], ((calloutState->floatRegisters))[2], ((calloutState->floatRegisters))[3], ((calloutState->floatRegisters))[4], ((calloutState->floatRegisters))[5], ((calloutState->floatRegisters))[6], ((calloutState->floatRegisters))[7]);
  	}
  	if ((allocaLiesSoSetSpBeforeCall())
  	 || (mustAlignStack())) {
  		setsp((calloutState->argVector));
  	}
  	/* begin atomicTypeOf: */
  	typeSpec = (calloutState->ffiRetHeader);
  	atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  	if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSingleFloat) >> 1)) {
  		if (atomicType == FFITypeSingleFloat) {
  			floatRet = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3], ((calloutState->integerRegisters))[4], ((calloutState->integerRegisters))[5], ((calloutState->integerRegisters))[6], ((calloutState->integerRegisters))[7]);
  		}
  		else {
  
  			/* atomicType = FFITypeDoubleFloat */
  			floatRet = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3], ((calloutState->integerRegisters))[4], ((calloutState->integerRegisters))[5], ((calloutState->integerRegisters))[6], ((calloutState->integerRegisters))[7]);
  		}
  		if (isCalleePopsConvention((calloutState->callFlags))) {
  			setsp((calloutState->argVector));
  		}
  		ownVM(myThreadIndex);
  		result = floatObjectOf(floatRet);
  		goto l8;
  	}
  	if (((calloutState->structReturnSize)) > (2 * BytesPerWord)) {
  		intRet = 0;
  		/* begin setReturnRegister:andCall:withArgsArray: */
  		structAddr = ((sqLong) ((calloutState->limit)));
  		arrayAddr = ((sqLong) ((&((calloutState->integerRegisters)))));
  		callAndReturnWithStructAddr(structAddr, ((sqLong) (((void *) address))), arrayAddr);
  	}
  	else {
  		intRet = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3], ((calloutState->integerRegisters))[4], ((calloutState->integerRegisters))[5], ((calloutState->integerRegisters))[6], ((calloutState->integerRegisters))[7]);
  		x1Ret = returnX1value();
  	}
  	if ((((calloutState->structReturnSize)) > 0)
  	 && (((calloutState->structReturnSize)) <= (2 * BytesPerWord))) {
  
  		/* Only 2 regs used in ARMv8/Aarch64 current */
  		((calloutState->integerRegisters))[0] = intRet;
  		((calloutState->integerRegisters))[1] = x1Ret;
  	}
  	if (isCalleePopsConvention((calloutState->callFlags))) {
  		setsp((calloutState->argVector));
  	}
  	ownVM(myThreadIndex);
  	if (((calloutState->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) {
  
  		/* Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
  		   'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct. */
  		if (((calloutState->ffiRetHeader)) & FFIFlagPointer) {
  			/* begin ffiReturnPointer:ofType:in: */
  			specLiteral = (argArrayOrNil != null
  				? stackValue(1)
  				: literalofMethod(0, primitiveMethod()));
  			argTypes = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral);
  			retType = fetchPointerofObject(0, argTypes);
  			retClass = fetchPointerofObject(1, retType);
  			if (retClass == (nilObject())) {
  
  				/* Create ExternalData upon return */
  				/* begin atomicTypeOf: */
  				typeSpec1 = (calloutState->ffiRetHeader);
  				atomicType1 = ((usqInt) (typeSpec1 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  				if ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {
  
  					/* String return */
  					/* begin ffiReturnCStringFrom: */
  					cPointer = ((usqInt) intRet);
  					if (!(cPointer)) {
  						retOop = nilObject();
  						goto l5;
  					}
  					cString = ((char *) cPointer);
  					strLen = 0;
  					while (!((cString[strLen]) == 0)) {
  						strLen += 1;
  					}
  					strOop = instantiateClassindexableSize(classString(), strLen);
  					strPtr = firstIndexableField(strOop);
  					for (i1 = 0; i1 < strLen; i1 += 1) {
  						strPtr[i1] = (cString[i1]);
  					}
  					retOop = strOop;
  	l5:	/* end ffiReturnCStringFrom: */;
  					result = retOop;
  					goto l8;
  				}
  				
  #if SPURVM
  				oop2 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  				ptr1 = firstIndexableField(oop2);
  				ptr1[0] = (((sqInt) intRet));
  				retOop = instantiateClassindexableSize(classExternalData(), 0);
  				storePointerofObjectwithValue(0, retOop, oop2);
  
  #else /* SPURVM */
  				pushRemappableOop(retType);
  				oop2 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  				ptr1 = firstIndexableField(oop2);
  				ptr1[0] = (((sqInt) intRet));
  								pushRemappableOop(oop2);
  				retOop = instantiateClassindexableSize(classExternalData(), 0);
  				oop2 = popRemappableOop();
  				storePointerofObjectwithValue(0, retOop, oop2);
  				retType = popRemappableOop()
  #endif /* SPURVM */
  ;
  				storePointerofObjectwithValue(1, retOop, retType);
  				result = retOop;
  				goto l8;
  			}
  			classOop = (((calloutState->ffiRetHeader)) & FFIFlagStructure
  				? classByteArray()
  				: classExternalAddress());
  			
  #if SPURVM
  			oop2 = instantiateClassindexableSize(classOop, BytesPerWord);
  
  #else /* SPURVM */
  			pushRemappableOop(retClass);
  			oop2 = instantiateClassindexableSize(classOop, BytesPerWord);
  			retClass = popRemappableOop()
  #endif /* SPURVM */
  ;
  			ptr1 = firstIndexableField(oop2);
  			ptr1[0] = (((sqInt) intRet));
  			
  #if SPURVM
  			retOop = instantiateClassindexableSize(retClass, 0);
  
  #else /* SPURVM */
  			pushRemappableOop(oop2);
  			retOop = instantiateClassindexableSize(retClass, 0);
  			oop2 = popRemappableOop()
  #endif /* SPURVM */
  ;
  			storePointerofObjectwithValue(0, retOop, oop2);
  			result = retOop;
  			goto l8;
  		}
  		/* begin ffiReturnStruct:ofType:in: */
  		specLiteral1 = (argArrayOrNil != null
  			? stackValue(1)
  			: literalofMethod(0, primitiveMethod()));
  		argTypes1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral1);
  		ffiRetType = fetchPointerofObject(0, argTypes1);
  		retClass1 = fetchPointerofObject(1, ffiRetType);
  		retOop1 = instantiateClassindexableSize(retClass1, 0);
  		
  #if SPURVM
  		oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  
  #else /* SPURVM */
  		pushRemappableOop(retOop1);
  		oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  		retOop1 = popRemappableOop()
  #endif /* SPURVM */
  ;
  		memcpy(firstIndexableField(oop1), (((calloutState->structReturnSize)) <= (2 * BytesPerWord)
  			? (&((calloutState->integerRegisters)))
  			: (calloutState->limit)), (calloutState->structReturnSize));
  		storePointerofObjectwithValue(0, retOop1, oop1);
  		result = retOop1;
  		goto l8;
  	}
  	/* begin ffiCreateIntegralResultOop:ofAtomicType:in: */
  	assert(atomicType < FFITypeSingleFloat);
  	if (atomicType == FFITypeBool) {
  
  		/* Make sure bool honors the byte size requested */
  		byteSize = ((calloutState->ffiRetHeader)) & FFIStructSizeMask;
  		value = (byteSize == (sizeof(intRet))
  			? intRet
  			: intRet & (((((unsigned long long)1)) << (byteSize * 8)) - 1));
  		result = (value == 0
  			? falseObject()
  			: trueObject());
  		goto l8;
  	}
  	if (atomicType <= FFITypeSignedInt) {
  
  		/* these are all generall integer returns */
  		if (atomicType <= ((BytesPerWord == 8
  			? FFITypeSignedInt
  			: FFITypeSignedShort))) {
  
  			/* byte/short. first extract partial word, then sign extend */
  
  			/* # of significant bits */
  			shift = ((BytesPerWord == 8)
  			 && (atomicType >= FFITypeUnsignedInt)
  				? 32
  				: (((usqInt) atomicType) >> 1) * 8);
  			value = intRet & (((((unsigned long long)1)) << shift) - 1);
  			if (atomicType & 1) {
  
  				/* make the guy signed */
  				mask = (((unsigned long long)1)) << (shift - 1);
  				value = (value & (mask - 1)) - (value & mask);
  			}
  			result = integerObjectOf(value);
  			goto l8;
  		}
  		result = (atomicType & 1
  			? (BytesPerWord == 8
  					? signed64BitIntegerFor(intRet)
  					: signed32BitIntegerFor(intRet))
  			: (BytesPerWord == 8
  					? positive64BitIntegerFor(intRet)
  					: positive32BitIntegerFor(intRet)));
  		goto l8;
  	}
  	result = ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
  		? (atomicType & 1
  				? signed64BitIntegerFor(intRet)
  				: positive64BitIntegerFor(intRet))
  		: characterObjectOf(intRet & 0xFF));
  	l8:	/* end ffiCalloutTo:SpecOnStack:in: */;
  	/* begin cleanupCalloutState: */
  	while (((calloutState->stringArgIndex)) > 0) {
  		free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
  	}
  	popthenPush(primNumArgs + 1, result);
  	return result;
  }
  
  
  /*	Make sure we can return an object of the given type */
  
  	/* ThreadedFFIPlugin>>#ffiCheckReturn:With:in: */
  static sqInt
  ffiCheckReturnWithin(sqInt retSpec, sqInt retClass, CalloutState *calloutState)
  {
  	if (!(retClass == (nilObject()))) {
  		if (!(includesBehaviorThatOf(retClass, classExternalStructure()))) {
  			return FFIErrorBadReturn;
  		}
  	}
  	if (!((isWords(retSpec))
  		 && ((slotSizeOf(retSpec)) > 0))) {
  		return FFIErrorWrongType;
  	}
  	(calloutState->ffiRetHeader = fetchLong32ofObject(0, retSpec));
  	if (!(((calloutState->ffiRetHeader)) & FFIFlagAtomic)) {
  		if (retClass == (nilObject())) {
  			return FFIErrorBadReturn;
  		}
  	}
  	if ((((calloutState->ffiRetHeader)) & (FFIFlagPointer | FFIFlagStructure)) == FFIFlagStructure) {
  		(calloutState->structReturnSize = ((calloutState->ffiRetHeader)) & FFIStructSizeMask);
  	}
  	return 0;
  }
  
  
  /*	Make sure that the given oop is a valid external handle */
  
  	/* ThreadedFFIPlugin>>#ffiContentsOfHandle:errCode: */
  static sqInt
  ffiContentsOfHandleerrCode(sqInt oop, sqInt errCode)
  {
  	if (!((isBytes(oop))
  		 && ((byteSizeOf(oop)) == (sizeof(sqInt))))) {
  		return ffiFail(errCode);
  	}
  	return fetchPointerofObject(0, oop);
  }
  
  
  /*	Callout support. Return the appropriate oop for the given atomic type */
  
  	/* ThreadedFFIPlugin>>#ffiCreateIntegralResultOop:ofAtomicType:in: */
  static sqInt
  ffiCreateIntegralResultOopofAtomicTypein(usqLong retVal, sqInt atomicType, CalloutState *calloutState)
  {
      sqInt byteSize;
      usqLong mask;
      sqInt shift;
      usqLong value;
  
  	assert(atomicType < FFITypeSingleFloat);
  	if (atomicType == FFITypeBool) {
  
  		/* Make sure bool honors the byte size requested */
  		byteSize = ((calloutState->ffiRetHeader)) & FFIStructSizeMask;
  		value = (byteSize == (sizeof(retVal))
  			? retVal
  			: retVal & (((((unsigned long long)1)) << (byteSize * 8)) - 1));
  		return (value == 0
  			? falseObject()
  			: trueObject());
  	}
  	if (atomicType <= FFITypeSignedInt) {
  
  		/* these are all generall integer returns */
  		if (atomicType <= ((BytesPerWord == 8
  			? FFITypeSignedInt
  			: FFITypeSignedShort))) {
  
  			/* byte/short. first extract partial word, then sign extend */
  
  			/* # of significant bits */
  			shift = ((BytesPerWord == 8)
  			 && (atomicType >= FFITypeUnsignedInt)
  				? 32
  				: (((usqInt) atomicType) >> 1) * 8);
  			value = retVal & (((((unsigned long long)1)) << shift) - 1);
  			if (atomicType & 1) {
  
  				/* make the guy signed */
  				mask = (((unsigned long long)1)) << (shift - 1);
  				value = (value & (mask - 1)) - (value & mask);
  			}
  			return integerObjectOf(value);
  		}
  		return (atomicType & 1
  			? (BytesPerWord == 8
  					? signed64BitIntegerFor(retVal)
  					: signed32BitIntegerFor(retVal))
  			: (BytesPerWord == 8
  					? positive64BitIntegerFor(retVal)
  					: positive32BitIntegerFor(retVal)));
  	}
  	return ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
  		? (atomicType & 1
  				? signed64BitIntegerFor(retVal)
  				: positive64BitIntegerFor(retVal))
  		: characterObjectOf(retVal & 0xFF));
  }
  
  
  /*	Map the FFI error code into a primitive error code. If reason is negative
  	it encodes one of the
  	standard PrimErr... codes, negated to distinguish it from the FFIError
  	codes. If it is an FFIError...
  	code then add the size of the primitive error table + 2 to disambiguate it
  	from the PrimErr... codes.
  	For historic reasons the FFIError codes range from -1 on up hence adding
  	size + 2 maps them to
  	size of table + 1 on up. This OFFSET IS undone by ExternalFunction
  	class>>externalCallFailedWith:. Thus we can communicate back both
  	PrimErr.. and FFIError codes. Complex but necessary. */
  
  	/* ThreadedFFIPlugin>>#ffiFail: */
  static sqInt
  ffiFail(sqInt reason)
  {
  	ffiLastError = reason;
  	return primitiveFailFor((reason >= FFINoCalloutAvailable
  		? (reason + 2) + (slotSizeOf(primitiveErrorTable()))
  		: -reason));
  }
  
  
  /*	Support for generic callout. Return a float value that is coerced as C
  	would do.
   */
  
  	/* ThreadedFFIPlugin>>#ffiFloatValueOf: */
  static double
  ffiFloatValueOf(sqInt oop)
  {
  	if (isFloatObject(oop)) {
  		return floatValueOf(oop);
  	}
  	return ((double) (ffiIntegerValueOf(oop)) );
  }
  
  
  /*	Support for generic callout. Answer an integer value that is coerced as C
  	would do.
   */
  /*	Cheat with a tag test */
  
  	/* ThreadedFFIPlugin>>#ffiIntegerValueOf: */
  static sqInt
  ffiIntegerValueOf(sqInt oop)
  {
  	if (oop & (BytesPerWord - 1)) {
  		if (isIntegerObject(oop)) {
  			return integerValueOf(oop);
  		}
  		
  #    if SPURVM
  		if (isCharacterObject(oop)) {
  
  			/* Immediate in Spur */
  			return characterValueOf(oop);
  		}
  		if (isFloatObject(oop)) {
  
  			/* Immediate in 64-bit Spur */
  			return floatValueOf(oop);
  		}
  #    endif /* SPURVM */
  	}
  	else {
  		
  #    if SPURVM
  
  		/* No non-immediate characters in Spur */
  #    else /* SPURVM */
  		if (isCharacterObject(oop)) {
  			return characterValueOf(oop);
  		}
  #    endif /* SPURVM */
  		if (isFloatObject(oop)) {
  			return floatValueOf(oop);
  		}
  		if (oop == (nilObject())) {
  			return 0;
  		}
  		if (oop == (falseObject())) {
  			return 0;
  		}
  		if (oop == (trueObject())) {
  			return 1;
  		}
  		if (isLargePositiveIntegerObject(oop)) {
  			
  #      if BytesPerWord == 8
  
  			/* Use cppIf: to get the return type of the function right.  Should be sqInt on 32-bits. */
  			return positive64BitValueOf(oop);
  #      else /* BytesPerWord == 8 */
  			return positive32BitValueOf(oop);
  #      endif /* BytesPerWord == 8 */
  		}
  	}
  	return signedMachineIntegerValueOf(oop);
  }
  
  
  /*	Load the function address for a call out to an external function */
  
  	/* ThreadedFFIPlugin>>#ffiLoadCalloutAddressFrom: */
  static sqInt
  ffiLoadCalloutAddressFrom(sqInt oop)
  {
      sqInt address;
      sqInt functionName;
      sqInt module;
      sqInt moduleHandle;
  
  
  	/* First find and load the module */
  	module = fetchPointerofObject(externalFunctionInstSize + 1, oop);
  	moduleHandle = ffiLoadCalloutModule(module);
  	if (failed()) {
  		return 0;
  	}
  	functionName = fetchPointerofObject(externalFunctionInstSize, oop);
  	if (!(isBytes(functionName))) {
  		return ffiFail(FFIErrorBadExternalFunction);
  	}
  	address = ((sqInt)(ioLoadSymbolOfLengthFromModule(((sqInt)(firstIndexableField(functionName))), byteSizeOf(functionName), moduleHandle)));
  	if ((failed())
  	 || (address == 0)) {
  		return ffiFail(FFIErrorAddressNotFound);
  	}
  	return address;
  }
  
  
  /*	Load the address of the foreign function from the given object */
  
  	/* ThreadedFFIPlugin>>#ffiLoadCalloutAddress: */
  static sqInt
  ffiLoadCalloutAddress(sqInt lit)
  {
      sqInt address;
      sqInt addressPtr;
      sqIntptr_t *ptr;
  
  
  	/* Lookup the address */
  
  	/* Make sure it's an external handle */
  	addressPtr = fetchPointerofObject(0, lit);
  	/* begin ffiContentsOfHandle:errCode: */
  	if (!((isBytes(addressPtr))
  		 && ((byteSizeOf(addressPtr)) == (sizeof(sqInt))))) {
  		address = ffiFail(FFIErrorBadAddress);
  		goto l1;
  	}
  	address = fetchPointerofObject(0, addressPtr);
  	l1:	/* end ffiContentsOfHandle:errCode: */;
  	if (failed()) {
  		return 0;
  	}
  	if (address == 0) {
  
  		/* Go look it up in the module */
  		if (externalFunctionInstSize > ExternalFunctionStackSizeIndex) {
  			storePointerofObjectwithValue(ExternalFunctionStackSizeIndex, lit, integerObjectOf(-1));
  		}
  		if ((slotSizeOf(lit)) < 5) {
  			return ffiFail(FFIErrorNoModule);
  		}
  		address = ffiLoadCalloutAddressFrom(lit);
  		if (failed()) {
  			return 0;
  		}
  		ptr = firstIndexableField(addressPtr);
  		ptr[0] = address;
  	}
  	return address;
  }
  
  
  /*	Load the given module and return its handle */
  
  	/* ThreadedFFIPlugin>>#ffiLoadCalloutModule: */
  static sqInt
  ffiLoadCalloutModule(sqInt module)
  {
      sqInt ffiModuleName;
      sqInt moduleHandle;
      sqInt moduleHandlePtr;
      sqInt moduleLength;
      sqInt *ptr;
      sqInt rcvr;
  
  	if (isBytes(module)) {
  
  		/* plain module name */
  		ffiModuleName = module;
  		moduleLength = byteSizeOf(ffiModuleName);
  		moduleHandle = ((sqInt)(ioLoadModuleOfLength(((sqInt)(firstIndexableField(ffiModuleName))), moduleLength)));
  		if ((failed())
  		 || (moduleHandle == 0)) {
  			return ffiFail(FFIErrorModuleNotFound);
  		}
  		return moduleHandle;
  	}
  	rcvr = stackValue(methodArgumentCount());
  	if (!(isKindOfClass(rcvr, classExternalLibrary()))) {
  		return ffiFail(FFIErrorNoModule);
  	}
  	moduleHandlePtr = fetchPointerofObject(0, rcvr);
  	/* begin ffiContentsOfHandle:errCode: */
  	if (!((isBytes(moduleHandlePtr))
  		 && ((byteSizeOf(moduleHandlePtr)) == (sizeof(sqInt))))) {
  		moduleHandle = ffiFail(FFIErrorBadExternalLibrary);
  		goto l1;
  	}
  	moduleHandle = fetchPointerofObject(0, moduleHandlePtr);
  	l1:	/* end ffiContentsOfHandle:errCode: */;
  	if (failed()) {
  		return 0;
  	}
  	if (moduleHandle == 0) {
  
  		/* need to reload module */
  		ffiModuleName = fetchPointerofObject(1, rcvr);
  		if (!(isBytes(ffiModuleName))) {
  			return ffiFail(FFIErrorBadExternalLibrary);
  		}
  		moduleLength = byteSizeOf(ffiModuleName);
  		moduleHandle = ((sqInt)(ioLoadModuleOfLength(((sqInt)(firstIndexableField(ffiModuleName))), moduleLength)));
  		if ((failed())
  		 || (moduleHandle == 0)) {
  			return ffiFail(FFIErrorModuleNotFound);
  		}
  		ptr = firstIndexableField(moduleHandlePtr);
  		ptr[0] = moduleHandle;
  	}
  	return moduleHandle;
  }
  
  
  /*	fetch the function name */
  
  	/* ThreadedFFIPlugin>>#ffiLogCallout: */
  static void
  ffiLogCallout(sqInt lit)
  {
      sqInt functionName;
  
  	if (ffiLogEnabled) {
  		functionName = fetchPointerofObject(externalFunctionInstSize, lit);
  		if (!(isBytes(functionName))) {
  			return;
  		}
  		ffiLogCallOfLength(firstIndexableField(functionName), byteSizeOf(functionName));
  	}
  }
  
  
  /*	This is a special entry point exposed such that client code can 
  	enable and disable logging of FFI calls. */
  
  	/* ThreadedFFIPlugin>>#ffiLogCallsTo: */
  EXPORT(sqInt)
  ffiLogCallsTo(char *fileName)
  {
  	return 1;
  }
  
  
  /*	Push the contents of the given external structure */
  
  	/* ThreadedFFIPlugin>>#ffiPushPointerContentsOf:in: */
  static sqInt
  ffiPushPointerContentsOfin(sqInt oop, CalloutState *calloutState)
  {
      void * ptrAddress;
      sqInt ptrClass;
  
  	ptrClass = fetchClassOf(oop);
  	if (ptrClass == (classExternalAddress())) {
  
  		/* Don't you dare to pass pointers into object memory */
  		ptrAddress = ((void *)(fetchPointerofObject(0, oop)));
  		if (isInMemory(ptrAddress)) {
  			return FFIErrorInvalidPointer;
  		}
  		/* begin ffiPushPointer:in: */
  		if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  			((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
  			(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  		}
  		else {
  			if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  				return FFIErrorCallFrameTooBig;
  			}
  			longAtput((calloutState->currentArg), ptrAddress);
  			(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  		}
  		return 0;
  	}
  	if (ptrClass == (classByteArray())) {
  
  		/* Since this involves passing the address of the first indexable field we need to fail
  		   the call if it is threaded and the object is young, since it may move during the call. */
  		
  #    if COGMTVM
  		if ((((calloutState->callFlags)) & FFICallFlagThreaded)
  		 && (isYoung(oop))) {
  			return -PrimErrObjectMayMove;
  		}
  #    endif /* COGMTVM */
  		ptrAddress = firstIndexableField(oop);
  		/* begin ffiPushPointer:in: */
  		if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  			((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
  			(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  		}
  		else {
  			if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  				return FFIErrorCallFrameTooBig;
  			}
  			longAtput((calloutState->currentArg), ptrAddress);
  			(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  		}
  		return 0;
  	}
  	if (includesBehaviorThatOf(ptrClass, classAlien())) {
  		
  #    if COGMTVM
  		if ((((calloutState->callFlags)) & FFICallFlagThreaded)
  		 && (((assert(isAlien(oop)),
  		(longAt(oop + BaseHeaderSize)) > 0))
  		 && (isYoung(oop)))) {
  			return -PrimErrObjectMayMove;
  		}
  #    endif /* COGMTVM */
  		ptrAddress = ((longAt(oop + BaseHeaderSize)) > 0
  			? (oop + BaseHeaderSize) + BytesPerOop
  			: longAt((oop + BaseHeaderSize) + BytesPerOop));
  		/* begin ffiPushPointer:in: */
  		if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  			((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
  			(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  		}
  		else {
  			if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  				return FFIErrorCallFrameTooBig;
  			}
  			longAtput((calloutState->currentArg), ptrAddress);
  			(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  		}
  		return 0;
  	}
  	return FFIErrorBadArg;
  }
  
  	/* ThreadedARM32FFIPlugin>>#ffiPushPointer:in: */
  static sqInt
  ffiPushPointerin(void *pointer, CalloutState *calloutState)
  {
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), pointer);
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  	/* ThreadedARM32FFIPlugin>>#ffiPushSignedByte:in: */
  static sqInt
  ffiPushSignedBytein(sqInt value, CalloutState *calloutState)
  {
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((signed char) value));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), ((signed char) value));
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  	/* ThreadedARM32FFIPlugin>>#ffiPushSignedChar:in: */
  static sqInt
  ffiPushSignedCharin(sqInt value, CalloutState *calloutState)
  {
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((signed char) value));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), ((signed char) value));
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  	/* ThreadedARM64FFIPlugin>>#ffiPushSignedInt:in: */
  static sqInt
  ffiPushSignedIntin(sqInt value, CalloutState *calloutState)
  {
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqLong) value));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), value);
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  
  /*	Push a longlong type (e.g., a 64bit integer).
  	Note: Coercions from float are *not* supported. */
  
  	/* ThreadedFFIPlugin>>#ffiPushSignedLongLongOop:in: */
  static sqInt
  ffiPushSignedLongLongOopin(sqInt oop, CalloutState *calloutState)
  {
      sqLong value;
  
  	if ((oop == (nilObject()))
  	 || (oop == (falseObject()))) {
  		value = 0;
  	}
  	else {
  		if (oop == (trueObject())) {
  			value = 1;
  		}
  		else {
  			value = signed64BitValueOf(oop);
  			if (failed()) {
  				return FFIErrorCoercionFailed;
  			}
  		}
  	}
  	/* begin ffiPushSignedLongLong:in: */
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqLong) value));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), value);
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  	/* ThreadedARM64FFIPlugin>>#ffiPushSignedLongLong:in: */
  static sqInt
  ffiPushSignedLongLongin(sqLong value, CalloutState *calloutState)
  {
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqLong) value));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), value);
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  	/* ThreadedARM32FFIPlugin>>#ffiPushSignedShort:in: */
  static sqInt
  ffiPushSignedShortin(sqInt value, CalloutState *calloutState)
  {
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((signed short) value));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), ((signed short) value));
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  	/* ThreadedFFIPlugin>>#ffiPushString:OfLength:in: */
  static sqInt
  ffiPushStringOfLengthin(char *pointer, sqInt length, CalloutState *calloutState)
  {
      char *copy;
  
  	if (((calloutState->stringArgIndex)) >= MaxNumArgs) {
  		return -PrimErrBadNumArgs;
  	}
  	copy = malloc(length + 1);
  	if (copy == null) {
  		return -PrimErrNoCMemory;
  	}
  	memcpy(copy, pointer, length);
  	copy[length] = 0;
  	((calloutState->stringArgs))[(calloutState->stringArgIndex)] = copy;
  	(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) + 1);
  	/* begin ffiPushPointer:in: */
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)copy));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), copy);
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  
  /*	Push the contents of the given external structure */
  
  	/* ThreadedFFIPlugin>>#ffiPushStructureContentsOf:in: */
  static sqInt
  ffiPushStructureContentsOfin(sqInt oop, CalloutState *calloutState)
  {
      sqInt *argSpec;
      sqInt *argSpec1;
      sqInt argSpecSize;
      sqInt argSpecSize1;
      sqInt availableRegisterSpace;
      sqInt availableRegisterSpace1;
      void * ptrAddress;
      sqInt ptrClass;
      sqInt roundedSize;
      sqInt roundedSize1;
      sqInt stackPartSize;
      sqInt stackPartSize1;
      sqInt structSize;
      sqInt structSize1;
  
  	ptrClass = fetchClassOf(oop);
  	if (ptrClass == (classExternalAddress())) {
  
  		/* ExternalAddress is bytes */
  
  		/* There is no way we can make sure the structure is valid.
  		   But we can at least check for attempts to pass pointers to ST memory. */
  		ptrAddress = ((void *)(fetchPointerofObject(0, oop)));
  		if (isInMemory(ptrAddress)) {
  			return FFIErrorInvalidPointer;
  		}
  		/* begin ffiPushStructure:ofSize:typeSpec:ofLength:in: */
  		structSize = ((calloutState->ffiArgHeader)) & FFIStructSizeMask;
  		argSpec = (calloutState->ffiArgSpec);
  		argSpecSize = (calloutState->ffiArgSpecSize);
  		availableRegisterSpace = (NumIntRegArgs - ((calloutState->integerRegisterIndex))) * BytesPerWord;
  		stackPartSize = structSize;
  		if (availableRegisterSpace > 0) {
  			if (structSize <= availableRegisterSpace) {
  
  				/* all in registers */
  				stackPartSize = 0;
  				memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ptrAddress, structSize);
  				(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + (((usqInt) (structSize + 3) >> 3)));
  			}
  			else {
  
  				/* If no previous co-processor candidate arg has already been pushed on the stack, then split the struct between registers and stack.
  				   Otherwise push entire struct on stack. */
  				if (((calloutState->currentArg)) == ((calloutState->argVector))) {
  					stackPartSize = structSize - availableRegisterSpace;
  					memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ptrAddress, availableRegisterSpace);
  				}
  				else {
  					availableRegisterSpace = 0;
  				}
  				(calloutState->integerRegisterIndex = NumIntRegArgs);
  			}
  		}
  		if (stackPartSize > 0) {
  			roundedSize = (((stackPartSize + 3) | 3) - 3);
  			if ((((calloutState->currentArg)) + roundedSize) > ((calloutState->limit))) {
  				return FFIErrorCallFrameTooBig;
  			}
  			memcpy((calloutState->currentArg), (&((((char *) ptrAddress))[availableRegisterSpace])), stackPartSize);
  			(calloutState->currentArg = ((calloutState->currentArg)) + roundedSize);
  		}
  		return 0;
  	}
  	if (ptrClass == (classByteArray())) {
  
  		/* The following is a somewhat pessimistic test but I like being sure... */
  		if (!((byteSizeOf(oop)) == (((calloutState->ffiArgHeader)) & FFIStructSizeMask))) {
  			return FFIErrorStructSize;
  		}
  		ptrAddress = firstIndexableField(oop);
  		if (!(((calloutState->ffiArgHeader)) & FFIFlagPointer)) {
  
  			/* Since this involves passing the address of the first indexable field we need to fail
  			   the call if it is threaded and the object is young, since it may move during the call. */
  			
  #      if COGMTVM
  			if ((((calloutState->callFlags)) & FFICallFlagThreaded)
  			 && (isYoung(oop))) {
  				return -PrimErrObjectMayMove;
  			}
  #      endif /* COGMTVM */
  			/* begin ffiPushStructure:ofSize:typeSpec:ofLength:in: */
  			structSize1 = ((calloutState->ffiArgHeader)) & FFIStructSizeMask;
  			argSpec1 = (calloutState->ffiArgSpec);
  			argSpecSize1 = (calloutState->ffiArgSpecSize);
  			availableRegisterSpace1 = (NumIntRegArgs - ((calloutState->integerRegisterIndex))) * BytesPerWord;
  			stackPartSize1 = structSize1;
  			if (availableRegisterSpace1 > 0) {
  				if (structSize1 <= availableRegisterSpace1) {
  
  					/* all in registers */
  					stackPartSize1 = 0;
  					memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ptrAddress, structSize1);
  					(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + (((usqInt) (structSize1 + 3) >> 3)));
  				}
  				else {
  
  					/* If no previous co-processor candidate arg has already been pushed on the stack, then split the struct between registers and stack.
  					   Otherwise push entire struct on stack. */
  					if (((calloutState->currentArg)) == ((calloutState->argVector))) {
  						stackPartSize1 = structSize1 - availableRegisterSpace1;
  						memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ptrAddress, availableRegisterSpace1);
  					}
  					else {
  						availableRegisterSpace1 = 0;
  					}
  					(calloutState->integerRegisterIndex = NumIntRegArgs);
  				}
  			}
  			if (stackPartSize1 > 0) {
  				roundedSize1 = (((stackPartSize1 + 3) | 3) - 3);
  				if ((((calloutState->currentArg)) + roundedSize1) > ((calloutState->limit))) {
  					return FFIErrorCallFrameTooBig;
  				}
  				memcpy((calloutState->currentArg), (&((((char *) ptrAddress))[availableRegisterSpace1])), stackPartSize1);
  				(calloutState->currentArg = ((calloutState->currentArg)) + roundedSize1);
  			}
  			return 0;
  		}
  		if (!((((calloutState->ffiArgHeader)) & FFIStructSizeMask) == BytesPerWord)) {
  			return FFIErrorStructSize;
  		}
  		ptrAddress = ((void *)(fetchPointerofObject(0, oop)));
  		if (isInMemory(ptrAddress)) {
  			return FFIErrorInvalidPointer;
  		}
  		/* begin ffiPushPointer:in: */
  		if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  			((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
  			(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  		}
  		else {
  			if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  				return FFIErrorCallFrameTooBig;
  			}
  			longAtput((calloutState->currentArg), ptrAddress);
  			(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  		}
  		return 0;
  	}
  	return FFIErrorBadArg;
  }
  
  	/* ThreadedARM64FFIPlugin>>#ffiPushStructure:ofSize:typeSpec:ofLength:in: */
  static sqInt
  ffiPushStructureofSizetypeSpecofLengthin(void *pointer, sqInt structSize, sqInt *argSpec, sqInt argSpecSize, CalloutState *calloutState)
  {
      sqInt availableRegisterSpace;
      sqInt roundedSize;
      sqInt stackPartSize;
  
  	availableRegisterSpace = (NumIntRegArgs - ((calloutState->integerRegisterIndex))) * BytesPerWord;
  	stackPartSize = structSize;
  	if (availableRegisterSpace > 0) {
  		if (structSize <= availableRegisterSpace) {
  
  			/* all in registers */
  			stackPartSize = 0;
  			memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), pointer, structSize);
  			(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + (((usqInt) (structSize + 3) >> 3)));
  		}
  		else {
  
  			/* If no previous co-processor candidate arg has already been pushed on the stack, then split the struct between registers and stack.
  			   Otherwise push entire struct on stack. */
  			if (((calloutState->currentArg)) == ((calloutState->argVector))) {
  				stackPartSize = structSize - availableRegisterSpace;
  				memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), pointer, availableRegisterSpace);
  			}
  			else {
  				availableRegisterSpace = 0;
  			}
  			(calloutState->integerRegisterIndex = NumIntRegArgs);
  		}
  	}
  	if (stackPartSize > 0) {
  		roundedSize = (((stackPartSize + 3) | 3) - 3);
  		if ((((calloutState->currentArg)) + roundedSize) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		memcpy((calloutState->currentArg), (&((((char *) pointer))[availableRegisterSpace])), stackPartSize);
  		(calloutState->currentArg = ((calloutState->currentArg)) + roundedSize);
  	}
  	return 0;
  }
  
  	/* ThreadedARM32FFIPlugin>>#ffiPushUnsignedByte:in: */
  static sqInt
  ffiPushUnsignedBytein(sqInt value, CalloutState *calloutState)
  {
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((unsigned char) value));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), ((unsigned char) value));
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  	/* ThreadedARM32FFIPlugin>>#ffiPushUnsignedChar:in: */
  static sqInt
  ffiPushUnsignedCharin(sqInt value, CalloutState *calloutState)
  {
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((unsigned char) value));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), ((unsigned char) value));
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  	/* ThreadedARM64FFIPlugin>>#ffiPushUnsignedInt:in: */
  static sqInt
  ffiPushUnsignedIntin(sqInt value, CalloutState *calloutState)
  {
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((usqLong) value));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), value);
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  
  /*	Push an unsigned longlong type (e.g., a 64bit integer).
  	Note: Coercions from float are *not* supported. */
  
  	/* ThreadedFFIPlugin>>#ffiPushUnsignedLongLongOop:in: */
  static sqInt
  ffiPushUnsignedLongLongOopin(sqInt oop, CalloutState *calloutState)
  {
      usqLong value;
  
  	if ((oop == (nilObject()))
  	 || (oop == (falseObject()))) {
  		value = 0;
  	}
  	else {
  		if (oop == (trueObject())) {
  			value = 1;
  		}
  		else {
  			value = positive64BitValueOf(oop);
  			if (failed()) {
  				return FFIErrorCoercionFailed;
  			}
  		}
  	}
  	/* begin ffiPushUnsignedLongLong:in: */
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((usqLong) value));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), value);
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  	/* ThreadedARM64FFIPlugin>>#ffiPushUnsignedLongLong:in: */
  static sqInt
  ffiPushUnsignedLongLongin(usqLong value, CalloutState *calloutState)
  {
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((usqLong) value));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), value);
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  	/* ThreadedARM32FFIPlugin>>#ffiPushUnsignedShort:in: */
  static sqInt
  ffiPushUnsignedShortin(sqInt value, CalloutState *calloutState)
  {
  	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
  		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((unsigned short) value));
  		(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1);
  	}
  	else {
  		if ((((calloutState->currentArg)) + BytesPerWord) > ((calloutState->limit))) {
  			return FFIErrorCallFrameTooBig;
  		}
  		longAtput((calloutState->currentArg), ((unsigned short) value));
  		(calloutState->currentArg = ((calloutState->currentArg)) + BytesPerWord);
  	}
  	return 0;
  }
  
  
  /*	This is a fallback in case somebody tries to pass a 'void' value.
  	We could simply ignore the argument but I think it's better to let
  	the caller know what he did */
  
  	/* ThreadedFFIPlugin>>#ffiPushVoid:in: */
  static sqInt
  ffiPushVoidin(sqInt ignored, CalloutState *calloutState)
  {
  	return FFIErrorAttemptToPassVoid;
  }
  
  
  /*	Create a Smalltalk string from a zero terminated C string */
  
  	/* ThreadedFFIPlugin>>#ffiReturnCStringFrom: */
  static sqInt
  ffiReturnCStringFrom(sqInt cPointer)
  {
      char *cString;
      sqInt i;
      sqInt strLen;
      sqInt strOop;
      char *strPtr;
  
  	if (!(cPointer)) {
  		return nilObject();
  	}
  	cString = ((char *) cPointer);
  	strLen = 0;
  	while (!((cString[strLen]) == 0)) {
  		strLen += 1;
  	}
  	strOop = instantiateClassindexableSize(classString(), strLen);
  	strPtr = firstIndexableField(strOop);
  	for (i = 0; i < strLen; i += 1) {
  		strPtr[i] = (cString[i]);
  	}
  	return strOop;
  }
  
  
  /*	Generic callout support. Create a pointer return value from an external
  	function call
   */
  
  	/* ThreadedFFIPlugin>>#ffiReturnPointer:ofType:in: */
  static sqInt
  ffiReturnPointerofTypein(usqLong retVal, sqInt retType, CalloutState *calloutState)
  {
      sqInt atomicType;
      sqInt classOop;
      sqInt cPointer;
      char *cString;
      sqInt i;
      sqInt oop;
      sqInt *ptr;
      sqInt retClass;
      sqInt retOop;
      sqInt strLen;
      sqInt strOop;
      char *strPtr;
      sqInt typeSpec;
  
  	retClass = fetchPointerofObject(1, retType);
  	if (retClass == (nilObject())) {
  
  		/* Create ExternalData upon return */
  		/* begin atomicTypeOf: */
  		typeSpec = (calloutState->ffiRetHeader);
  		atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  		if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {
  
  			/* String return */
  			/* begin ffiReturnCStringFrom: */
  			cPointer = ((usqInt) retVal);
  			if (!(cPointer)) {
  				retOop = nilObject();
  				goto l1;
  			}
  			cString = ((char *) cPointer);
  			strLen = 0;
  			while (!((cString[strLen]) == 0)) {
  				strLen += 1;
  			}
  			strOop = instantiateClassindexableSize(classString(), strLen);
  			strPtr = firstIndexableField(strOop);
  			for (i = 0; i < strLen; i += 1) {
  				strPtr[i] = (cString[i]);
  			}
  			retOop = strOop;
  	l1:	/* end ffiReturnCStringFrom: */;
  			return retOop;
  		}
  		
  #if SPURVM
  		oop = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  		ptr = firstIndexableField(oop);
  		ptr[0] = (((sqInt) retVal));
  		retOop = instantiateClassindexableSize(classExternalData(), 0);
  		storePointerofObjectwithValue(0, retOop, oop);
  
  #else /* SPURVM */
  		pushRemappableOop(retType);
  		oop = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  		ptr = firstIndexableField(oop);
  		ptr[0] = (((sqInt) retVal));
  				pushRemappableOop(oop);
  		retOop = instantiateClassindexableSize(classExternalData(), 0);
  		oop = popRemappableOop();
  		storePointerofObjectwithValue(0, retOop, oop);
  		retType = popRemappableOop()
  #endif /* SPURVM */
  ;
  		storePointerofObjectwithValue(1, retOop, retType);
  		return retOop;
  	}
  	classOop = (((calloutState->ffiRetHeader)) & FFIFlagStructure
  		? classByteArray()
  		: classExternalAddress());
  	
  #if SPURVM
  	oop = instantiateClassindexableSize(classOop, BytesPerWord);
  
  #else /* SPURVM */
  	pushRemappableOop(retClass);
  	oop = instantiateClassindexableSize(classOop, BytesPerWord);
  	retClass = popRemappableOop()
  #endif /* SPURVM */
  ;
  	ptr = firstIndexableField(oop);
  	ptr[0] = (((sqInt) retVal));
  	
  #if SPURVM
  	retOop = instantiateClassindexableSize(retClass, 0);
  
  #else /* SPURVM */
  	pushRemappableOop(oop);
  	retOop = instantiateClassindexableSize(retClass, 0);
  	oop = popRemappableOop()
  #endif /* SPURVM */
  ;
  	storePointerofObjectwithValue(0, retOop, oop);
  	return retOop;
  }
  
  
  /*	Create a structure return value from an external function call. The value
  	has been stored in
  	alloca'ed space pointed to by the calloutState or in the return value. */
  
  	/* ThreadedARM64FFIPlugin>>#ffiReturnStruct:ofType:in: */
  static sqInt
  ffiReturnStructofTypein(usqLong longLongRet, sqInt ffiRetType, CalloutState *calloutState)
  {
      sqInt oop;
      sqInt retClass;
      sqInt retOop;
  
  	retClass = fetchPointerofObject(1, ffiRetType);
  	retOop = instantiateClassindexableSize(retClass, 0);
  	
  #if SPURVM
  	oop = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  
  #else /* SPURVM */
  	pushRemappableOop(retOop);
  	oop = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  	retOop = popRemappableOop()
  #endif /* SPURVM */
  ;
  	memcpy(firstIndexableField(oop), (((calloutState->structReturnSize)) <= (2 * BytesPerWord)
  		? (&((calloutState->integerRegisters)))
  		: (calloutState->limit)), (calloutState->structReturnSize));
  	storePointerofObjectwithValue(0, retOop, oop);
  	return retOop;
  }
  
  
  /*	Answer the return type object for the current invocation */
  
  	/* ThreadedFFIPlugin>>#ffiReturnType: */
  static sqInt
  ffiReturnType(sqInt specOnStack)
  {
      sqInt argTypes;
      sqInt specLiteral;
  
  	specLiteral = (specOnStack
  		? stackValue(1)
  		: literalofMethod(0, primitiveMethod()));
  	argTypes = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral);
  	return fetchPointerofObject(0, argTypes);
  }
  
  
  /*	Check that the calling convention is valid. This test also filters out
  	attempts to do a threaded call in the non-threaded VM/plugin combinatioin. */
  
  	/* ThreadedFFIPlugin>>#ffiSupportsCallingConvention: */
  static sqInt
  ffiSupportsCallingConvention(sqInt aCallingConvention)
  {
  	return (aCallingConvention == FFICallTypeCDecl)
  	 || (aCallingConvention == FFICallTypeApi);
  }
  
  
  /*	Validate if the given oop (an instance of ExternalData) can be passed as a
  	pointer to the given atomic type.
   */
  
  	/* ThreadedFFIPlugin>>#ffiValidateExternalData:AtomicType: */
  static sqInt
  ffiValidateExternalDataAtomicType(sqInt oop, sqInt atomicType)
  {
      sqInt ptrType;
      sqInt spec;
      sqInt specOop;
      sqInt specType;
  
  	ptrType = fetchPointerofObject(1, oop);
  	if (!((isPointers(ptrType))
  		 && ((slotSizeOf(ptrType)) >= 2))) {
  		return FFIErrorWrongType;
  	}
  	specOop = fetchPointerofObject(0, ptrType);
  	if (!((isWords(specOop))
  		 && ((slotSizeOf(specOop)) > 0))) {
  		return FFIErrorWrongType;
  	}
  	spec = fetchPointerofObject(0, specOop);
  	if (!(spec & FFIFlagAtomic)) {
  		return FFIErrorWrongType;
  	}
  	/* begin atomicTypeOf: */
  	specType = ((usqInt) (spec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  	if (specType != atomicType) {
  
  		/* Allow for signed/unsigned conversion but nothing else.
  		   See FFIConstants class>>#initializeTypeConstants */
  		if (!((atomicType >= FFITypeUnsignedByte)
  			 && ((atomicType <= FFITypeSignedChar)
  			 && ((((usqInt) atomicType) >> 1) == (((usqInt) specType) >> 1))))) {
  			return FFIErrorCoercionFailed;
  		}
  	}
  	return 0;
  }
  
  
  /*	Note: This is hardcoded so it can be run from Squeak.
  	The module name is used for validating a module *after*
  	it is loaded to check if it does really contain the module
  	we're thinking it contains. This is important! */
  
  	/* ThreadedFFIPlugin>>#getModuleName */
  EXPORT(const char *)
  getModuleName(void)
  {
  	return "SqueakFFIPrims";
  }
  
  	/* ThreadedARM64FFIPlugin>>#getX1register */
  static sqInt
  getX1register(void)
  {
      extern sqLong returnX1value();
  
  	return returnX1value();
  }
  
  	/* ThreadedFFIPlugin>>#initialiseModule */
  EXPORT(sqInt)
  initialiseModule(void)
  {
  
  	/* By default, disable logging */
  	ffiLastError = 0;
  
  	/* Get the instSize of ExternalFunction to know whether it contains a cache of the stackSize,
  	   and what the offset of ExternalLibraryFunction's functionName and moduleName slots are. */
  	ffiLogEnabled = 0;
  	externalFunctionInstSize = instanceSizeOf(classExternalFunction());
  	initSurfacePluginFunctionPointers();
  	return 1;
  }
  
  	/* ThreadedFFIPlugin>>#isAlien: */
  static sqInt
  isAlien(sqInt anOop)
  {
  	return includesBehaviorThatOf(fetchClassOf(anOop), classAlien());
  }
  
  	/* ThreadedFFIPlugin>>#isAtomicType: */
  static sqInt
  isAtomicType(sqInt typeSpec)
  {
  	return typeSpec & FFIFlagAtomic;
  }
  
  	/* ThreadedFFIPlugin>>#isDirectAlien: */
  static sqInt
  isDirectAlien(sqInt oop)
  {
  	assert(isAlien(oop));
  	return (longAt(oop + BaseHeaderSize)) > 0;
  }
  
  	/* ThreadedFFIPlugin>>#msg: */
  static sqInt
  msg(char *s)
  {
  	logDebug("\n%s: %s", getModuleName(), s);
  	return 0;
  }
  
  
  /*	Answer if a struct result of a given size is unable to be returned in
  	registers. 
   */
  
  	/* ThreadedARM64FFIPlugin>>#mustReturnStructOnStack: */
  static sqInt
  mustReturnStructOnStack(sqInt returnStructSize)
  {
  	return returnStructSize > (2 * BytesPerWord);
  }
  
  
  /*	Answer if a struct returned in memory is returned to the
  	referent of a pointer passed as an implciit first argument.
  	It almost always is. Subclasses can override if not. */
  
  	/* ThreadedARM64FFIPlugin>>#nonRegisterStructReturnIsViaImplicitFirstArgument */
  static sqInt
  nonRegisterStructReturnIsViaImplicitFirstArgument(void)
  {
  	return 0;
  }
  
  
  /*	IMPORTANT: IF YOU CHANGE THE NAME OF THIS METHOD YOU MUST CHANGE
  	Interpreter>>primitiveCalloutToFFI
  	TO REFLECT THE CHANGE. */
  /*	Perform a function call to a foreign function.
  	Only invoked from method containing explicit external call spec. */
  
  	/* ThreadedFFIPlugin>>#primitiveCallout */
  EXPORT(void)
  primitiveCallout(void)
  {
      sqInt address;
      sqInt address1;
      sqInt address11;
      sqInt address2;
      sqInt addressPtr;
      sqInt addressPtr1;
      char *allocation;
      char *allocation1;
      sqInt argClass;
      sqInt argClass1;
      sqInt argSpec;
      sqInt argSpec1;
      sqInt argType;
      sqInt argType1;
      sqInt argTypeArray;
      sqInt argTypeArray1;
      sqInt argTypes;
      sqInt argTypes1;
      sqInt argTypes2;
      sqInt argTypes3;
      sqLong arrayAddr;
      sqLong arrayAddr1;
      sqInt atomicType;
      sqInt atomicType1;
      sqInt atomicType11;
      sqInt atomicType2;
      sqInt byteSize;
      sqInt byteSize1;
      extern void callAndReturnWithStructAddr(sqLong structAddr,sqLong procAddr,sqLong arrayAddr);
      CalloutState *calloutState;
      CalloutState *calloutState1;
      sqInt classOop;
      sqInt classOop1;
      sqInt cPointer;
      sqInt cPointer1;
      char *cString;
      char *cString1;
      sqInt err;
      sqInt err1;
      sqInt externalFunction;
      sqInt ffiRetType;
      sqInt ffiRetType1;
      sqInt flags;
      sqInt flags1;
      double floatRet;
      double floatRet1;
      sqInt functionName;
      sqInt functionName1;
      sqInt i;
      sqInt i1;
      sqInt i11;
      sqInt i2;
      usqLong intRet;
      usqLong intRet1;
      extern void loadFloatRegs(double, double, double, double, double, double, double, double);
      usqLong mask;
      usqLong mask1;
      sqInt meth;
      sqInt myThreadIndex;
      sqInt myThreadIndex1;
      sqInt nArgs;
      sqInt nArgs1;
      sqInt oop;
      sqInt oop1;
      sqInt oop11;
      sqInt oop2;
      sqInt oop21;
      sqInt oop3;
      sqInt primNumArgs;
      sqInt primNumArgs1;
      sqIntptr_t *ptr;
      sqInt *ptr1;
      sqInt *ptr11;
      sqIntptr_t *ptr2;
      sqInt requiredStackSize;
      sqInt requiredStackSize1;
      sqInt result;
      sqInt result1;
      sqInt result2;
      sqInt retClass;
      sqInt retClass1;
      sqInt retClass11;
      sqInt retClass2;
      sqInt retOop;
      sqInt retOop1;
      sqInt retOop11;
      sqInt retOop2;
      sqInt retryCount;
      sqInt retType;
      sqInt retType1;
      extern sqLong returnX1value();
      sqInt shift;
      sqInt shift1;
      sqInt specLiteral;
      sqInt specLiteral1;
      sqInt specLiteral2;
      sqInt specLiteral3;
      sqInt stackSize;
      sqInt stackSize1;
      sqInt strLen;
      sqInt strLen1;
      sqInt strOop;
      sqInt strOop1;
      char *strPtr;
      char *strPtr1;
      sqLong structAddr;
      sqLong structAddr1;
      CalloutState theCalloutState;
      CalloutState theCalloutState1;
      sqInt typeSpec;
      sqInt typeSpec1;
      sqInt typeSpec11;
      sqInt typeSpec2;
      usqLong value;
      usqLong value1;
      usqLong x1Ret;
      usqLong x1Ret1;
  
  	x1Ret = 0;
  	x1Ret1 = 0;
  	meth = primitiveMethod();
  	if (!((literalCountOf(meth)) > 0)) {
  		primitiveFailFor(PrimErrBadMethod);
  		return;
  	}
  	externalFunction = literalofMethod(0, meth);
  	
  #  if COGMTVM
  	nArgs = methodArgumentCount();
  	retryCount = 0;
  	while (1) {
  		/* begin ffiCall:ArgArrayOrNil:NumArgs: */
  		primNumArgs = methodArgumentCount();
  		if (!(isKindOfClass(externalFunction, classExternalFunction()))) {
  			result = ffiFail(FFIErrorNotFunction);
  			goto l9;
  		}
  		flags = fetchIntegerofObject(ExternalFunctionFlagsIndex, externalFunction);
  		if (failed()) {
  			result = ffiFail(FFIErrorBadArgs);
  			goto l9;
  		}
  		/* begin ffiLoadCalloutAddress: */
  
  		/* Make sure it's an external handle */
  		addressPtr = fetchPointerofObject(0, externalFunction);
  		if (!((isBytes(addressPtr))
  			 && ((byteSizeOf(addressPtr)) == (sizeof(sqInt))))) {
  			address1 = ffiFail(FFIErrorBadAddress);
  			goto l1;
  		}
  		address1 = fetchPointerofObject(0, addressPtr);
  	l1:	/* end ffiContentsOfHandle:errCode: */;
  		if (failed()) {
  			address = 0;
  			goto l2;
  		}
  		if (address1 == 0) {
  
  			/* Go look it up in the module */
  			if (externalFunctionInstSize > ExternalFunctionStackSizeIndex) {
  				storePointerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, integerObjectOf(-1));
  			}
  			if ((slotSizeOf(externalFunction)) < 5) {
  				address = ffiFail(FFIErrorNoModule);
  				goto l2;
  			}
  			address1 = ffiLoadCalloutAddressFrom(externalFunction);
  			if (failed()) {
  				address = 0;
  				goto l2;
  			}
  			ptr = firstIndexableField(addressPtr);
  			ptr[0] = address1;
  		}
  		address = address1;
  	l2:	/* end ffiLoadCalloutAddress: */;
  		if (failed()) {
  			result = 0;
  			goto l9;
  		}
  
  		/* must be array of arg types */
  		argTypeArray = fetchPointerofObject(ExternalFunctionArgTypesIndex, externalFunction);
  		if (!((isArray(argTypeArray))
  			 && ((slotSizeOf(argTypeArray)) == (nArgs + 1)))) {
  			result = ffiFail(FFIErrorBadArgs);
  			goto l9;
  		}
  		
  #    if COGMTVM
  		if (!(((flags & FFICallTypesMask) == FFICallTypeCDecl)
  			 || ((flags & FFICallTypesMask) == FFICallTypeApi))) {
  			result = ffiFail(FFIErrorCallType);
  			goto l9;
  		}
  #    else /* COGMTVM */
  
  		/* not masking causes threaded calls to fail, which is as they should if the plugin is not threaded. */
  		if (!((flags == FFICallTypeCDecl)
  			 || (flags == FFICallTypeApi))) {
  			result = ffiFail(FFIErrorCallType);
  			goto l9;
  		}
  #    endif /* COGMTVM */
  		requiredStackSize = (externalFunctionInstSize > ExternalFunctionStackSizeIndex
  			? fetchIntegerofObject(ExternalFunctionStackSizeIndex, externalFunction)
  			: -1);
  		if (failed()) {
  			result = primitiveFailFor((null == null
  				? PrimErrBadMethod
  				: PrimErrBadReceiver));
  			goto l9;
  		}
  		stackSize = (requiredStackSize < 0
  			? DefaultMaxStackSize
  			: requiredStackSize);
  		calloutState = (&theCalloutState);
  		memset(calloutState, 0, sizeof(CalloutState));
  		(calloutState->callFlags = flags);
  		argType = fetchPointerofObject(0, argTypeArray);
  		argSpec = fetchPointerofObject(0, argType);
  		argClass = fetchPointerofObject(1, argType);
  		if (((err = ffiCheckReturnWithin(argSpec, argClass, calloutState))) != 0) {
  			result = ffiFail(err);
  			goto l9;
  		}
  		allocation = alloca((stackSize + ((calloutState->structReturnSize))) + (cStackAlignment()));
  		if (mustAlignStack()) {
  			allocation = ((char *) ((((((usqIntptr_t)allocation)) | ((cStackAlignment()) - 1)) - ((cStackAlignment()) - 1))));
  		}
  		(calloutState->argVector = allocation);
  		(calloutState->currentArg = allocation);
  		(calloutState->limit = allocation + stackSize);
  		for (i = 1; i <= nArgs; i += 1) {
  			argType = fetchPointerofObject(i, argTypeArray);
  			argSpec = fetchPointerofObject(0, argType);
  			argClass = fetchPointerofObject(1, argType);
  			oop = (null == null
  				? stackValue(nArgs - i)
  				: fetchPointerofObject(i - 1, null));
  			err = ffiArgumentSpecClassin(oop, argSpec, argClass, calloutState);
  			if (err != 0) {
  				/* begin cleanupCalloutState: */
  				while (((calloutState->stringArgIndex)) > 0) {
  					free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
  				}
  				
  #        if COGMTVM
  				if (err == (-PrimErrObjectMayMove)) {
  					result = PrimErrObjectMayMove;
  					goto l9;
  				}
  #        endif /* COGMTVM */
  				result = ffiFail(err);
  				goto l9;
  			}
  		}
  		assert(!(failed()));
  		/* begin ffiLogCallout: */
  		if (ffiLogEnabled) {
  			functionName = fetchPointerofObject(externalFunctionInstSize, externalFunction);
  			if (!(isBytes(functionName))) {
  				goto l3;
  			}
  			ffiLogCallOfLength(firstIndexableField(functionName), byteSizeOf(functionName));
  		}
  	l3:	/* end ffiLogCallout: */;
  		if ((requiredStackSize < 0)
  		 && (externalFunctionInstSize > ExternalFunctionStackSizeIndex)) {
  			stackSize = ((calloutState->currentArg)) - ((calloutState->argVector));
  			storeIntegerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, stackSize);
  		}
  		/* begin ffiCalloutTo:SpecOnStack:in: */
  		myThreadIndex = disownVM(
  #    if COGMTVM
  			(((calloutState->callFlags)) & FFICallFlagThreaded
  						? DisownVMForFFICall + DisownVMForThreading
  						: DisownVMForFFICall)
  #    else /* COGMTVM */
  			DisownVMForFFICall
  #    endif /* COGMTVM */
  			);
  		if (((calloutState->floatRegisterIndex)) > 0) {
  			loadFloatRegs(((calloutState->floatRegisters))[0], ((calloutState->floatRegisters))[1], ((calloutState->floatRegisters))[2], ((calloutState->floatRegisters))[3], ((calloutState->floatRegisters))[4], ((calloutState->floatRegisters))[5], ((calloutState->floatRegisters))[6], ((calloutState->floatRegisters))[7]);
  		}
  		if ((allocaLiesSoSetSpBeforeCall())
  		 || (mustAlignStack())) {
  			setsp((calloutState->argVector));
  		}
  		/* begin atomicTypeOf: */
  		typeSpec = (calloutState->ffiRetHeader);
  		atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  		if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSingleFloat) >> 1)) {
  			if (atomicType == FFITypeSingleFloat) {
  				floatRet = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3], ((calloutState->integerRegisters))[4], ((calloutState->integerRegisters))[5], ((calloutState->integerRegisters))[6], ((calloutState->integerRegisters))[7]);
  			}
  			else {
  
  				/* atomicType = FFITypeDoubleFloat */
  				floatRet = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3], ((calloutState->integerRegisters))[4], ((calloutState->integerRegisters))[5], ((calloutState->integerRegisters))[6], ((calloutState->integerRegisters))[7]);
  			}
  			if (isCalleePopsConvention((calloutState->callFlags))) {
  				setsp((calloutState->argVector));
  			}
  			ownVM(myThreadIndex);
  			result1 = floatObjectOf(floatRet);
  			goto l8;
  		}
  		if (((calloutState->structReturnSize)) > (2 * BytesPerWord)) {
  			intRet = 0;
  			/* begin setReturnRegister:andCall:withArgsArray: */
  			structAddr = ((sqLong) ((calloutState->limit)));
  			arrayAddr = ((sqLong) ((&((calloutState->integerRegisters)))));
  			callAndReturnWithStructAddr(structAddr, ((sqLong) (((void *) address))), arrayAddr);
  		}
  		else {
  			intRet = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3], ((calloutState->integerRegisters))[4], ((calloutState->integerRegisters))[5], ((calloutState->integerRegisters))[6], ((calloutState->integerRegisters))[7]);
  			x1Ret = returnX1value();
  		}
  		if ((((calloutState->structReturnSize)) > 0)
  		 && (((calloutState->structReturnSize)) <= (2 * BytesPerWord))) {
  
  			/* Only 2 regs used in ARMv8/Aarch64 current */
  			((calloutState->integerRegisters))[0] = intRet;
  			((calloutState->integerRegisters))[1] = x1Ret;
  		}
  		if (isCalleePopsConvention((calloutState->callFlags))) {
  			setsp((calloutState->argVector));
  		}
  		ownVM(myThreadIndex);
  		if (((calloutState->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) {
  
  			/* Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
  			   'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct. */
  			if (((calloutState->ffiRetHeader)) & FFIFlagPointer) {
  				/* begin ffiReturnPointer:ofType:in: */
  				specLiteral = (null != null
  					? stackValue(1)
  					: literalofMethod(0, primitiveMethod()));
  				argTypes = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral);
  				retType = fetchPointerofObject(0, argTypes);
  				retClass = fetchPointerofObject(1, retType);
  				if (retClass == (nilObject())) {
  
  					/* Create ExternalData upon return */
  					/* begin atomicTypeOf: */
  					typeSpec1 = (calloutState->ffiRetHeader);
  					atomicType1 = ((usqInt) (typeSpec1 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  					if ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {
  
  						/* String return */
  						/* begin ffiReturnCStringFrom: */
  						cPointer = ((usqInt) intRet);
  						if (!(cPointer)) {
  							retOop = nilObject();
  							goto l5;
  						}
  						cString = ((char *) cPointer);
  						strLen = 0;
  						while (!((cString[strLen]) == 0)) {
  							strLen += 1;
  						}
  						strOop = instantiateClassindexableSize(classString(), strLen);
  						strPtr = firstIndexableField(strOop);
  						for (i1 = 0; i1 < strLen; i1 += 1) {
  							strPtr[i1] = (cString[i1]);
  						}
  						retOop = strOop;
  	l5:	/* end ffiReturnCStringFrom: */;
  						result1 = retOop;
  						goto l8;
  					}
  					
  #if SPURVM
  					oop2 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  					ptr1 = firstIndexableField(oop2);
  					ptr1[0] = (((sqInt) intRet));
  					retOop = instantiateClassindexableSize(classExternalData(), 0);
  					storePointerofObjectwithValue(0, retOop, oop2);
  
  #else /* SPURVM */
  					pushRemappableOop(retType);
  					oop2 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  					ptr1 = firstIndexableField(oop2);
  					ptr1[0] = (((sqInt) intRet));
  										pushRemappableOop(oop2);
  					retOop = instantiateClassindexableSize(classExternalData(), 0);
  					oop2 = popRemappableOop();
  					storePointerofObjectwithValue(0, retOop, oop2);
  					retType = popRemappableOop()
  #endif /* SPURVM */
  ;
  					storePointerofObjectwithValue(1, retOop, retType);
  					result1 = retOop;
  					goto l8;
  				}
  				classOop = (((calloutState->ffiRetHeader)) & FFIFlagStructure
  					? classByteArray()
  					: classExternalAddress());
  				
  #if SPURVM
  				oop2 = instantiateClassindexableSize(classOop, BytesPerWord);
  
  #else /* SPURVM */
  				pushRemappableOop(retClass);
  				oop2 = instantiateClassindexableSize(classOop, BytesPerWord);
  				retClass = popRemappableOop()
  #endif /* SPURVM */
  ;
  				ptr1 = firstIndexableField(oop2);
  				ptr1[0] = (((sqInt) intRet));
  				
  #if SPURVM
  				retOop = instantiateClassindexableSize(retClass, 0);
  
  #else /* SPURVM */
  				pushRemappableOop(oop2);
  				retOop = instantiateClassindexableSize(retClass, 0);
  				oop2 = popRemappableOop()
  #endif /* SPURVM */
  ;
  				storePointerofObjectwithValue(0, retOop, oop2);
  				result1 = retOop;
  				goto l8;
  			}
  			/* begin ffiReturnStruct:ofType:in: */
  			specLiteral2 = (null != null
  				? stackValue(1)
  				: literalofMethod(0, primitiveMethod()));
  			argTypes2 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral2);
  			ffiRetType = fetchPointerofObject(0, argTypes2);
  			retClass1 = fetchPointerofObject(1, ffiRetType);
  			retOop1 = instantiateClassindexableSize(retClass1, 0);
  			
  #if SPURVM
  			oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  
  #else /* SPURVM */
  			pushRemappableOop(retOop1);
  			oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  			retOop1 = popRemappableOop()
  #endif /* SPURVM */
  ;
  			memcpy(firstIndexableField(oop1), (((calloutState->structReturnSize)) <= (2 * BytesPerWord)
  				? (&((calloutState->integerRegisters)))
  				: (calloutState->limit)), (calloutState->structReturnSize));
  			storePointerofObjectwithValue(0, retOop1, oop1);
  			result1 = retOop1;
  			goto l8;
  		}
  		/* begin ffiCreateIntegralResultOop:ofAtomicType:in: */
  		assert(atomicType < FFITypeSingleFloat);
  		if (atomicType == FFITypeBool) {
  
  			/* Make sure bool honors the byte size requested */
  			byteSize = ((calloutState->ffiRetHeader)) & FFIStructSizeMask;
  			value = (byteSize == (sizeof(intRet))
  				? intRet
  				: intRet & (((((unsigned long long)1)) << (byteSize * 8)) - 1));
  			result1 = (value == 0
  				? falseObject()
  				: trueObject());
  			goto l8;
  		}
  		if (atomicType <= FFITypeSignedInt) {
  
  			/* these are all generall integer returns */
  			if (atomicType <= ((BytesPerWord == 8
  				? FFITypeSignedInt
  				: FFITypeSignedShort))) {
  
  				/* byte/short. first extract partial word, then sign extend */
  
  				/* # of significant bits */
  				shift = ((BytesPerWord == 8)
  				 && (atomicType >= FFITypeUnsignedInt)
  					? 32
  					: (((usqInt) atomicType) >> 1) * 8);
  				value = intRet & (((((unsigned long long)1)) << shift) - 1);
  				if (atomicType & 1) {
  
  					/* make the guy signed */
  					mask = (((unsigned long long)1)) << (shift - 1);
  					value = (value & (mask - 1)) - (value & mask);
  				}
  				result1 = integerObjectOf(value);
  				goto l8;
  			}
  			result1 = (atomicType & 1
  				? (BytesPerWord == 8
  						? signed64BitIntegerFor(intRet)
  						: signed32BitIntegerFor(intRet))
  				: (BytesPerWord == 8
  						? positive64BitIntegerFor(intRet)
  						: positive32BitIntegerFor(intRet)));
  			goto l8;
  		}
  		result1 = ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
  			? (atomicType & 1
  					? signed64BitIntegerFor(intRet)
  					: positive64BitIntegerFor(intRet))
  			: characterObjectOf(intRet & 0xFF));
  	l8:	/* end ffiCalloutTo:SpecOnStack:in: */;
  		/* begin cleanupCalloutState: */
  		while (((calloutState->stringArgIndex)) > 0) {
  			free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
  		}
  		popthenPush(primNumArgs + 1, result1);
  		result = result1;
  	l9:	/* end ffiCall:ArgArrayOrNil:NumArgs: */;
  		if (!((result == PrimErrObjectMayMove)
  		 && (((retryCount += 1)) <= (nArgs + 1)))) break;
  		tenuringIncrementalGC();
  	}
  #  else /* COGMTVM */
  	/* begin ffiCall:ArgArrayOrNil:NumArgs: */
  	nArgs1 = methodArgumentCount();
  	primNumArgs1 = methodArgumentCount();
  	if (!(isKindOfClass(externalFunction, classExternalFunction()))) {
  		ffiFail(FFIErrorNotFunction);
  		goto l18;
  	}
  	flags1 = fetchIntegerofObject(ExternalFunctionFlagsIndex, externalFunction);
  	if (failed()) {
  		ffiFail(FFIErrorBadArgs);
  		goto l18;
  	}
  	/* begin ffiLoadCalloutAddress: */
  
  	/* Make sure it's an external handle */
  	addressPtr1 = fetchPointerofObject(0, externalFunction);
  	if (!((isBytes(addressPtr1))
  		 && ((byteSizeOf(addressPtr1)) == (sizeof(sqInt))))) {
  		address11 = ffiFail(FFIErrorBadAddress);
  		goto l13;
  	}
  	address11 = fetchPointerofObject(0, addressPtr1);
  	l13:	/* end ffiContentsOfHandle:errCode: */;
  	if (failed()) {
  		address2 = 0;
  		goto l17;
  	}
  	if (address11 == 0) {
  
  		/* Go look it up in the module */
  		if (externalFunctionInstSize > ExternalFunctionStackSizeIndex) {
  			storePointerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, integerObjectOf(-1));
  		}
  		if ((slotSizeOf(externalFunction)) < 5) {
  			address2 = ffiFail(FFIErrorNoModule);
  			goto l17;
  		}
  		address11 = ffiLoadCalloutAddressFrom(externalFunction);
  		if (failed()) {
  			address2 = 0;
  			goto l17;
  		}
  		ptr2 = firstIndexableField(addressPtr1);
  		ptr2[0] = address11;
  	}
  	address2 = address11;
  	l17:	/* end ffiLoadCalloutAddress: */;
  	if (failed()) {
  		goto l18;
  	}
  
  	/* must be array of arg types */
  	argTypeArray1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, externalFunction);
  	if (!((isArray(argTypeArray1))
  		 && ((slotSizeOf(argTypeArray1)) == (nArgs1 + 1)))) {
  		ffiFail(FFIErrorBadArgs);
  		goto l18;
  	}
  	
  #  if COGMTVM
  	if (!(((flags1 & FFICallTypesMask) == FFICallTypeCDecl)
  		 || ((flags1 & FFICallTypesMask) == FFICallTypeApi))) {
  		ffiFail(FFIErrorCallType);
  		goto l18;
  	}
  #  else /* COGMTVM */
  
  	/* not masking causes threaded calls to fail, which is as they should if the plugin is not threaded. */
  	if (!((flags1 == FFICallTypeCDecl)
  		 || (flags1 == FFICallTypeApi))) {
  		ffiFail(FFIErrorCallType);
  		goto l18;
  	}
  #  endif /* COGMTVM */
  	requiredStackSize1 = (externalFunctionInstSize > ExternalFunctionStackSizeIndex
  		? fetchIntegerofObject(ExternalFunctionStackSizeIndex, externalFunction)
  		: -1);
  	if (failed()) {
  		primitiveFailFor((null == null
  			? PrimErrBadMethod
  			: PrimErrBadReceiver));
  		goto l18;
  	}
  	stackSize1 = (requiredStackSize1 < 0
  		? DefaultMaxStackSize
  		: requiredStackSize1);
  	calloutState1 = (&theCalloutState1);
  	memset(calloutState1, 0, sizeof(CalloutState));
  	(calloutState1->callFlags = flags1);
  	argType1 = fetchPointerofObject(0, argTypeArray1);
  	argSpec1 = fetchPointerofObject(0, argType1);
  	argClass1 = fetchPointerofObject(1, argType1);
  	if (((err1 = ffiCheckReturnWithin(argSpec1, argClass1, calloutState1))) != 0) {
  		ffiFail(err1);
  		goto l18;
  	}
  	allocation1 = alloca((stackSize1 + ((calloutState1->structReturnSize))) + (cStackAlignment()));
  	if (mustAlignStack()) {
  		allocation1 = ((char *) ((((((usqIntptr_t)allocation1)) | ((cStackAlignment()) - 1)) - ((cStackAlignment()) - 1))));
  	}
  	(calloutState1->argVector = allocation1);
  	(calloutState1->currentArg = allocation1);
  	(calloutState1->limit = allocation1 + stackSize1);
  	for (i2 = 1; i2 <= nArgs1; i2 += 1) {
  		argType1 = fetchPointerofObject(i2, argTypeArray1);
  		argSpec1 = fetchPointerofObject(0, argType1);
  		argClass1 = fetchPointerofObject(1, argType1);
  		oop3 = (null == null
  			? stackValue(nArgs1 - i2)
  			: fetchPointerofObject(i2 - 1, null));
  		err1 = ffiArgumentSpecClassin(oop3, argSpec1, argClass1, calloutState1);
  		if (err1 != 0) {
  			/* begin cleanupCalloutState: */
  			while (((calloutState1->stringArgIndex)) > 0) {
  				free(((calloutState1->stringArgs))[(calloutState1->stringArgIndex = ((calloutState1->stringArgIndex)) - 1)]);
  			}
  			
  #      if COGMTVM
  			if (err1 == (-PrimErrObjectMayMove)) {
  				goto l18;
  			}
  #      endif /* COGMTVM */
  			ffiFail(err1);
  			goto l18;
  		}
  	}
  	assert(!(failed()));
  	/* begin ffiLogCallout: */
  	if (ffiLogEnabled) {
  		functionName1 = fetchPointerofObject(externalFunctionInstSize, externalFunction);
  		if (!(isBytes(functionName1))) {
  			goto l12;
  		}
  		ffiLogCallOfLength(firstIndexableField(functionName1), byteSizeOf(functionName1));
  	}
  	l12:	/* end ffiLogCallout: */;
  	if ((requiredStackSize1 < 0)
  	 && (externalFunctionInstSize > ExternalFunctionStackSizeIndex)) {
  		stackSize1 = ((calloutState1->currentArg)) - ((calloutState1->argVector));
  		storeIntegerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, stackSize1);
  	}
  	/* begin ffiCalloutTo:SpecOnStack:in: */
  	myThreadIndex1 = disownVM(
  #  if COGMTVM
  		(((calloutState1->callFlags)) & FFICallFlagThreaded
  				? DisownVMForFFICall + DisownVMForThreading
  				: DisownVMForFFICall)
  #  else /* COGMTVM */
  		DisownVMForFFICall
  #  endif /* COGMTVM */
  		);
  	if (((calloutState1->floatRegisterIndex)) > 0) {
  		loadFloatRegs(((calloutState1->floatRegisters))[0], ((calloutState1->floatRegisters))[1], ((calloutState1->floatRegisters))[2], ((calloutState1->floatRegisters))[3], ((calloutState1->floatRegisters))[4], ((calloutState1->floatRegisters))[5], ((calloutState1->floatRegisters))[6], ((calloutState1->floatRegisters))[7]);
  	}
  	if ((allocaLiesSoSetSpBeforeCall())
  	 || (mustAlignStack())) {
  		setsp((calloutState1->argVector));
  	}
  	/* begin atomicTypeOf: */
  	typeSpec2 = (calloutState1->ffiRetHeader);
  	atomicType2 = ((usqInt) (typeSpec2 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  	if ((((usqInt) atomicType2) >> 1) == (((usqInt) FFITypeSingleFloat) >> 1)) {
  		if (atomicType2 == FFITypeSingleFloat) {
  			floatRet1 = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address2))), ((calloutState1->integerRegisters))[0], ((calloutState1->integerRegisters))[1], ((calloutState1->integerRegisters))[2], ((calloutState1->integerRegisters))[3], ((calloutState1->integerRegisters))[4], ((calloutState1->integerRegisters))[5], ((calloutState1->integerRegisters))[6], ((calloutState1->integerRegisters))[7]);
  		}
  		else {
  
  			/* atomicType = FFITypeDoubleFloat */
  			floatRet1 = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address2))), ((calloutState1->integerRegisters))[0], ((calloutState1->integerRegisters))[1], ((calloutState1->integerRegisters))[2], ((calloutState1->integerRegisters))[3], ((calloutState1->integerRegisters))[4], ((calloutState1->integerRegisters))[5], ((calloutState1->integerRegisters))[6], ((calloutState1->integerRegisters))[7]);
  		}
  		if (isCalleePopsConvention((calloutState1->callFlags))) {
  			setsp((calloutState1->argVector));
  		}
  		ownVM(myThreadIndex1);
  		result2 = floatObjectOf(floatRet1);
  		goto l14;
  	}
  	if (((calloutState1->structReturnSize)) > (2 * BytesPerWord)) {
  		intRet1 = 0;
  		/* begin setReturnRegister:andCall:withArgsArray: */
  		structAddr1 = ((sqLong) ((calloutState1->limit)));
  		arrayAddr1 = ((sqLong) ((&((calloutState1->integerRegisters)))));
  		callAndReturnWithStructAddr(structAddr1, ((sqLong) (((void *) address2))), arrayAddr1);
  	}
  	else {
  		intRet1 = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address2))), ((calloutState1->integerRegisters))[0], ((calloutState1->integerRegisters))[1], ((calloutState1->integerRegisters))[2], ((calloutState1->integerRegisters))[3], ((calloutState1->integerRegisters))[4], ((calloutState1->integerRegisters))[5], ((calloutState1->integerRegisters))[6], ((calloutState1->integerRegisters))[7]);
  		x1Ret1 = returnX1value();
  	}
  	if ((((calloutState1->structReturnSize)) > 0)
  	 && (((calloutState1->structReturnSize)) <= (2 * BytesPerWord))) {
  
  		/* Only 2 regs used in ARMv8/Aarch64 current */
  		((calloutState1->integerRegisters))[0] = intRet1;
  		((calloutState1->integerRegisters))[1] = x1Ret1;
  	}
  	if (isCalleePopsConvention((calloutState1->callFlags))) {
  		setsp((calloutState1->argVector));
  	}
  	ownVM(myThreadIndex1);
  	if (((calloutState1->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) {
  
  		/* Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
  		   'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct. */
  		if (((calloutState1->ffiRetHeader)) & FFIFlagPointer) {
  			/* begin ffiReturnPointer:ofType:in: */
  			specLiteral1 = (null != null
  				? stackValue(1)
  				: literalofMethod(0, primitiveMethod()));
  			argTypes1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral1);
  			retType1 = fetchPointerofObject(0, argTypes1);
  			retClass2 = fetchPointerofObject(1, retType1);
  			if (retClass2 == (nilObject())) {
  
  				/* Create ExternalData upon return */
  				/* begin atomicTypeOf: */
  				typeSpec11 = (calloutState1->ffiRetHeader);
  				atomicType11 = ((usqInt) (typeSpec11 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  				if ((((usqInt) atomicType11) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {
  
  					/* String return */
  					/* begin ffiReturnCStringFrom: */
  					cPointer1 = ((usqInt) intRet1);
  					if (!(cPointer1)) {
  						retOop2 = nilObject();
  						goto l11;
  					}
  					cString1 = ((char *) cPointer1);
  					strLen1 = 0;
  					while (!((cString1[strLen1]) == 0)) {
  						strLen1 += 1;
  					}
  					strOop1 = instantiateClassindexableSize(classString(), strLen1);
  					strPtr1 = firstIndexableField(strOop1);
  					for (i11 = 0; i11 < strLen1; i11 += 1) {
  						strPtr1[i11] = (cString1[i11]);
  					}
  					retOop2 = strOop1;
  	l11:	/* end ffiReturnCStringFrom: */;
  					result2 = retOop2;
  					goto l14;
  				}
  				
  #if SPURVM
  				oop21 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  				ptr11 = firstIndexableField(oop21);
  				ptr11[0] = (((sqInt) intRet1));
  				retOop2 = instantiateClassindexableSize(classExternalData(), 0);
  				storePointerofObjectwithValue(0, retOop2, oop21);
  
  #else /* SPURVM */
  				pushRemappableOop(retType1);
  				oop21 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  				ptr11 = firstIndexableField(oop21);
  				ptr11[0] = (((sqInt) intRet1));
  								pushRemappableOop(oop21);
  				retOop2 = instantiateClassindexableSize(classExternalData(), 0);
  				oop21 = popRemappableOop();
  				storePointerofObjectwithValue(0, retOop2, oop21);
  				retType1 = popRemappableOop()
  #endif /* SPURVM */
  ;
  				storePointerofObjectwithValue(1, retOop2, retType1);
  				result2 = retOop2;
  				goto l14;
  			}
  			classOop1 = (((calloutState1->ffiRetHeader)) & FFIFlagStructure
  				? classByteArray()
  				: classExternalAddress());
  			
  #if SPURVM
  			oop21 = instantiateClassindexableSize(classOop1, BytesPerWord);
  
  #else /* SPURVM */
  			pushRemappableOop(retClass2);
  			oop21 = instantiateClassindexableSize(classOop1, BytesPerWord);
  			retClass2 = popRemappableOop()
  #endif /* SPURVM */
  ;
  			ptr11 = firstIndexableField(oop21);
  			ptr11[0] = (((sqInt) intRet1));
  			
  #if SPURVM
  			retOop2 = instantiateClassindexableSize(retClass2, 0);
  
  #else /* SPURVM */
  			pushRemappableOop(oop21);
  			retOop2 = instantiateClassindexableSize(retClass2, 0);
  			oop21 = popRemappableOop()
  #endif /* SPURVM */
  ;
  			storePointerofObjectwithValue(0, retOop2, oop21);
  			result2 = retOop2;
  			goto l14;
  		}
  		/* begin ffiReturnStruct:ofType:in: */
  		specLiteral3 = (null != null
  			? stackValue(1)
  			: literalofMethod(0, primitiveMethod()));
  		argTypes3 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral3);
  		ffiRetType1 = fetchPointerofObject(0, argTypes3);
  		retClass11 = fetchPointerofObject(1, ffiRetType1);
  		retOop11 = instantiateClassindexableSize(retClass11, 0);
  		
  #if SPURVM
  		oop11 = instantiateClassindexableSize(classByteArray(), (calloutState1->structReturnSize));
  
  #else /* SPURVM */
  		pushRemappableOop(retOop11);
  		oop11 = instantiateClassindexableSize(classByteArray(), (calloutState1->structReturnSize));
  		retOop11 = popRemappableOop()
  #endif /* SPURVM */
  ;
  		memcpy(firstIndexableField(oop11), (((calloutState1->structReturnSize)) <= (2 * BytesPerWord)
  			? (&((calloutState1->integerRegisters)))
  			: (calloutState1->limit)), (calloutState1->structReturnSize));
  		storePointerofObjectwithValue(0, retOop11, oop11);
  		result2 = retOop11;
  		goto l14;
  	}
  	/* begin ffiCreateIntegralResultOop:ofAtomicType:in: */
  	assert(atomicType2 < FFITypeSingleFloat);
  	if (atomicType2 == FFITypeBool) {
  
  		/* Make sure bool honors the byte size requested */
  		byteSize1 = ((calloutState1->ffiRetHeader)) & FFIStructSizeMask;
  		value1 = (byteSize1 == (sizeof(intRet1))
  			? intRet1
  			: intRet1 & (((((unsigned long long)1)) << (byteSize1 * 8)) - 1));
  		result2 = (value1 == 0
  			? falseObject()
  			: trueObject());
  		goto l14;
  	}
  	if (atomicType2 <= FFITypeSignedInt) {
  
  		/* these are all generall integer returns */
  		if (atomicType2 <= ((BytesPerWord == 8
  			? FFITypeSignedInt
  			: FFITypeSignedShort))) {
  
  			/* byte/short. first extract partial word, then sign extend */
  
  			/* # of significant bits */
  			shift1 = ((BytesPerWord == 8)
  			 && (atomicType2 >= FFITypeUnsignedInt)
  				? 32
  				: (((usqInt) atomicType2) >> 1) * 8);
  			value1 = intRet1 & (((((unsigned long long)1)) << shift1) - 1);
  			if (atomicType2 & 1) {
  
  				/* make the guy signed */
  				mask1 = (((unsigned long long)1)) << (shift1 - 1);
  				value1 = (value1 & (mask1 - 1)) - (value1 & mask1);
  			}
  			result2 = integerObjectOf(value1);
  			goto l14;
  		}
  		result2 = (atomicType2 & 1
  			? (BytesPerWord == 8
  					? signed64BitIntegerFor(intRet1)
  					: signed32BitIntegerFor(intRet1))
  			: (BytesPerWord == 8
  					? positive64BitIntegerFor(intRet1)
  					: positive32BitIntegerFor(intRet1)));
  		goto l14;
  	}
  	result2 = ((((usqInt) atomicType2) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
  		? (atomicType2 & 1
  				? signed64BitIntegerFor(intRet1)
  				: positive64BitIntegerFor(intRet1))
  		: characterObjectOf(intRet1 & 0xFF));
  	l14:	/* end ffiCalloutTo:SpecOnStack:in: */;
  	/* begin cleanupCalloutState: */
  	while (((calloutState1->stringArgIndex)) > 0) {
  		free(((calloutState1->stringArgs))[(calloutState1->stringArgIndex = ((calloutState1->stringArgIndex)) - 1)]);
  	}
  	popthenPush(primNumArgs1 + 1, result2);
  	l18:	/* end ffiCall:ArgArrayOrNil:NumArgs: */;
  #  endif /* COGMTVM */
  	return;
  }
  
  
  /*	Perform a function call to a foreign function.
  	Only invoked from ExternalFunction>>invokeWithArguments: */
  
  	/* ThreadedFFIPlugin>>#primitiveCalloutWithArgs */
  EXPORT(void)
  primitiveCalloutWithArgs(void)
  {
      sqInt address;
      sqInt address1;
      sqInt address11;
      sqInt address2;
      sqInt addressPtr;
      sqInt addressPtr1;
      char *allocation;
      char *allocation1;
      sqInt argArray;
      sqInt argClass;
      sqInt argClass1;
      sqInt argSpec;
      sqInt argSpec1;
      sqInt argType;
      sqInt argType1;
      sqInt argTypeArray;
      sqInt argTypeArray1;
      sqInt argTypes;
      sqInt argTypes1;
      sqInt argTypes2;
      sqInt argTypes3;
      sqLong arrayAddr;
      sqLong arrayAddr1;
      sqInt atomicType;
      sqInt atomicType1;
      sqInt atomicType11;
      sqInt atomicType2;
      sqInt byteSize;
      sqInt byteSize1;
      extern void callAndReturnWithStructAddr(sqLong structAddr,sqLong procAddr,sqLong arrayAddr);
      CalloutState *calloutState;
      CalloutState *calloutState1;
      sqInt classOop;
      sqInt classOop1;
      sqInt cPointer;
      sqInt cPointer1;
      char *cString;
      char *cString1;
      sqInt err;
      sqInt err1;
      sqInt externalFunction;
      sqInt ffiRetType;
      sqInt ffiRetType1;
      sqInt flags;
      sqInt flags1;
      double floatRet;
      double floatRet1;
      sqInt functionName;
      sqInt functionName1;
      sqInt i;
      sqInt i1;
      sqInt i11;
      sqInt i2;
      usqLong intRet;
      usqLong intRet1;
      extern void loadFloatRegs(double, double, double, double, double, double, double, double);
      usqLong mask;
      usqLong mask1;
      sqInt myThreadIndex;
      sqInt myThreadIndex1;
      sqInt nArgs;
      sqInt oop;
      sqInt oop1;
      sqInt oop11;
      sqInt oop2;
      sqInt oop21;
      sqInt oop3;
      sqInt primNumArgs;
      sqInt primNumArgs1;
      sqIntptr_t *ptr;
      sqInt *ptr1;
      sqInt *ptr11;
      sqIntptr_t *ptr2;
      sqInt requiredStackSize;
      sqInt requiredStackSize1;
      sqInt result;
      sqInt result1;
      sqInt result2;
      sqInt retClass;
      sqInt retClass1;
      sqInt retClass11;
      sqInt retClass2;
      sqInt retOop;
      sqInt retOop1;
      sqInt retOop11;
      sqInt retOop2;
      sqInt retryCount;
      sqInt retType;
      sqInt retType1;
      extern sqLong returnX1value();
      sqInt shift;
      sqInt shift1;
      sqInt specLiteral;
      sqInt specLiteral1;
      sqInt specLiteral2;
      sqInt specLiteral3;
      sqInt stackSize;
      sqInt stackSize1;
      sqInt strLen;
      sqInt strLen1;
      sqInt strOop;
      sqInt strOop1;
      char *strPtr;
      char *strPtr1;
      sqLong structAddr;
      sqLong structAddr1;
      CalloutState theCalloutState;
      CalloutState theCalloutState1;
      sqInt typeSpec;
      sqInt typeSpec1;
      sqInt typeSpec11;
      sqInt typeSpec2;
      usqLong value;
      usqLong value1;
      usqLong x1Ret;
      usqLong x1Ret1;
  
  	x1Ret = 0;
  	x1Ret1 = 0;
  	if (!((methodArgumentCount()) == 1)) {
  		primitiveFailFor(PrimErrBadNumArgs);
  		return;
  	}
  	
  #  if COGMTVM
  	retryCount = 0;
  	while (1) {
  		externalFunction = stackValue(1);
  		argArray = stackValue(0);
  		if (!(isArray(argArray))) {
  			primitiveFailFor(PrimErrBadArgument);
  			return;
  		}
  		nArgs = slotSizeOf(argArray);
  		/* begin ffiCall:ArgArrayOrNil:NumArgs: */
  		primNumArgs = methodArgumentCount();
  		if (!(isKindOfClass(externalFunction, classExternalFunction()))) {
  			result = ffiFail(FFIErrorNotFunction);
  			goto l9;
  		}
  		flags = fetchIntegerofObject(ExternalFunctionFlagsIndex, externalFunction);
  		if (failed()) {
  			result = ffiFail(FFIErrorBadArgs);
  			goto l9;
  		}
  		/* begin ffiLoadCalloutAddress: */
  
  		/* Make sure it's an external handle */
  		addressPtr = fetchPointerofObject(0, externalFunction);
  		if (!((isBytes(addressPtr))
  			 && ((byteSizeOf(addressPtr)) == (sizeof(sqInt))))) {
  			address1 = ffiFail(FFIErrorBadAddress);
  			goto l1;
  		}
  		address1 = fetchPointerofObject(0, addressPtr);
  	l1:	/* end ffiContentsOfHandle:errCode: */;
  		if (failed()) {
  			address = 0;
  			goto l2;
  		}
  		if (address1 == 0) {
  
  			/* Go look it up in the module */
  			if (externalFunctionInstSize > ExternalFunctionStackSizeIndex) {
  				storePointerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, integerObjectOf(-1));
  			}
  			if ((slotSizeOf(externalFunction)) < 5) {
  				address = ffiFail(FFIErrorNoModule);
  				goto l2;
  			}
  			address1 = ffiLoadCalloutAddressFrom(externalFunction);
  			if (failed()) {
  				address = 0;
  				goto l2;
  			}
  			ptr = firstIndexableField(addressPtr);
  			ptr[0] = address1;
  		}
  		address = address1;
  	l2:	/* end ffiLoadCalloutAddress: */;
  		if (failed()) {
  			result = 0;
  			goto l9;
  		}
  
  		/* must be array of arg types */
  		argTypeArray = fetchPointerofObject(ExternalFunctionArgTypesIndex, externalFunction);
  		if (!((isArray(argTypeArray))
  			 && ((slotSizeOf(argTypeArray)) == (nArgs + 1)))) {
  			result = ffiFail(FFIErrorBadArgs);
  			goto l9;
  		}
  		
  #    if COGMTVM
  		if (!(((flags & FFICallTypesMask) == FFICallTypeCDecl)
  			 || ((flags & FFICallTypesMask) == FFICallTypeApi))) {
  			result = ffiFail(FFIErrorCallType);
  			goto l9;
  		}
  #    else /* COGMTVM */
  
  		/* not masking causes threaded calls to fail, which is as they should if the plugin is not threaded. */
  		if (!((flags == FFICallTypeCDecl)
  			 || (flags == FFICallTypeApi))) {
  			result = ffiFail(FFIErrorCallType);
  			goto l9;
  		}
  #    endif /* COGMTVM */
  		requiredStackSize = (externalFunctionInstSize > ExternalFunctionStackSizeIndex
  			? fetchIntegerofObject(ExternalFunctionStackSizeIndex, externalFunction)
  			: -1);
  		if (failed()) {
  			result = primitiveFailFor((argArray == null
  				? PrimErrBadMethod
  				: PrimErrBadReceiver));
  			goto l9;
  		}
  		stackSize = (requiredStackSize < 0
  			? DefaultMaxStackSize
  			: requiredStackSize);
  		calloutState = (&theCalloutState);
  		memset(calloutState, 0, sizeof(CalloutState));
  		(calloutState->callFlags = flags);
  		argType = fetchPointerofObject(0, argTypeArray);
  		argSpec = fetchPointerofObject(0, argType);
  		argClass = fetchPointerofObject(1, argType);
  		if (((err = ffiCheckReturnWithin(argSpec, argClass, calloutState))) != 0) {
  			result = ffiFail(err);
  			goto l9;
  		}
  		allocation = alloca((stackSize + ((calloutState->structReturnSize))) + (cStackAlignment()));
  		if (mustAlignStack()) {
  			allocation = ((char *) ((((((usqIntptr_t)allocation)) | ((cStackAlignment()) - 1)) - ((cStackAlignment()) - 1))));
  		}
  		(calloutState->argVector = allocation);
  		(calloutState->currentArg = allocation);
  		(calloutState->limit = allocation + stackSize);
  		for (i = 1; i <= nArgs; i += 1) {
  			argType = fetchPointerofObject(i, argTypeArray);
  			argSpec = fetchPointerofObject(0, argType);
  			argClass = fetchPointerofObject(1, argType);
  			oop = (argArray == null
  				? stackValue(nArgs - i)
  				: fetchPointerofObject(i - 1, argArray));
  			err = ffiArgumentSpecClassin(oop, argSpec, argClass, calloutState);
  			if (err != 0) {
  				/* begin cleanupCalloutState: */
  				while (((calloutState->stringArgIndex)) > 0) {
  					free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
  				}
  				
  #        if COGMTVM
  				if (err == (-PrimErrObjectMayMove)) {
  					result = PrimErrObjectMayMove;
  					goto l9;
  				}
  #        endif /* COGMTVM */
  				result = ffiFail(err);
  				goto l9;
  			}
  		}
  		assert(!(failed()));
  		/* begin ffiLogCallout: */
  		if (ffiLogEnabled) {
  			functionName = fetchPointerofObject(externalFunctionInstSize, externalFunction);
  			if (!(isBytes(functionName))) {
  				goto l3;
  			}
  			ffiLogCallOfLength(firstIndexableField(functionName), byteSizeOf(functionName));
  		}
  	l3:	/* end ffiLogCallout: */;
  		if ((requiredStackSize < 0)
  		 && (externalFunctionInstSize > ExternalFunctionStackSizeIndex)) {
  			stackSize = ((calloutState->currentArg)) - ((calloutState->argVector));
  			storeIntegerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, stackSize);
  		}
  		/* begin ffiCalloutTo:SpecOnStack:in: */
  		myThreadIndex = disownVM(
  #    if COGMTVM
  			(((calloutState->callFlags)) & FFICallFlagThreaded
  						? DisownVMForFFICall + DisownVMForThreading
  						: DisownVMForFFICall)
  #    else /* COGMTVM */
  			DisownVMForFFICall
  #    endif /* COGMTVM */
  			);
  		if (((calloutState->floatRegisterIndex)) > 0) {
  			loadFloatRegs(((calloutState->floatRegisters))[0], ((calloutState->floatRegisters))[1], ((calloutState->floatRegisters))[2], ((calloutState->floatRegisters))[3], ((calloutState->floatRegisters))[4], ((calloutState->floatRegisters))[5], ((calloutState->floatRegisters))[6], ((calloutState->floatRegisters))[7]);
  		}
  		if ((allocaLiesSoSetSpBeforeCall())
  		 || (mustAlignStack())) {
  			setsp((calloutState->argVector));
  		}
  		/* begin atomicTypeOf: */
  		typeSpec = (calloutState->ffiRetHeader);
  		atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  		if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSingleFloat) >> 1)) {
  			if (atomicType == FFITypeSingleFloat) {
  				floatRet = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3], ((calloutState->integerRegisters))[4], ((calloutState->integerRegisters))[5], ((calloutState->integerRegisters))[6], ((calloutState->integerRegisters))[7]);
  			}
  			else {
  
  				/* atomicType = FFITypeDoubleFloat */
  				floatRet = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3], ((calloutState->integerRegisters))[4], ((calloutState->integerRegisters))[5], ((calloutState->integerRegisters))[6], ((calloutState->integerRegisters))[7]);
  			}
  			if (isCalleePopsConvention((calloutState->callFlags))) {
  				setsp((calloutState->argVector));
  			}
  			ownVM(myThreadIndex);
  			result1 = floatObjectOf(floatRet);
  			goto l8;
  		}
  		if (((calloutState->structReturnSize)) > (2 * BytesPerWord)) {
  			intRet = 0;
  			/* begin setReturnRegister:andCall:withArgsArray: */
  			structAddr = ((sqLong) ((calloutState->limit)));
  			arrayAddr = ((sqLong) ((&((calloutState->integerRegisters)))));
  			callAndReturnWithStructAddr(structAddr, ((sqLong) (((void *) address))), arrayAddr);
  		}
  		else {
  			intRet = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3], ((calloutState->integerRegisters))[4], ((calloutState->integerRegisters))[5], ((calloutState->integerRegisters))[6], ((calloutState->integerRegisters))[7]);
  			x1Ret = returnX1value();
  		}
  		if ((((calloutState->structReturnSize)) > 0)
  		 && (((calloutState->structReturnSize)) <= (2 * BytesPerWord))) {
  
  			/* Only 2 regs used in ARMv8/Aarch64 current */
  			((calloutState->integerRegisters))[0] = intRet;
  			((calloutState->integerRegisters))[1] = x1Ret;
  		}
  		if (isCalleePopsConvention((calloutState->callFlags))) {
  			setsp((calloutState->argVector));
  		}
  		ownVM(myThreadIndex);
  		if (((calloutState->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) {
  
  			/* Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
  			   'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct. */
  			if (((calloutState->ffiRetHeader)) & FFIFlagPointer) {
  				/* begin ffiReturnPointer:ofType:in: */
  				specLiteral = (argArray != null
  					? stackValue(1)
  					: literalofMethod(0, primitiveMethod()));
  				argTypes = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral);
  				retType = fetchPointerofObject(0, argTypes);
  				retClass = fetchPointerofObject(1, retType);
  				if (retClass == (nilObject())) {
  
  					/* Create ExternalData upon return */
  					/* begin atomicTypeOf: */
  					typeSpec1 = (calloutState->ffiRetHeader);
  					atomicType1 = ((usqInt) (typeSpec1 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  					if ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {
  
  						/* String return */
  						/* begin ffiReturnCStringFrom: */
  						cPointer = ((usqInt) intRet);
  						if (!(cPointer)) {
  							retOop = nilObject();
  							goto l5;
  						}
  						cString = ((char *) cPointer);
  						strLen = 0;
  						while (!((cString[strLen]) == 0)) {
  							strLen += 1;
  						}
  						strOop = instantiateClassindexableSize(classString(), strLen);
  						strPtr = firstIndexableField(strOop);
  						for (i1 = 0; i1 < strLen; i1 += 1) {
  							strPtr[i1] = (cString[i1]);
  						}
  						retOop = strOop;
  	l5:	/* end ffiReturnCStringFrom: */;
  						result1 = retOop;
  						goto l8;
  					}
  					
  #if SPURVM
  					oop2 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  					ptr1 = firstIndexableField(oop2);
  					ptr1[0] = (((sqInt) intRet));
  					retOop = instantiateClassindexableSize(classExternalData(), 0);
  					storePointerofObjectwithValue(0, retOop, oop2);
  
  #else /* SPURVM */
  					pushRemappableOop(retType);
  					oop2 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  					ptr1 = firstIndexableField(oop2);
  					ptr1[0] = (((sqInt) intRet));
  										pushRemappableOop(oop2);
  					retOop = instantiateClassindexableSize(classExternalData(), 0);
  					oop2 = popRemappableOop();
  					storePointerofObjectwithValue(0, retOop, oop2);
  					retType = popRemappableOop()
  #endif /* SPURVM */
  ;
  					storePointerofObjectwithValue(1, retOop, retType);
  					result1 = retOop;
  					goto l8;
  				}
  				classOop = (((calloutState->ffiRetHeader)) & FFIFlagStructure
  					? classByteArray()
  					: classExternalAddress());
  				
  #if SPURVM
  				oop2 = instantiateClassindexableSize(classOop, BytesPerWord);
  
  #else /* SPURVM */
  				pushRemappableOop(retClass);
  				oop2 = instantiateClassindexableSize(classOop, BytesPerWord);
  				retClass = popRemappableOop()
  #endif /* SPURVM */
  ;
  				ptr1 = firstIndexableField(oop2);
  				ptr1[0] = (((sqInt) intRet));
  				
  #if SPURVM
  				retOop = instantiateClassindexableSize(retClass, 0);
  
  #else /* SPURVM */
  				pushRemappableOop(oop2);
  				retOop = instantiateClassindexableSize(retClass, 0);
  				oop2 = popRemappableOop()
  #endif /* SPURVM */
  ;
  				storePointerofObjectwithValue(0, retOop, oop2);
  				result1 = retOop;
  				goto l8;
  			}
  			/* begin ffiReturnStruct:ofType:in: */
  			specLiteral2 = (argArray != null
  				? stackValue(1)
  				: literalofMethod(0, primitiveMethod()));
  			argTypes2 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral2);
  			ffiRetType = fetchPointerofObject(0, argTypes2);
  			retClass1 = fetchPointerofObject(1, ffiRetType);
  			retOop1 = instantiateClassindexableSize(retClass1, 0);
  			
  #if SPURVM
  			oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  
  #else /* SPURVM */
  			pushRemappableOop(retOop1);
  			oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  			retOop1 = popRemappableOop()
  #endif /* SPURVM */
  ;
  			memcpy(firstIndexableField(oop1), (((calloutState->structReturnSize)) <= (2 * BytesPerWord)
  				? (&((calloutState->integerRegisters)))
  				: (calloutState->limit)), (calloutState->structReturnSize));
  			storePointerofObjectwithValue(0, retOop1, oop1);
  			result1 = retOop1;
  			goto l8;
  		}
  		/* begin ffiCreateIntegralResultOop:ofAtomicType:in: */
  		assert(atomicType < FFITypeSingleFloat);
  		if (atomicType == FFITypeBool) {
  
  			/* Make sure bool honors the byte size requested */
  			byteSize = ((calloutState->ffiRetHeader)) & FFIStructSizeMask;
  			value = (byteSize == (sizeof(intRet))
  				? intRet
  				: intRet & (((((unsigned long long)1)) << (byteSize * 8)) - 1));
  			result1 = (value == 0
  				? falseObject()
  				: trueObject());
  			goto l8;
  		}
  		if (atomicType <= FFITypeSignedInt) {
  
  			/* these are all generall integer returns */
  			if (atomicType <= ((BytesPerWord == 8
  				? FFITypeSignedInt
  				: FFITypeSignedShort))) {
  
  				/* byte/short. first extract partial word, then sign extend */
  
  				/* # of significant bits */
  				shift = ((BytesPerWord == 8)
  				 && (atomicType >= FFITypeUnsignedInt)
  					? 32
  					: (((usqInt) atomicType) >> 1) * 8);
  				value = intRet & (((((unsigned long long)1)) << shift) - 1);
  				if (atomicType & 1) {
  
  					/* make the guy signed */
  					mask = (((unsigned long long)1)) << (shift - 1);
  					value = (value & (mask - 1)) - (value & mask);
  				}
  				result1 = integerObjectOf(value);
  				goto l8;
  			}
  			result1 = (atomicType & 1
  				? (BytesPerWord == 8
  						? signed64BitIntegerFor(intRet)
  						: signed32BitIntegerFor(intRet))
  				: (BytesPerWord == 8
  						? positive64BitIntegerFor(intRet)
  						: positive32BitIntegerFor(intRet)));
  			goto l8;
  		}
  		result1 = ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
  			? (atomicType & 1
  					? signed64BitIntegerFor(intRet)
  					: positive64BitIntegerFor(intRet))
  			: characterObjectOf(intRet & 0xFF));
  	l8:	/* end ffiCalloutTo:SpecOnStack:in: */;
  		/* begin cleanupCalloutState: */
  		while (((calloutState->stringArgIndex)) > 0) {
  			free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
  		}
  		popthenPush(primNumArgs + 1, result1);
  		result = result1;
  	l9:	/* end ffiCall:ArgArrayOrNil:NumArgs: */;
  		if (!((result == PrimErrObjectMayMove)
  		 && (((retryCount += 1)) <= (nArgs + 1)))) break;
  		tenuringIncrementalGC();
  	}
  #  else /* COGMTVM */
  	externalFunction = stackValue(1);
  	argArray = stackValue(0);
  	if (!(isArray(argArray))) {
  		primitiveFailFor(PrimErrBadArgument);
  		return;
  	}
  	nArgs = slotSizeOf(argArray);
  	/* begin ffiCall:ArgArrayOrNil:NumArgs: */
  	primNumArgs1 = methodArgumentCount();
  	if (!(isKindOfClass(externalFunction, classExternalFunction()))) {
  		ffiFail(FFIErrorNotFunction);
  		goto l18;
  	}
  	flags1 = fetchIntegerofObject(ExternalFunctionFlagsIndex, externalFunction);
  	if (failed()) {
  		ffiFail(FFIErrorBadArgs);
  		goto l18;
  	}
  	/* begin ffiLoadCalloutAddress: */
  
  	/* Make sure it's an external handle */
  	addressPtr1 = fetchPointerofObject(0, externalFunction);
  	if (!((isBytes(addressPtr1))
  		 && ((byteSizeOf(addressPtr1)) == (sizeof(sqInt))))) {
  		address11 = ffiFail(FFIErrorBadAddress);
  		goto l13;
  	}
  	address11 = fetchPointerofObject(0, addressPtr1);
  	l13:	/* end ffiContentsOfHandle:errCode: */;
  	if (failed()) {
  		address2 = 0;
  		goto l17;
  	}
  	if (address11 == 0) {
  
  		/* Go look it up in the module */
  		if (externalFunctionInstSize > ExternalFunctionStackSizeIndex) {
  			storePointerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, integerObjectOf(-1));
  		}
  		if ((slotSizeOf(externalFunction)) < 5) {
  			address2 = ffiFail(FFIErrorNoModule);
  			goto l17;
  		}
  		address11 = ffiLoadCalloutAddressFrom(externalFunction);
  		if (failed()) {
  			address2 = 0;
  			goto l17;
  		}
  		ptr2 = firstIndexableField(addressPtr1);
  		ptr2[0] = address11;
  	}
  	address2 = address11;
  	l17:	/* end ffiLoadCalloutAddress: */;
  	if (failed()) {
  		goto l18;
  	}
  
  	/* must be array of arg types */
  	argTypeArray1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, externalFunction);
  	if (!((isArray(argTypeArray1))
  		 && ((slotSizeOf(argTypeArray1)) == (nArgs + 1)))) {
  		ffiFail(FFIErrorBadArgs);
  		goto l18;
  	}
  	
  #  if COGMTVM
  	if (!(((flags1 & FFICallTypesMask) == FFICallTypeCDecl)
  		 || ((flags1 & FFICallTypesMask) == FFICallTypeApi))) {
  		ffiFail(FFIErrorCallType);
  		goto l18;
  	}
  #  else /* COGMTVM */
  
  	/* not masking causes threaded calls to fail, which is as they should if the plugin is not threaded. */
  	if (!((flags1 == FFICallTypeCDecl)
  		 || (flags1 == FFICallTypeApi))) {
  		ffiFail(FFIErrorCallType);
  		goto l18;
  	}
  #  endif /* COGMTVM */
  	requiredStackSize1 = (externalFunctionInstSize > ExternalFunctionStackSizeIndex
  		? fetchIntegerofObject(ExternalFunctionStackSizeIndex, externalFunction)
  		: -1);
  	if (failed()) {
  		primitiveFailFor((argArray == null
  			? PrimErrBadMethod
  			: PrimErrBadReceiver));
  		goto l18;
  	}
  	stackSize1 = (requiredStackSize1 < 0
  		? DefaultMaxStackSize
  		: requiredStackSize1);
  	calloutState1 = (&theCalloutState1);
  	memset(calloutState1, 0, sizeof(CalloutState));
  	(calloutState1->callFlags = flags1);
  	argType1 = fetchPointerofObject(0, argTypeArray1);
  	argSpec1 = fetchPointerofObject(0, argType1);
  	argClass1 = fetchPointerofObject(1, argType1);
  	if (((err1 = ffiCheckReturnWithin(argSpec1, argClass1, calloutState1))) != 0) {
  		ffiFail(err1);
  		goto l18;
  	}
  	allocation1 = alloca((stackSize1 + ((calloutState1->structReturnSize))) + (cStackAlignment()));
  	if (mustAlignStack()) {
  		allocation1 = ((char *) ((((((usqIntptr_t)allocation1)) | ((cStackAlignment()) - 1)) - ((cStackAlignment()) - 1))));
  	}
  	(calloutState1->argVector = allocation1);
  	(calloutState1->currentArg = allocation1);
  	(calloutState1->limit = allocation1 + stackSize1);
  	for (i2 = 1; i2 <= nArgs; i2 += 1) {
  		argType1 = fetchPointerofObject(i2, argTypeArray1);
  		argSpec1 = fetchPointerofObject(0, argType1);
  		argClass1 = fetchPointerofObject(1, argType1);
  		oop3 = (argArray == null
  			? stackValue(nArgs - i2)
  			: fetchPointerofObject(i2 - 1, argArray));
  		err1 = ffiArgumentSpecClassin(oop3, argSpec1, argClass1, calloutState1);
  		if (err1 != 0) {
  			/* begin cleanupCalloutState: */
  			while (((calloutState1->stringArgIndex)) > 0) {
  				free(((calloutState1->stringArgs))[(calloutState1->stringArgIndex = ((calloutState1->stringArgIndex)) - 1)]);
  			}
  			
  #      if COGMTVM
  			if (err1 == (-PrimErrObjectMayMove)) {
  				goto l18;
  			}
  #      endif /* COGMTVM */
  			ffiFail(err1);
  			goto l18;
  		}
  	}
  	assert(!(failed()));
  	/* begin ffiLogCallout: */
  	if (ffiLogEnabled) {
  		functionName1 = fetchPointerofObject(externalFunctionInstSize, externalFunction);
  		if (!(isBytes(functionName1))) {
  			goto l12;
  		}
  		ffiLogCallOfLength(firstIndexableField(functionName1), byteSizeOf(functionName1));
  	}
  	l12:	/* end ffiLogCallout: */;
  	if ((requiredStackSize1 < 0)
  	 && (externalFunctionInstSize > ExternalFunctionStackSizeIndex)) {
  		stackSize1 = ((calloutState1->currentArg)) - ((calloutState1->argVector));
  		storeIntegerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, stackSize1);
  	}
  	/* begin ffiCalloutTo:SpecOnStack:in: */
  	myThreadIndex1 = disownVM(
  #  if COGMTVM
  		(((calloutState1->callFlags)) & FFICallFlagThreaded
  				? DisownVMForFFICall + DisownVMForThreading
  				: DisownVMForFFICall)
  #  else /* COGMTVM */
  		DisownVMForFFICall
  #  endif /* COGMTVM */
  		);
  	if (((calloutState1->floatRegisterIndex)) > 0) {
  		loadFloatRegs(((calloutState1->floatRegisters))[0], ((calloutState1->floatRegisters))[1], ((calloutState1->floatRegisters))[2], ((calloutState1->floatRegisters))[3], ((calloutState1->floatRegisters))[4], ((calloutState1->floatRegisters))[5], ((calloutState1->floatRegisters))[6], ((calloutState1->floatRegisters))[7]);
  	}
  	if ((allocaLiesSoSetSpBeforeCall())
  	 || (mustAlignStack())) {
  		setsp((calloutState1->argVector));
  	}
  	/* begin atomicTypeOf: */
  	typeSpec2 = (calloutState1->ffiRetHeader);
  	atomicType2 = ((usqInt) (typeSpec2 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  	if ((((usqInt) atomicType2) >> 1) == (((usqInt) FFITypeSingleFloat) >> 1)) {
  		if (atomicType2 == FFITypeSingleFloat) {
  			floatRet1 = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address2))), ((calloutState1->integerRegisters))[0], ((calloutState1->integerRegisters))[1], ((calloutState1->integerRegisters))[2], ((calloutState1->integerRegisters))[3], ((calloutState1->integerRegisters))[4], ((calloutState1->integerRegisters))[5], ((calloutState1->integerRegisters))[6], ((calloutState1->integerRegisters))[7]);
  		}
  		else {
  
  			/* atomicType = FFITypeDoubleFloat */
  			floatRet1 = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address2))), ((calloutState1->integerRegisters))[0], ((calloutState1->integerRegisters))[1], ((calloutState1->integerRegisters))[2], ((calloutState1->integerRegisters))[3], ((calloutState1->integerRegisters))[4], ((calloutState1->integerRegisters))[5], ((calloutState1->integerRegisters))[6], ((calloutState1->integerRegisters))[7]);
  		}
  		if (isCalleePopsConvention((calloutState1->callFlags))) {
  			setsp((calloutState1->argVector));
  		}
  		ownVM(myThreadIndex1);
  		result2 = floatObjectOf(floatRet1);
  		goto l14;
  	}
  	if (((calloutState1->structReturnSize)) > (2 * BytesPerWord)) {
  		intRet1 = 0;
  		/* begin setReturnRegister:andCall:withArgsArray: */
  		structAddr1 = ((sqLong) ((calloutState1->limit)));
  		arrayAddr1 = ((sqLong) ((&((calloutState1->integerRegisters)))));
  		callAndReturnWithStructAddr(structAddr1, ((sqLong) (((void *) address2))), arrayAddr1);
  	}
  	else {
  		intRet1 = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address2))), ((calloutState1->integerRegisters))[0], ((calloutState1->integerRegisters))[1], ((calloutState1->integerRegisters))[2], ((calloutState1->integerRegisters))[3], ((calloutState1->integerRegisters))[4], ((calloutState1->integerRegisters))[5], ((calloutState1->integerRegisters))[6], ((calloutState1->integerRegisters))[7]);
  		x1Ret1 = returnX1value();
  	}
  	if ((((calloutState1->structReturnSize)) > 0)
  	 && (((calloutState1->structReturnSize)) <= (2 * BytesPerWord))) {
  
  		/* Only 2 regs used in ARMv8/Aarch64 current */
  		((calloutState1->integerRegisters))[0] = intRet1;
  		((calloutState1->integerRegisters))[1] = x1Ret1;
  	}
  	if (isCalleePopsConvention((calloutState1->callFlags))) {
  		setsp((calloutState1->argVector));
  	}
  	ownVM(myThreadIndex1);
  	if (((calloutState1->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) {
  
  		/* Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
  		   'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct. */
  		if (((calloutState1->ffiRetHeader)) & FFIFlagPointer) {
  			/* begin ffiReturnPointer:ofType:in: */
  			specLiteral1 = (argArray != null
  				? stackValue(1)
  				: literalofMethod(0, primitiveMethod()));
  			argTypes1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral1);
  			retType1 = fetchPointerofObject(0, argTypes1);
  			retClass2 = fetchPointerofObject(1, retType1);
  			if (retClass2 == (nilObject())) {
  
  				/* Create ExternalData upon return */
  				/* begin atomicTypeOf: */
  				typeSpec11 = (calloutState1->ffiRetHeader);
  				atomicType11 = ((usqInt) (typeSpec11 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
  				if ((((usqInt) atomicType11) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {
  
  					/* String return */
  					/* begin ffiReturnCStringFrom: */
  					cPointer1 = ((usqInt) intRet1);
  					if (!(cPointer1)) {
  						retOop2 = nilObject();
  						goto l11;
  					}
  					cString1 = ((char *) cPointer1);
  					strLen1 = 0;
  					while (!((cString1[strLen1]) == 0)) {
  						strLen1 += 1;
  					}
  					strOop1 = instantiateClassindexableSize(classString(), strLen1);
  					strPtr1 = firstIndexableField(strOop1);
  					for (i11 = 0; i11 < strLen1; i11 += 1) {
  						strPtr1[i11] = (cString1[i11]);
  					}
  					retOop2 = strOop1;
  	l11:	/* end ffiReturnCStringFrom: */;
  					result2 = retOop2;
  					goto l14;
  				}
  				
  #if SPURVM
  				oop21 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  				ptr11 = firstIndexableField(oop21);
  				ptr11[0] = (((sqInt) intRet1));
  				retOop2 = instantiateClassindexableSize(classExternalData(), 0);
  				storePointerofObjectwithValue(0, retOop2, oop21);
  
  #else /* SPURVM */
  				pushRemappableOop(retType1);
  				oop21 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  				ptr11 = firstIndexableField(oop21);
  				ptr11[0] = (((sqInt) intRet1));
  								pushRemappableOop(oop21);
  				retOop2 = instantiateClassindexableSize(classExternalData(), 0);
  				oop21 = popRemappableOop();
  				storePointerofObjectwithValue(0, retOop2, oop21);
  				retType1 = popRemappableOop()
  #endif /* SPURVM */
  ;
  				storePointerofObjectwithValue(1, retOop2, retType1);
  				result2 = retOop2;
  				goto l14;
  			}
  			classOop1 = (((calloutState1->ffiRetHeader)) & FFIFlagStructure
  				? classByteArray()
  				: classExternalAddress());
  			
  #if SPURVM
  			oop21 = instantiateClassindexableSize(classOop1, BytesPerWord);
  
  #else /* SPURVM */
  			pushRemappableOop(retClass2);
  			oop21 = instantiateClassindexableSize(classOop1, BytesPerWord);
  			retClass2 = popRemappableOop()
  #endif /* SPURVM */
  ;
  			ptr11 = firstIndexableField(oop21);
  			ptr11[0] = (((sqInt) intRet1));
  			
  #if SPURVM
  			retOop2 = instantiateClassindexableSize(retClass2, 0);
  
  #else /* SPURVM */
  			pushRemappableOop(oop21);
  			retOop2 = instantiateClassindexableSize(retClass2, 0);
  			oop21 = popRemappableOop()
  #endif /* SPURVM */
  ;
  			storePointerofObjectwithValue(0, retOop2, oop21);
  			result2 = retOop2;
  			goto l14;
  		}
  		/* begin ffiReturnStruct:ofType:in: */
  		specLiteral3 = (argArray != null
  			? stackValue(1)
  			: literalofMethod(0, primitiveMethod()));
  		argTypes3 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral3);
  		ffiRetType1 = fetchPointerofObject(0, argTypes3);
  		retClass11 = fetchPointerofObject(1, ffiRetType1);
  		retOop11 = instantiateClassindexableSize(retClass11, 0);
  		
  #if SPURVM
  		oop11 = instantiateClassindexableSize(classByteArray(), (calloutState1->structReturnSize));
  
  #else /* SPURVM */
  		pushRemappableOop(retOop11);
  		oop11 = instantiateClassindexableSize(classByteArray(), (calloutState1->structReturnSize));
  		retOop11 = popRemappableOop()
  #endif /* SPURVM */
  ;
  		memcpy(firstIndexableField(oop11), (((calloutState1->structReturnSize)) <= (2 * BytesPerWord)
  			? (&((calloutState1->integerRegisters)))
  			: (calloutState1->limit)), (calloutState1->structReturnSize));
  		storePointerofObjectwithValue(0, retOop11, oop11);
  		result2 = retOop11;
  		goto l14;
  	}
  	/* begin ffiCreateIntegralResultOop:ofAtomicType:in: */
  	assert(atomicType2 < FFITypeSingleFloat);
  	if (atomicType2 == FFITypeBool) {
  
  		/* Make sure bool honors the byte size requested */
  		byteSize1 = ((calloutState1->ffiRetHeader)) & FFIStructSizeMask;
  		value1 = (byteSize1 == (sizeof(intRet1))
  			? intRet1
  			: intRet1 & (((((unsigned long long)1)) << (byteSize1 * 8)) - 1));
  		result2 = (value1 == 0
  			? falseObject()
  			: trueObject());
  		goto l14;
  	}
  	if (atomicType2 <= FFITypeSignedInt) {
  
  		/* these are all generall integer returns */
  		if (atomicType2 <= ((BytesPerWord == 8
  			? FFITypeSignedInt
  			: FFITypeSignedShort))) {
  
  			/* byte/short. first extract partial word, then sign extend */
  
  			/* # of significant bits */
  			shift1 = ((BytesPerWord == 8)
  			 && (atomicType2 >= FFITypeUnsignedInt)
  				? 32
  				: (((usqInt) atomicType2) >> 1) * 8);
  			value1 = intRet1 & (((((unsigned long long)1)) << shift1) - 1);
  			if (atomicType2 & 1) {
  
  				/* make the guy signed */
  				mask1 = (((unsigned long long)1)) << (shift1 - 1);
  				value1 = (value1 & (mask1 - 1)) - (value1 & mask1);
  			}
  			result2 = integerObjectOf(value1);
  			goto l14;
  		}
  		result2 = (atomicType2 & 1
  			? (BytesPerWord == 8
  					? signed64BitIntegerFor(intRet1)
  					: signed32BitIntegerFor(intRet1))
  			: (BytesPerWord == 8
  					? positive64BitIntegerFor(intRet1)
  					: positive32BitIntegerFor(intRet1)));
  		goto l14;
  	}
  	result2 = ((((usqInt) atomicType2) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
  		? (atomicType2 & 1
  				? signed64BitIntegerFor(intRet1)
  				: positive64BitIntegerFor(intRet1))
  		: characterObjectOf(intRet1 & 0xFF));
  	l14:	/* end ffiCalloutTo:SpecOnStack:in: */;
  	/* begin cleanupCalloutState: */
  	while (((calloutState1->stringArgIndex)) > 0) {
  		free(((calloutState1->stringArgs))[(calloutState1->stringArgIndex = ((calloutState1->stringArgIndex)) - 1)]);
  	}
  	popthenPush(primNumArgs1 + 1, result2);
  	l18:	/* end ffiCall:ArgArrayOrNil:NumArgs: */;
  #  endif /* COGMTVM */
  	return;
  }
  
  
  /*	arguments: name(type, stack offset)
  	width(Integer, 4)
  	height(Integer, 3)
  	rowPitch(Integer, 2)
  	depth(Integer, 1)
  	isMSB(Boolean, 0) */
  
  	/* ThreadedFFIPlugin>>#primitiveCreateManualSurface */
  EXPORT(sqInt)
  primitiveCreateManualSurface(void)
  {
      sqInt depth;
      sqInt height;
      sqInt isMSB;
      sqInt result;
      sqInt rowPitch;
      sqInt width;
  
  	if (!((methodArgumentCount()) == 5)) {
  		return primitiveFailFor(PrimErrBadNumArgs);
  	}
  	width = stackIntegerValue(4);
  	height = stackIntegerValue(3);
  	rowPitch = stackIntegerValue(2);
  	depth = stackIntegerValue(1);
  	isMSB = stackObjectValue(0);
  	isMSB = booleanValueOf(isMSB);
  	if (failed()) {
  		return null;
  	}
  	result = createManualSurface(width, height, rowPitch, depth, isMSB);
  	if (result < 0) {
  		return primitiveFail();
  	}
  	result = signed32BitIntegerFor(result);
  	return popthenPush(6, result);
  }
  
  	/* ThreadedFFIPlugin>>#primitiveDestroyManualSurface */
  EXPORT(sqInt)
  primitiveDestroyManualSurface(void)
  {
      sqInt surfaceID;
  
  	if (!((methodArgumentCount()) == 1)) {
  		return primitiveFail();
  	}
  	surfaceID = stackIntegerValue(0);
  	if (!(failed())) {
  		if ((destroyManualSurface(surfaceID)) == 0) {
  			primitiveFail();
  		}
  		else {
  			pop(1);
  		}
  	}
  	return 0;
  }
  
  
  /*	Primitive. Allocate an object on the external heap. */
  
  	/* ThreadedFFIPlugin>>#primitiveFFIAllocate */
  EXPORT(sqInt)
  primitiveFFIAllocate(void)
  {
      sqInt addr;
      sqInt byteSize;
      sqInt oop;
      sqIntptr_t *ptr;
  
  	byteSize = stackIntegerValue(0);
  	if (failed()) {
  		return null;
  	}
  	addr = ffiAlloc(byteSize);
  	if (addr == 0) {
  		return primitiveFail();
  	}
  	oop = instantiateClassindexableSize(classExternalAddress(), sizeof(sqIntptr_t));
  	ptr = firstIndexableField(oop);
  	ptr[0] = addr;
  	return popthenPush(2, oop);
  }
  
  
  /*	Return a (signed or unsigned) n byte integer from the given byte offset. */
  
  	/* ThreadedFFIPlugin>>#primitiveFFIDoubleAt */
  EXPORT(sqInt)
  primitiveFFIDoubleAt(void)
  {
      void * addr;
      sqInt byteOffset;
      double floatValue;
      sqInt rcvr;
  
  	byteOffset = stackIntegerValue(0);
  	rcvr = stackObjectValue(1);
  	if (failed()) {
  		return 0;
  	}
  	addr = ffiAddressOfstartingAtsize(rcvr, byteOffset, 8);
  	if (addr == 0) {
  		return primitiveFail();
  	}
  	memcpy((&floatValue), addr, sizeof(floatValue));
  	pop(2);
  	return pushFloat(floatValue);
  }
  
  
  /*	Return a (signed or unsigned) n byte integer from the given byte offset. */
  
  	/* ThreadedFFIPlugin>>#primitiveFFIDoubleAtPut */
  EXPORT(sqInt)
  primitiveFFIDoubleAtPut(void)
  {
      void * addr;
      sqInt byteOffset;
      sqInt floatOop;
      double floatValue;
      sqInt rcvr;
  
  	floatOop = stackValue(0);
  	if (isIntegerObject(floatOop)) {
  		floatValue = ((double) (integerValueOf(floatOop)));
  	}
  	else {
  		floatValue = ((double) (floatValueOf(floatOop)));
  	}
  	byteOffset = stackIntegerValue(1);
  	rcvr = stackObjectValue(2);
  	if (failed()) {
  		return 0;
  	}
  	addr = ffiAddressOfstartingAtsize(rcvr, byteOffset, 8);
  	if (addr == 0) {
  		return primitiveFail();
  	}
  	memcpy(addr, (&floatValue), sizeof(floatValue));
  	return popthenPush(3, floatOop);
  }
  
  
  /*	Return a (signed or unsigned) n byte integer from the given byte offset. */
  
  	/* ThreadedFFIPlugin>>#primitiveFFIFloatAt */
  EXPORT(sqInt)
  primitiveFFIFloatAt(void)
  {
      void * addr;
      sqInt byteOffset;
      float floatValue;
      sqInt rcvr;
  
  	byteOffset = stackIntegerValue(0);
  	rcvr = stackObjectValue(1);
  	if (failed()) {
  		return 0;
  	}
  	addr = ffiAddressOfstartingAtsize(rcvr, byteOffset, 4);
  	if (addr == 0) {
  		return primitiveFail();
  	}
  	memcpy((&floatValue), addr, sizeof(floatValue));
  	pop(2);
  	return pushFloat(floatValue);
  }
  
  
  /*	Return a (signed or unsigned) n byte integer from the given byte offset. */
  
  	/* ThreadedFFIPlugin>>#primitiveFFIFloatAtPut */
  EXPORT(sqInt)
  primitiveFFIFloatAtPut(void)
  {
      void * addr;
      sqInt byteOffset;
      sqInt floatOop;
      float floatValue;
      sqInt rcvr;
  
  	floatOop = stackValue(0);
  	if (isIntegerObject(floatOop)) {
  		floatValue = ((float) (integerValueOf(floatOop)));
  	}
  	else {
  		floatValue = ((float) (floatValueOf(floatOop)));
  	}
  	byteOffset = stackIntegerValue(1);
  	rcvr = stackObjectValue(2);
  	if (failed()) {
  		return 0;
  	}
  	addr = ffiAddressOfstartingAtsize(rcvr, byteOffset, 4);
  	if (addr == 0) {
  		return primitiveFail();
  	}
  	memcpy(addr, (&floatValue), sizeof(floatValue));
  	return popthenPush(3, floatOop);
  }
  
  
  /*	Primitive. Free the object pointed to on the external heap. */
  
  	/* ThreadedFFIPlugin>>#primitiveFFIFree */
  EXPORT(sqInt)
  primitiveFFIFree(void)
  {
      sqIntptr_t addr;
      sqInt oop;
      sqIntptr_t *ptr;
  
  	oop = stackObjectValue(0);
  	if (!(((fetchClassOf(oop)) == (classExternalAddress()))
  		 && ((byteSizeOf(oop)) == (sizeof(sqIntptr_t))))) {
  		return primitiveFail();
  	}
  	ptr = firstIndexableField(oop);
  
  	/* Don't you dare to free Squeak's memory! */
  	addr = ptr[0];
  	if ((addr == 0)
  	 || ((((((usqIntptr_t)addr)) & ((sizeof(sqIntptr_t)) - 1)) != 0)
  	 || (isInMemory(addr)))) {
  		return primitiveFail();
  	}
  	ffiFree(addr);
  	return ptr[0] = 0;
  }
  
  
  /*	Primitive. Return the error code from a failed call to the foreign
  	function interface.
  	This is for backwards-compatibility. Thread-safe access to the error code
  	is via the
  	primitive error code. */
  
  	/* ThreadedFFIPlugin>>#primitiveFFIGetLastError */
  EXPORT(sqInt)
  primitiveFFIGetLastError(void)
  {
  	methodReturnInteger(ffiLastError);
  	return 0;
  }
  
  
  /*	Answer a (signed or unsigned) n byte integer from the given byte offset
  	in the receiver, using the platform's endianness. */
  
  	/* ThreadedFFIPlugin>>#primitiveFFIIntegerAt */
  EXPORT(sqInt)
  primitiveFFIIntegerAt(void)
  {
      void * addr;
      sqInt byteOffset;
      sqInt byteSize;
      sqInt isSigned;
      usqLong mask;
      sqInt rcvr;
      usqLong value;
      sqInt valueOop;
  
  	isSigned = booleanValueOf(stackValue(0));
  	byteSize = stackIntegerValue(1);
  	byteOffset = stackIntegerValue(2);
  	rcvr = stackObjectValue(3);
  	if (failed()) {
  		return 0;
  	}
  	if (!((byteOffset > 0)
  		 && ((((byteSize >= 1) && (byteSize <= 8)))
  		 && ((byteSize & (byteSize - 1)) == 0)))) {
  		return primitiveFail();
  	}
  	addr = ffiAddressOfstartingAtsize(rcvr, byteOffset, byteSize);
  	if (addr == 0) {
  		return primitiveFail();
  	}
  	if (byteSize <= 2) {
  		if (byteSize == 1) {
  			value = ((unsigned char) (byteAt(addr)));
  		}
  		else {
  			value = ((unsigned short) (unalignedShortAt(addr)));
  		}
  	}
  	else {
  		if (byteSize == 4) {
  			value = ((unsigned int) (unalignedLong32At(addr)));
  		}
  		else {
  			value = unalignedLong64At(addr);
  		}
  	}
  	if (byteSize < BytesPerWord) {
  		if (isSigned) {
  
  			/* sign extend value */
  			mask = (((unsigned long long)1)) << ((byteSize * 8) - 1);
  			value = (value & (mask - 1)) - (value & mask);
  		}
  		valueOop = integerObjectOf(value);
  	}
  	else {
  
  		/* general 64 bit integer; note these never fail */
  		if (isSigned) {
  			if (byteSize < 8) {
  
  				/* sign extend value */
  				mask = (((unsigned long long)1)) << ((byteSize * 8) - 1);
  				value = (value & (mask - 1)) - (value & mask);
  			}
  			valueOop = signed64BitIntegerFor(value);
  		}
  		else {
  			valueOop = positive64BitIntegerFor(value);
  		}
  	}
  	return popthenPush(4, valueOop);
  }
  
  
  /*	Store a (signed or unsigned) n byte integer at the given byte offset
  	in the receiver, using the platform's endianness. */
  
  	/* ThreadedFFIPlugin>>#primitiveFFIIntegerAtPut */
  EXPORT(sqInt)
  primitiveFFIIntegerAtPut(void)
  {
      void * addr;
      sqInt byteOffset;
      sqInt byteSize;
      sqInt isSigned;
      sqLong max;
      sqInt rcvr;
      sqLong value;
      sqInt valueOop;
  
  	isSigned = booleanValueOf(stackValue(0));
  	byteSize = stackIntegerValue(1);
  	valueOop = stackValue(2);
  	byteOffset = stackIntegerValue(3);
  	rcvr = stackObjectValue(4);
  	if (failed()) {
  		return 0;
  	}
  	if (!((byteOffset > 0)
  		 && ((((byteSize >= 1) && (byteSize <= 8)))
  		 && ((byteSize & (byteSize - 1)) == 0)))) {
  		return primitiveFail();
  	}
  	addr = ffiAddressOfstartingAtsize(rcvr, byteOffset, byteSize);
  	if (addr == 0) {
  		return primitiveFail();
  	}
  	if (isSigned) {
  		value = signed64BitValueOf(valueOop);
  	}
  	else {
  		value = positive64BitValueOf(valueOop);
  	}
  	if (failed()) {
  		return 0;
  	}
  	if (byteSize < 8) {
  		if (isSigned) {
  			max = (((unsigned long long)1)) << ((8 * byteSize) - 1);
  			if (!((value >= (0 - max))
  				 && (value < max))) {
  				return primitiveFail();
  			}
  		}
  		else {
  			if (!((((unsigned long long)value)) < ((((unsigned long long)1)) << (8 * byteSize)))) {
  				return primitiveFail();
  			}
  		}
  	}
  	if (byteSize <= 2) {
  		if (byteSize == 1) {
  			byteAtput(addr, value);
  		}
  		else {
  			unalignedShortAtput(addr, value);
  		}
  	}
  	else {
  		if (byteSize == 4) {
  			unalignedLong32Atput(addr, value);
  		}
  		else {
  			unalignedLong64Atput(addr, value);
  		}
  	}
  	return popthenPush(5, valueOop);
  }
  
  
  /*	Primitive. Force loading the receiver (an instance of ExternalLibrary). */
  
  	/* ThreadedFFIPlugin>>#primitiveForceLoad */
  EXPORT(sqInt)
  primitiveForceLoad(void)
  {
      sqInt ffiModuleName;
      sqInt moduleHandle;
      sqInt moduleHandlePtr;
      sqInt *ptr;
      sqInt rcvr;
  
  	if (!((methodArgumentCount()) == 0)) {
  		return primitiveFail();
  	}
  	rcvr = stackValue(0);
  	if (!(isKindOfClass(rcvr, classExternalLibrary()))) {
  		return ffiFail(FFIErrorBadExternalLibrary);
  	}
  	moduleHandlePtr = fetchPointerofObject(0, rcvr);
  	/* begin ffiContentsOfHandle:errCode: */
  	if (!((isBytes(moduleHandlePtr))
  		 && ((byteSizeOf(moduleHandlePtr)) == (sizeof(sqInt))))) {
  		moduleHandle = ffiFail(FFIErrorBadExternalLibrary);
  		goto l1;
  	}
  	moduleHandle = fetchPointerofObject(0, moduleHandlePtr);
  	l1:	/* end ffiContentsOfHandle:errCode: */;
  	if (failed()) {
  		return 0;
  	}
  	ffiModuleName = fetchPointerofObject(1, rcvr);
  	if (!(isBytes(ffiModuleName))) {
  		return ffiFail(FFIErrorBadExternalLibrary);
  	}
  	moduleHandle = ((sqInt)(ioLoadModuleOfLength(((sqInt)(firstIndexableField(ffiModuleName))), byteSizeOf(ffiModuleName))));
  	if (failed()) {
  		return ffiFail(FFIErrorModuleNotFound);
  	}
  	ptr = firstIndexableField(moduleHandlePtr);
  	ptr[0] = moduleHandle;
  	return 0;
  }
  
  
  /*	Attempt to find the address of a symbol in a loaded library.
  	loadSymbol: aSymbol fromModule: moduleName
  	<primitive: 'primitiveLoadSymbolFromModule' error: errorCode module:
  	'SqueakFFIPrims'>  */
  
  	/* ThreadedFFIPlugin>>#primitiveLoadSymbolFromModule */
  EXPORT(sqInt)
  primitiveLoadSymbolFromModule(void)
  {
      void *address;
      sqInt module;
      sqInt moduleHandle;
      sqInt oop;
      void **ptr;
      sqInt symbol;
  
  	if (!((methodArgumentCount()) == 2)) {
  		return primitiveFailFor(PrimErrBadNumArgs);
  	}
  	module = stackValue(0);
  	symbol = stackValue(1);
  	moduleHandle = (module != (nilObject())
  		? ffiLoadCalloutModule(module)
  		: 0);
  	if (failed()) {
  		return primitiveFailFor(PrimErrNotFound);
  	}
  	address = ioLoadSymbolOfLengthFromModule(((sqInt) (firstIndexableField(symbol))), byteSizeOf(symbol), moduleHandle);
  	if ((failed())
  	 || (address == 0)) {
  		return primitiveFailFor(PrimErrNotFound);
  	}
  	oop = instantiateClassindexableSize(classExternalAddress(), sizeof(void *));
  	ptr = firstIndexableField(oop);
  	ptr[0] = address;
  	return methodReturnValue(oop);
  }
  
  
  /*	Enable logging of FFI calls by providing it with a log file name. */
  
  	/* ThreadedFFIPlugin>>#primitiveLogCallsTo */
  EXPORT(sqInt)
  primitiveLogCallsTo(void)
  {
  	return primitiveFail();
  }
  
  
  /*	Create a 'manual surface' data-structure. See the ExternalForm class in
  	the FFI package for example usage. */
  /*	arguments: name(type, stack offset)
  	surfaceID(Integer, 1)
  	ptr(uint32/uint64, 0) */
  
  	/* ThreadedFFIPlugin>>#primitiveSetManualSurfacePointer */
  EXPORT(sqInt)
  primitiveSetManualSurfacePointer(void)
  {
      usqIntptr_t ptr;
      sqInt result;
      sqInt surfaceID;
  
  	if (!((methodArgumentCount()) == 2)) {
  		return primitiveFail();
  	}
  	surfaceID = stackIntegerValue(1);
  	ptr = positiveMachineIntegerValueOf(stackValue(0));
  	if (failed()) {
  		return null;
  	}
  	result = setManualSurfacePointer(surfaceID, ((void *)ptr));
  	if (result == 0) {
  		return primitiveFail();
  	}
  	return pop(2);
  }
  
  
  /*	Answer if a struct result of a given size is able to be returned in
  	registers. NB: this is a predicate! #returnStructInRegisters: does NOT
  	return a struct in anything!
   */
  
  	/* ThreadedARM64FFIPlugin>>#returnStructInRegisters: */
  static sqInt
  returnStructInRegisters(sqInt returnStructSize)
  {
  	return returnStructSize <= (2 * BytesPerWord);
  }
  
  
  /*	Note: This is coded so that it can be run in Squeak. */
  /*	Initialization of the plugin in the simulator.
  	The real routine is in the superclass. */
  
  	/* ThreadedFFIPlugin>>#setInterpreter: */
  EXPORT(sqInt)
  setInterpreter(struct VirtualMachine *anInterpreter)
  {
      sqInt ok;
  
  	interpreterProxy = anInterpreter;
  	ok = ((interpreterProxy->majorVersion()) == (VM_PROXY_MAJOR))
  	 && ((interpreterProxy->minorVersion()) >= (VM_PROXY_MINOR));
  	if (ok) {
  		
  #if !defined(SQUEAK_BUILTIN_PLUGIN)
  		booleanValueOf = interpreterProxy->booleanValueOf;
  		byteSizeOf = interpreterProxy->byteSizeOf;
  #if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
  		characterObjectOf = interpreterProxy->characterObjectOf;
  #else
  #if !defined(characterObjectOf)
  		characterObjectOf = 0;
  #endif
  #endif
  #if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
  		characterValueOf = interpreterProxy->characterValueOf;
  #else
  #if !defined(characterValueOf)
  		characterValueOf = 0;
  #endif
  #endif
  		classAlien = interpreterProxy->classAlien;
  		classByteArray = interpreterProxy->classByteArray;
  		classExternalAddress = interpreterProxy->classExternalAddress;
  		classExternalData = interpreterProxy->classExternalData;
  		classExternalFunction = interpreterProxy->classExternalFunction;
  		classExternalLibrary = interpreterProxy->classExternalLibrary;
  		classExternalStructure = interpreterProxy->classExternalStructure;
  		classLargePositiveInteger = interpreterProxy->classLargePositiveInteger;
  		classString = interpreterProxy->classString;
  		disownVM = interpreterProxy->disownVM;
  		failed = interpreterProxy->failed;
  		falseObject = interpreterProxy->falseObject;
  		fetchClassOf = interpreterProxy->fetchClassOf;
  		fetchIntegerofObject = interpreterProxy->fetchIntegerofObject;
  		fetchLong32ofObject = interpreterProxy->fetchLong32ofObject;
  		fetchPointerofObject = interpreterProxy->fetchPointerofObject;
  		firstIndexableField = interpreterProxy->firstIndexableField;
  		floatObjectOf = interpreterProxy->floatObjectOf;
  		floatValueOf = interpreterProxy->floatValueOf;
  		includesBehaviorThatOf = interpreterProxy->includesBehaviorThatOf;
  		instanceSizeOf = interpreterProxy->instanceSizeOf;
  		instantiateClassindexableSize = interpreterProxy->instantiateClassindexableSize;
  		integerObjectOf = interpreterProxy->integerObjectOf;
  		integerValueOf = interpreterProxy->integerValueOf;
  		ioLoadModuleOfLength = interpreterProxy->ioLoadModuleOfLength;
  		ioLoadSymbolOfLengthFromModule = interpreterProxy->ioLoadSymbolOfLengthFromModule;
  		isKindOfClass = interpreterProxy->isKindOfClass;
  		isArray = interpreterProxy->isArray;
  		isBytes = interpreterProxy->isBytes;
  #if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
  		isCharacterObject = interpreterProxy->isCharacterObject;
  #else
  #if !defined(isCharacterObject)
  		isCharacterObject = 0;
  #endif
  #endif
  		isFloatObject = interpreterProxy->isFloatObject;
  #if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
  		isImmediate = interpreterProxy->isImmediate;
  #else
  #if !defined(isImmediate)
  		isImmediate = 0;
  #endif
  #endif
  		isInMemory = interpreterProxy->isInMemory;
  		isIntegerObject = interpreterProxy->isIntegerObject;
  		isPointers = interpreterProxy->isPointers;
  		isWords = interpreterProxy->isWords;
  		isYoung = interpreterProxy->isYoung;
  		literalofMethod = interpreterProxy->literalofMethod;
  		literalCountOf = interpreterProxy->literalCountOf;
  		methodArgumentCount = interpreterProxy->methodArgumentCount;
  		methodReturnInteger = interpreterProxy->methodReturnInteger;
  		methodReturnValue = interpreterProxy->methodReturnValue;
  		nilObject = interpreterProxy->nilObject;
  		ownVM = interpreterProxy->ownVM;
  		pop = interpreterProxy->pop;
  		popthenPush = interpreterProxy->popthenPush;
  		popRemappableOop = interpreterProxy->popRemappableOop;
  		positive32BitIntegerFor = interpreterProxy->positive32BitIntegerFor;
  		positive32BitValueOf = interpreterProxy->positive32BitValueOf;
  		positive64BitIntegerFor = interpreterProxy->positive64BitIntegerFor;
  		positive64BitValueOf = interpreterProxy->positive64BitValueOf;
  		positiveMachineIntegerValueOf = interpreterProxy->positiveMachineIntegerValueOf;
  		primitiveErrorTable = interpreterProxy->primitiveErrorTable;
  		primitiveFail = interpreterProxy->primitiveFail;
  		primitiveFailFor = interpreterProxy->primitiveFailFor;
  		primitiveMethod = interpreterProxy->primitiveMethod;
  		pushFloat = interpreterProxy->pushFloat;
  		pushRemappableOop = interpreterProxy->pushRemappableOop;
  		signed32BitIntegerFor = interpreterProxy->signed32BitIntegerFor;
  		signed64BitIntegerFor = interpreterProxy->signed64BitIntegerFor;
  		signed64BitValueOf = interpreterProxy->signed64BitValueOf;
  		signedMachineIntegerValueOf = interpreterProxy->signedMachineIntegerValueOf;
  		slotSizeOf = interpreterProxy->slotSizeOf;
  		stackIntegerValue = interpreterProxy->stackIntegerValue;
  		stackObjectValue = interpreterProxy->stackObjectValue;
  		stackValue = interpreterProxy->stackValue;
  		storeIntegerofObjectwithValue = interpreterProxy->storeIntegerofObjectwithValue;
  		storePointerofObjectwithValue = interpreterProxy->storePointerofObjectwithValue;
  		tenuringIncrementalGC = interpreterProxy->tenuringIncrementalGC;
  		trueObject = interpreterProxy->trueObject;
  #endif /* !defined(SQUEAK_BUILTIN_PLUGIN) */
  	}
  	return ok;
  }
  
  	/* ThreadedARM64FFIPlugin>>#setReturnRegister:andCall:withArgsArray: */
  static sqInt
  setReturnRegisterandCallwithArgsArray(sqLong structAddr, sqLong procAddr, sqLong arrayAddr)
  {
      extern void callAndReturnWithStructAddr(sqLong structAddr,sqLong procAddr,sqLong arrayAddr);
  
  	callAndReturnWithStructAddr(structAddr, procAddr, arrayAddr);
  	return 0;
  }
  
  
  /*	Answer the first field of oop which is assumed to be an Alien of at least
  	8 bytes
   */
  
  	/* ThreadedFFIPlugin>>#sizeField: */
  static sqInt
  sizeField(sqInt oop)
  {
  	return longAt(oop + BaseHeaderSize);
  }
  
  
  /*	<Alien oop> ^<Integer> */
  /*	Answer the start of oop's data. For direct aliens this is the address of
  	the second field. For indirect and pointer aliens it is what the second
  	field points to. */
  
  	/* ThreadedFFIPlugin>>#startOfData: */
  static sqInt
  startOfData(sqInt oop)
  {
  	return ((longAt(oop + BaseHeaderSize)) > 0
  		? (oop + BaseHeaderSize) + BytesPerOop
  		: longAt((oop + BaseHeaderSize) + BytesPerOop));
  }
  
  
  #ifdef SQUEAK_BUILTIN_PLUGIN
  
  static char _m[] = "SqueakFFIPrims";
  void* ARM64FFIPlugin_exports[][3] = {
  	{(void*)_m, "ffiLogCallsTo", (void*)ffiLogCallsTo},
  	{(void*)_m, "getModuleName", (void*)getModuleName},
  	{(void*)_m, "initialiseModule", (void*)initialiseModule},
  	{(void*)_m, "primitiveCallout\000\002", (void*)primitiveCallout},
  	{(void*)_m, "primitiveCalloutWithArgs\000\004", (void*)primitiveCalloutWithArgs},
  	{(void*)_m, "primitiveCreateManualSurface\000\000", (void*)primitiveCreateManualSurface},
  	{(void*)_m, "primitiveDestroyManualSurface\000\000", (void*)primitiveDestroyManualSurface},
  	{(void*)_m, "primitiveFFIAllocate\000\001", (void*)primitiveFFIAllocate},
  	{(void*)_m, "primitiveFFIDoubleAt\000\001", (void*)primitiveFFIDoubleAt},
  	{(void*)_m, "primitiveFFIDoubleAtPut\000\001", (void*)primitiveFFIDoubleAtPut},
  	{(void*)_m, "primitiveFFIFloatAt\000\001", (void*)primitiveFFIFloatAt},
  	{(void*)_m, "primitiveFFIFloatAtPut\000\001", (void*)primitiveFFIFloatAtPut},
  	{(void*)_m, "primitiveFFIFree\000\001", (void*)primitiveFFIFree},
  	{(void*)_m, "primitiveFFIGetLastError\000\377", (void*)primitiveFFIGetLastError},
  	{(void*)_m, "primitiveFFIIntegerAt\000\001", (void*)primitiveFFIIntegerAt},
  	{(void*)_m, "primitiveFFIIntegerAtPut\000\001", (void*)primitiveFFIIntegerAtPut},
  	{(void*)_m, "primitiveForceLoad\000\002", (void*)primitiveForceLoad},
  	{(void*)_m, "primitiveLoadSymbolFromModule\000\002", (void*)primitiveLoadSymbolFromModule},
  	{(void*)_m, "primitiveLogCallsTo\000\000", (void*)primitiveLogCallsTo},
  	{(void*)_m, "primitiveSetManualSurfacePointer\000\000", (void*)primitiveSetManualSurfacePointer},
  	{(void*)_m, "setInterpreter", (void*)setInterpreter},
  	{NULL, NULL, NULL}
  };
  
  #else /* ifdef SQ_BUILTIN_PLUGIN */
  
  EXPORT(signed char) primitiveCalloutAccessorDepth = 2;
  EXPORT(signed char) primitiveCalloutWithArgsAccessorDepth = 4;
  EXPORT(signed char) primitiveCreateManualSurfaceAccessorDepth = 0;
  EXPORT(signed char) primitiveDestroyManualSurfaceAccessorDepth = 0;
  EXPORT(signed char) primitiveFFIAllocateAccessorDepth = 1;
  EXPORT(signed char) primitiveFFIDoubleAtAccessorDepth = 1;
  EXPORT(signed char) primitiveFFIDoubleAtPutAccessorDepth = 1;
  EXPORT(signed char) primitiveFFIFloatAtAccessorDepth = 1;
  EXPORT(signed char) primitiveFFIFloatAtPutAccessorDepth = 1;
  EXPORT(signed char) primitiveFFIFreeAccessorDepth = 1;
  EXPORT(signed char) primitiveFFIIntegerAtAccessorDepth = 1;
  EXPORT(signed char) primitiveFFIIntegerAtPutAccessorDepth = 1;
  EXPORT(signed char) primitiveForceLoadAccessorDepth = 2;
  EXPORT(signed char) primitiveLoadSymbolFromModuleAccessorDepth = 2;
  EXPORT(signed char) primitiveLogCallsToAccessorDepth = 0;
  EXPORT(signed char) primitiveSetManualSurfacePointerAccessorDepth = 0;
  
  #endif /* ifdef SQ_BUILTIN_PLUGIN */
  