text: /* Automatically generated by
  	VMPluginCodeGenerator VMMaker.oscog-eem.2944 uuid: 242b00d2-2d09-4363-8f25-cedcd6ee2187
     from
  	ThreadedARM64FFIPlugin VMMaker.oscog-eem.2944 uuid: 242b00d2-2d09-4363-8f25-cedcd6ee2187
   */
  static char __buildInfo[] = "ThreadedARM64FFIPlugin VMMaker.oscog-eem.2944 uuid: 242b00d2-2d09-4363-8f25-cedcd6ee2187 " __DATE__ ;
  
  
  #include "config.h"
  #include <math.h>
  #include "sqMathShim.h"
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <time.h>
  
  /* 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 "sqMemoryAccess.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
  # define INT_EXT "(i)"
  #else
  # define INT_EXT "(e)"
  #endif
  
  
  /* 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(setsp) && defined(__GNUC__)
  # if defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__)
  #	define setsp(spval) asm volatile ("movl %0,%%esp" : : "m"(spval))
  # elif defined(__amd64__) || defined(__x86_64__) ||  defined(__amd64) || defined(__x86_64)
  #	define setsp(spval) asm volatile ("movq %0,%%rsp" : : "m"(spval))
  # 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
           */
  #	define setsp(spval) asm volatile ("mov sp, %0"  : : "r"(spval))
  # elif defined(__arm__)
  #	define setsp(spval) asm volatile ("ldr %%sp, %0" : : "m"(spval))
  # endif
  #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
  
  /* The dispatchOn:in:with:with: generates an unwanted call on error.  Just squash it. */
  #define error(foo) 0
  
  /* 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 FFITypeUnsignedLongLong 8
  #define FFITypeUnsignedShort 4
  #define FFITypeVoid 0
  #define MaxNumArgs 15
  #define NumFloatRegArgs 8
  #define NumIntRegArgs 8
  #define PluginVersionInfo " VMMaker.oscog-eem.2944"
  #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 0
  #endif
  
  typedef struct {
  	char *argVector;
  	char *currentArg;
  	char *limit;
  	sqInt	structReturnSize;
  	sqInt	structReturnType;
  	sqInt	callFlags;
  	unsigned int *ffiArgSpec;
  	sqInt	ffiArgSpecSize;
  	sqInt	ffiArgHeader;
  	sqInt	ffiRetHeader;
  	sqInt	ffiRetSpec;
  	sqInt	stringArgIndex;
  	char *stringArgs[MaxNumArgs];
  	sqInt	integerRegisterIndex;
  	sqInt	floatRegisterIndex;
  	sqInt		integerRegisters[NumIntRegArgs];
  	double		floatRegisters[NumFloatRegArgs];
   } CalloutState;
  
  #define ThreadedFFICalloutStateForARM64 CalloutState
  #define ThreadedFFICalloutState CalloutState
  
  
  typedef struct { char pad_to_misalgnment; char element; } structByte;
  
  typedef struct { char pad_to_misalgnment; short element; } structShort;
  
  typedef struct { char pad_to_misalgnment; int element; } structInt;
  
  typedef struct { char pad_to_misalgnment; long long element; } structLongLong;
  
  typedef struct { char pad_to_misalgnment; float element; } structFloat;
  
  typedef struct { char pad_to_misalgnment; double element; } structDouble;
  
  typedef struct { char pad_to_misalgnment; struct {char c; } element; } structStruct;
  
  
  
  
  /*** Function Prototypes ***/
  static sqInt alignmentOfStructSpecOfLengthStartingAt(unsigned int *specs, sqInt specSize, sqInt *indexPtr);
  static sqInt atomicTypeOf(sqInt typeSpec);
  static sqInt canReturnInRegistersStructOfSize(sqInt returnStructSize);
  static sqInt checkAlignmentOfStructSpecOfLengthStartingAt(unsigned int *specs, sqInt specSize, sqInt startIndex);
  static sqInt checkAlignmentOfUnionSpecOfLengthStartingAt(unsigned int *specs, sqInt specSize, sqInt startIndex);
  static void cleanupCalloutState(CalloutState *calloutState);
  static sqInt encodeStructReturnTypeIn(CalloutState *calloutState);
  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 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, unsigned int *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(void *longLongRetPtr, 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 oop);
  static sqInt isAtomicType(sqInt typeSpec);
  static sqInt isDirectAlien(sqInt oop);
  static sqInt isUnionSpecOfLengthStartingAt(unsigned int *specs, sqInt specSize, sqInt startIndex);
  static sqInt msg(char *s);
  static sqInt mustReturnStructOnStack(sqInt returnStructSize);
  static sqInt nonRegisterStructReturnIsViaImplicitFirstArgument(void);
  EXPORT(void) primitiveCallout(void);
  EXPORT(void) primitiveCalloutWithArgs(void);
  EXPORT(sqInt) primitiveCDataModel(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);
  EXPORT(sqInt) primitiveStructureElementAlignment(void);
  static sqInt returnStructInRegisters(CalloutState *calloutState);
  EXPORT(sqInt) setInterpreter(struct VirtualMachine *anInterpreter);
  static sqInt setReturnRegisterandCallwithArgsArray(sqLong structAddr, sqLong procAddr, sqLong arrayAddr);
  static sqInt sizeField(sqInt alienOop);
  static sqInt startOfData(sqInt alienOop);
  static sqInt structIsHomogenousFloatArrayOfSizetypeSpecofLength(sqInt structSize, unsigned int *argSpec, sqInt argSpecSize);
  
  
  /*** Variables ***/
  static sqInt externalFunctionInstSize;
  static sqInt ffiLastError;
  static sqInt ffiLogEnabled;
  
  #if defined(SQUEAK_BUILTIN_PLUGIN)
  
  # define isIntegerObject(oop) ((oop) & 1)
  # define integerObjectOf(value) ((((usqInt) value) << NumSmallIntegerTagBits) | 1)
  # define integerValueOf(oop) ((oop) >> NumSmallIntegerTagBits)
  
  # 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)(int 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);
  #if !defined(integerObjectOf)
  static sqInt (*integerObjectOf)(sqInt value);
  #endif
  #if !defined(integerValueOf)
  static sqInt (*integerValueOf)(sqInt oop);
  #endif
  static void * (*ioLoadModuleOfLength)(sqInt moduleNameIndex, sqInt moduleLength);
  static void * (*ioLoadSymbolOfLengthFromModule)(sqInt functionNameIndex, sqInt functionLength, void *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);
  #if !defined(isImmediate)
  static sqInt (*isImmediate)(sqInt anObject);
  #endif
  static sqInt (*isInMemory)(sqInt address);
  #if !defined(isIntegerObject)
  static sqInt (*isIntegerObject)(sqInt objectPointer);
  #endif
  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 (*methodReturnFloat)(double aFloat);
  static sqInt (*methodReturnInteger)(sqInt integer);
  static sqInt (*methodReturnString)(char *aCString);
  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 (*primitiveFailForOSError)(sqLong osError);
  static sqInt (*primitiveMethod)(void);
  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(int 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);
  #if !defined(integerObjectOf)
  extern sqInt integerObjectOf(sqInt value);
  #endif
  #if !defined(integerValueOf)
  extern sqInt integerValueOf(sqInt oop);
  #endif
  extern void * ioLoadModuleOfLength(sqInt moduleNameIndex, sqInt moduleLength);
  extern void * ioLoadSymbolOfLengthFromModule(sqInt functionNameIndex, sqInt functionLength, void *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 methodReturnFloat(double aFloat);
  extern sqInt methodReturnInteger(sqInt integer);
  extern sqInt methodReturnString(char *aCString);
  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);
  #if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 14)
  extern sqInt primitiveFailForOSError(sqLong osError);
  #else
  # define primitiveFailForOSError(osError) 0
  #endif
  extern sqInt primitiveMethod(void);
  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 = "ARM64FFIPlugin VMMaker.oscog-eem.2944 " INT_EXT;
  
  
  /*** 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
  #define unalignedLong32At(index) long32At(index)
  #define unalignedLong32Atput(index,value) long32Atput(index,value)
  #define unalignedLong64At(index) long64At(index)
  #define unalignedLong64Atput(index,value) long64Atput(index,value)
  #define unalignedShortAt(index) shortAt(index)
  #define unalignedShortAtput(index,value) shortAtput(index,value)
  
  
  
  /*	Answer with the alignment requirement for a structure/union.
  	Note that indexPtr is a pointer so as to be changed on return.
  	On input, the index points to the structure header (the one with
  	FFIFlagStructure + structSize).
  	On output, the index points the the structure trailer (the
  	FFIFlagStructure). 
   */
  
  	/* ThreadedFFIPlugin>>#alignmentOfStructSpec:OfLength:StartingAt: */
  static sqInt
  alignmentOfStructSpecOfLengthStartingAt(unsigned int *specs, sqInt specSize, sqInt *indexPtr)
  {
      sqInt byteAlignment;
      unsigned int spec;
      sqInt thisAlignment;
  
  	spec = specs[indexPtr[0]];
  	assert((spec & ((FFIFlagPointer + FFIFlagAtomic) + FFIFlagStructure)) == FFIFlagStructure);
  	byteAlignment = 1;
  	while (1) {
  		indexPtr[0] = ((indexPtr[0]) + 1);
  		if (!((indexPtr[0]) < specSize)) break;
  		spec = specs[indexPtr[0]];
  		if (spec == FFIFlagStructure) {
  			return byteAlignment;
  		}
  		thisAlignment = (spec & FFIFlagPointer
  			? BytesPerWord
  			: (spec & FFIFlagStructure
  					? alignmentOfStructSpecOfLengthStartingAt(specs, specSize, indexPtr)
  					: spec & FFIStructSizeMask));
  		byteAlignment = ((byteAlignment < thisAlignment) ? thisAlignment : byteAlignment);
  	}
  	assert(0);
  	return byteAlignment;
  }
  
  	/* ThreadedFFIPlugin>>#atomicTypeOf: */
  static sqInt
  atomicTypeOf(sqInt typeSpec)
  {
  	return ((usqInt)((typeSpec & FFIAtomicTypeMask))) >> FFIAtomicTypeShift;
  }
  
  
  /*	Answer if a struct result of a given size is able to be returned in
  	registers. NB: this is a predicate! #canReturnInRegistersStructOfSize:
  	does NOT return a struct in anything!
   */
  
  	/* ThreadedARM64FFIPlugin>>#canReturnInRegistersStructOfSize: */
  static sqInt
  canReturnInRegistersStructOfSize(sqInt returnStructSize)
  {
  	return returnStructSize <= (2 * BytesPerWord);
  }
  
  
  /*	Check the alignment of a structure and return true if correctly aligned.
  	If computed size = declared size, then the struct is assumed correctly
  	aligned. 
   */
  
  	/* ThreadedFFIPlugin>>#checkAlignmentOfStructSpec:OfLength:StartingAt: */
  static sqInt
  checkAlignmentOfStructSpecOfLengthStartingAt(unsigned int *specs, sqInt specSize, sqInt startIndex)
  {
      sqInt computedSize;
      unsigned int declaredSize;
      sqInt fieldAlignment;
      sqInt fieldSize;
      sqInt index;
      sqInt maxAlignment;
      unsigned int spec;
  
  	index = startIndex;
  	spec = specs[index];
  	assert((spec & ((FFIFlagPointer + FFIFlagAtomic) + FFIFlagStructure)) == FFIFlagStructure);
  	if (isUnionSpecOfLengthStartingAt(specs, specSize, index)) {
  		return checkAlignmentOfUnionSpecOfLengthStartingAt(specs, specSize, startIndex);
  	}
  	declaredSize = spec & FFIStructSizeMask;
  	computedSize = 0;
  	maxAlignment = 1;
  	while (((index += 1)) < specSize) {
  		spec = specs[index];
  		if (spec == FFIFlagStructure) {
  			return (((computedSize - 1) | (maxAlignment - 1)) + 1) == declaredSize;
  		}
  		if (spec & FFIFlagPointer) {
  			fieldSize = BytesPerWord;
  			fieldAlignment = fieldSize;
  		}
  		else {
  			fieldSize = spec & FFIStructSizeMask;
  			if (spec & FFIFlagStructure) {
  				if (!(checkAlignmentOfStructSpecOfLengthStartingAt(specs, specSize, index))) {
  					return 0;
  				}
  				fieldAlignment = alignmentOfStructSpecOfLengthStartingAt(specs, specSize, (&index));
  			}
  			else {
  				fieldAlignment = fieldSize;
  			}
  		}
  		maxAlignment = ((maxAlignment < fieldAlignment) ? fieldAlignment : maxAlignment);
  		computedSize = ((computedSize - 1) | (fieldAlignment - 1)) + 1;
  		computedSize += fieldSize;
  	}
  	return (((computedSize - 1) | (maxAlignment - 1)) + 1) == declaredSize;
  }
  
  
  /*	Check the alignment of a union and return true if correctly aligned.
  	Union are correctly aligned, but a sub-structure might not. */
  
  	/* ThreadedFFIPlugin>>#checkAlignmentOfUnionSpec:OfLength:StartingAt: */
  static sqInt
  checkAlignmentOfUnionSpecOfLengthStartingAt(unsigned int *specs, sqInt specSize, sqInt startIndex)
  {
      sqInt index;
      unsigned int spec;
  
  	index = startIndex;
  	spec = specs[index];
  	while (1) {
  		index += 1;
  		if (!(index < specSize)) break;
  		spec = specs[index];
  		if (spec == FFIFlagStructure) {
  			return 1;
  		}
  		if (!(spec & FFIFlagPointer)) {
  			if (spec & FFIFlagStructure) {
  				if (!(checkAlignmentOfStructSpecOfLengthStartingAt(specs, specSize, index))) {
  					return 0;
  				}
  			}
  		}
  	}
  	return 1;
  }
  
  
  /*	Free any temporary arg strings. */
  
  	/* ThreadedFFIPlugin>>#cleanupCalloutState: */
  static void
  cleanupCalloutState(CalloutState *calloutState)
  {
  	while (((calloutState->stringArgIndex)) > 0) {
  		free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
  	}
  }
  
  
  /*	Set the return type to true if returning the struct via register */
  
  	/* ThreadedARM64FFIPlugin>>#encodeStructReturnTypeIn: */
  static sqInt
  encodeStructReturnTypeIn(CalloutState *calloutState)
  {
  	(calloutState->structReturnType = ((calloutState->structReturnSize)) <= (2 * BytesPerWord));
  	return 0;
  }
  
  
  /*	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
  				if (isCharacterObject(oop)) {
  					intValue = characterValueOf(oop);
  					goto l2;
  				}
  #        endif
  				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
  				}
  			}
  			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)])))) = 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 argIsAlien;
      unsigned int *argSpec1;
      unsigned int *argSpec2;
      sqInt argSpecSize;
      sqInt argSpecSize1;
      sqInt atomicType;
      sqInt atomicType1;
      sqInt atomicType2;
      sqInt availableRegisterSpace;
      sqInt availableRegisterSpace1;
      char *copy;
      sqInt err;
      double floatValue;
      sqInt intValue;
      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 general instance 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;
  		}
  	}
  
  	/* Fetch and check the contents of the compiled spec */
  	valueOop = (isStruct
  		? fetchPointerofObject(0, oop)
  		: oop);
  	if (!(isWords(argSpec))) {
  		return FFIErrorWrongType;
  	}
  	(calloutState->ffiArgSpecSize = (byteSizeOf(argSpec)) / (sizeof(unsigned int)));
  	if (((calloutState->ffiArgSpecSize)) == 0) {
  		return FFIErrorWrongType;
  	}
  	(calloutState->ffiArgSpec = ((unsigned int *) (firstIndexableField(argSpec))));
  	(calloutState->ffiArgHeader = ((calloutState->ffiArgSpec))[0]);
  	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(((usqIntptr_t)ptrAddress))) {
  				return FFIErrorInvalidPointer;
  			}
  			/* begin ffiPushStructure:ofSize:typeSpec:ofLength:in: */
  			structSize = ((calloutState->ffiArgHeader)) & FFIStructSizeMask;
  			argSpec2 = (calloutState->ffiArgSpec);
  			argSpecSize = (calloutState->ffiArgSpecSize);
  			if (structIsHomogenousFloatArrayOfSizetypeSpecofLength(structSize, argSpec2, argSpecSize)) {
  				availableRegisterSpace = (NumFloatRegArgs - ((calloutState->floatRegisterIndex))) * BytesPerWord;
  				if (structSize <= availableRegisterSpace) {
  
  					/* Stage C, step C.2, all in floating-point registers (!!) */
  					memcpy(((void *) ((&(((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)])))), ptrAddress, structSize);
  					(calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + ((((usqInt)((structSize + 7))) >> 3)));
  					return 0;
  				}
  				availableRegisterSpace = 0;
  				(calloutState->floatRegisterIndex = 8);
  			}
  			else {
  				availableRegisterSpace = (NumIntRegArgs - ((calloutState->integerRegisterIndex))) * BytesPerWord;
  			}
  			stackPartSize = structSize;
  			if (availableRegisterSpace > 0) {
  				if (structSize <= availableRegisterSpace) {
  
  					/* all in integer registers */
  					memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ptrAddress, structSize);
  					(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + ((((usqInt)((structSize + 7))) >> 3)));
  					return 0;
  				}
  				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);
  				if (structIsHomogenousFloatArrayOfSizetypeSpecofLength(structSize1, argSpec1, argSpecSize1)) {
  					availableRegisterSpace1 = (NumFloatRegArgs - ((calloutState->floatRegisterIndex))) * BytesPerWord;
  					if (structSize1 <= availableRegisterSpace1) {
  
  						/* Stage C, step C.2, all in floating-point registers (!!) */
  						memcpy(((void *) ((&(((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)])))), ptrAddress, structSize1);
  						(calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + ((((usqInt)((structSize1 + 7))) >> 3)));
  						return 0;
  					}
  					availableRegisterSpace1 = 0;
  					(calloutState->floatRegisterIndex = 8);
  				}
  				else {
  					availableRegisterSpace1 = (NumIntRegArgs - ((calloutState->integerRegisterIndex))) * BytesPerWord;
  				}
  				stackPartSize1 = structSize1;
  				if (availableRegisterSpace1 > 0) {
  					if (structSize1 <= availableRegisterSpace1) {
  
  						/* all in integer registers */
  						memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ptrAddress, structSize1);
  						(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + ((((usqInt)((structSize1 + 7))) >> 3)));
  						return 0;
  					}
  					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(((usqIntptr_t)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) {
  			if (isStruct) {
  
  				/* e.g., ExternalData */
  				/* 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);
  			}
  			/* begin ffiAtomicArgByReference:Class:in: */
  			typeSpec1 = (calloutState->ffiArgHeader);
  			atomicType1 = ((usqInt)((typeSpec1 & FFIAtomicTypeMask))) >> FFIAtomicTypeShift;
  			if (atomicType1 == FFITypeBool) {
  
  				/* No bools on input */
  				return FFIErrorCoercionFailed;
  			}
  			argIsAlien = ((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 = 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)
  			 && (((!argIsAlien)
  			 || ((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 = 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 (argIsAlien) {
  					/* 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 = 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 (argIsAlien) {
  					/* 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 ffiPushPointerContentsOfin(valueOop, calloutState);
  		}
  		return FFIErrorCoercionFailed;
  	}
  	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
  					if (isCharacterObject(valueOop)) {
  						intValue = characterValueOf(valueOop);
  						goto l7;
  					}
  #          endif
  					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
  					}
  				}
  				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)])))) = 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 argIsAlien;
      sqInt atomicType;
      char *copy;
      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;
  	}
  	argIsAlien = ((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 = 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)
  	 && (((!argIsAlien)
  	 || ((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 = 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 (argIsAlien) {
  			/* 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 = 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 (argIsAlien) {
  			/* 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);
  }
  
  
  /*	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;
      sqInt argTypes2;
      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 ffiRetType1;
      sqInt flags;
      union { struct { float floats[8]; } f; struct dprr { double doubles[4]; } d; } floatRet;
      sqInt functionName;
      sqInt i;
      sqInt i1;
      usqLong intRet;
      extern void loadFloatRegs(double, double, double, double, double, double, double, double);
      void *longLongRetPtr;
      void *longLongRetPtr1;
      usqLong mask;
      sqInt myThreadIndex;
      sqInt oop;
      sqInt oop1;
      sqInt oop2;
      sqInt oop3;
      sqInt primNumArgs;
      sqIntptr_t *ptr;
      sqInt *ptr1;
      sqInt requiredStackSize;
      sqInt result;
      sqInt retClass;
      sqInt retClass1;
      sqInt retClass2;
      sqInt retOop;
      sqInt retOop1;
      sqInt retOop2;
      sqInt retType;
      extern sqLong returnX1value();
      sqInt shift;
      sqInt specLiteral;
      sqInt specLiteral1;
      sqInt specLiteral2;
      sqInt specSize;
      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) {
  			storeIntegerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, -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
  			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
  		);
  	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))
  	 || (((((calloutState->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) == FFIFlagStructure)
  	 && (structIsHomogenousFloatArrayOfSizetypeSpecofLength(((calloutState->ffiRetHeader)) & FFIStructSizeMask, ((unsigned int *) (firstIndexableField((calloutState->ffiRetSpec)))), ((specSize = byteSizeOf((calloutState->ffiRetSpec)))) / (sizeof(unsigned int)))))) {
  		(floatRet.d = dispatchFunctionPointerwithwithwithwithwithwithwithwith(((struct dprr (*)(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);
  		if (atomicType == FFITypeDoubleFloat) {
  			result = floatObjectOf(((((floatRet.d)).doubles))[0]);
  			goto l10;
  		}
  		if (atomicType == FFITypeSingleFloat) {
  			result = floatObjectOf(((((floatRet.f)).floats))[0]);
  			goto l10;
  		}
  		if (specSize > ((calloutState->structReturnSize))) {
  			((((floatRet.f)).floats))[1] = (((((floatRet.f)).floats))[2]);
  			((((floatRet.f)).floats))[2] = (((((floatRet.f)).floats))[4]);
  			((((floatRet.f)).floats))[3] = (((((floatRet.f)).floats))[6]);
  		}
  		/* begin ffiReturnStruct:ofType:in: */
  		longLongRetPtr = (&floatRet);
  		/* begin ffiReturnType: */
  		specLiteral = (argArrayOrNil != null
  			? stackValue(1)
  			: literalofMethod(0, primitiveMethod()));
  		argTypes = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral);
  		ffiRetType = fetchPointerofObject(0, argTypes);
  		retClass = fetchPointerofObject(1, ffiRetType);
  		retOop = instantiateClassindexableSize(retClass, 0);
  		
  #if SPURVM
  		oop3 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  #else /* SPURVM */
  		pushRemappableOop(retOop);
  		oop3 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  		retOop = popRemappableOop();
  #endif /* SPURVM */
  		memcpy(firstIndexableField(oop3), longLongRetPtr, (calloutState->structReturnSize));
  		storePointerofObjectwithValue(0, retOop, oop3);
  		result = retOop;
  		goto l10;
  	}
  	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->structReturnType))) {
  
  		/* 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: */
  			specLiteral1 = (argArrayOrNil != null
  				? stackValue(1)
  				: literalofMethod(0, primitiveMethod()));
  			argTypes1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral1);
  			retType = fetchPointerofObject(0, argTypes1);
  			retClass1 = fetchPointerofObject(1, retType);
  			if (retClass1 == (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) {
  						retOop1 = nilObject();
  						goto l7;
  					}
  					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]);
  					}
  					retOop1 = strOop;
  	l7:	/* end ffiReturnCStringFrom: */;
  					result = retOop1;
  					goto l10;
  				}
  				
  #if SPURVM
  				oop1 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  				ptr1 = firstIndexableField(oop1);
  				ptr1[0] = (((sqInt) intRet));
  				retOop1 = instantiateClassindexableSize(classExternalData(), 0);
  				storePointerofObjectwithValue(0, retOop1, oop1);
  #else /* SPURVM */
  				pushRemappableOop(retType);
  				oop1 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
  				ptr1 = firstIndexableField(oop1);
  				ptr1[0] = (((sqInt) intRet));
  								pushRemappableOop(oop1);
  				retOop1 = instantiateClassindexableSize(classExternalData(), 0);
  				oop1 = popRemappableOop();
  				storePointerofObjectwithValue(0, retOop1, oop1);
  				retType = popRemappableOop();
  #endif /* SPURVM */
  				storePointerofObjectwithValue(1, retOop1, retType);
  				result = retOop1;
  				goto l10;
  			}
  			classOop = (((calloutState->ffiRetHeader)) & FFIFlagStructure
  				? classByteArray()
  				: classExternalAddress());
  			
  #if SPURVM
  			oop1 = instantiateClassindexableSize(classOop, BytesPerWord);
  #else /* SPURVM */
  			pushRemappableOop(retClass1);
  			oop1 = instantiateClassindexableSize(classOop, BytesPerWord);
  			retClass1 = popRemappableOop();
  #endif /* SPURVM */
  			ptr1 = firstIndexableField(oop1);
  			ptr1[0] = (((sqInt) intRet));
  			
  #if SPURVM
  			retOop1 = instantiateClassindexableSize(retClass1, 0);
  #else /* SPURVM */
  			pushRemappableOop(oop1);
  			retOop1 = instantiateClassindexableSize(retClass1, 0);
  			oop1 = popRemappableOop();
  #endif /* SPURVM */
  			storePointerofObjectwithValue(0, retOop1, oop1);
  			result = retOop1;
  			goto l10;
  		}
  		/* begin ffiReturnStruct:ofType:in: */
  		longLongRetPtr1 = ((calloutState->structReturnType)
  			? (&((calloutState->integerRegisters)))
  			: (calloutState->limit));
  		/* begin ffiReturnType: */
  		specLiteral2 = (argArrayOrNil != null
  			? stackValue(1)
  			: literalofMethod(0, primitiveMethod()));
  		argTypes2 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral2);
  		ffiRetType1 = fetchPointerofObject(0, argTypes2);
  		retClass2 = fetchPointerofObject(1, ffiRetType1);
  		retOop2 = instantiateClassindexableSize(retClass2, 0);
  		
  #if SPURVM
  		oop2 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  #else /* SPURVM */
  		pushRemappableOop(retOop2);
  		oop2 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
  		retOop2 = popRemappableOop();
  #endif /* SPURVM */
  		memcpy(firstIndexableField(oop2), longLongRetPtr1, (calloutState->structReturnSize));
  		storePointerofObjectwithValue(0, retOop2, oop2);
  		result = retOop2;
  		goto l10;
  	}
  	/* 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 l10;
  	}
  	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 l10;
  		}
  		if (atomicType & 1) {
  			/* begin signedMachineIntegerFor: */
  			result = (BytesPerWord == 8
  				? signed64BitIntegerFor(((sqIntptr_t) intRet))
  				: signed32BitIntegerFor(((sqIntptr_t) intRet)));
  		}
  		else {
  			/* begin positiveMachineIntegerFor: */
  			result = (BytesPerWord == 8
  				? positive64BitIntegerFor(((usqIntptr_t) intRet))
  				: positive32BitIntegerFor(((usqIntptr_t) intRet)));
  		}
  		goto l10;
  	}
  	if ((((usqInt)(atomicType)) >> 1) == (((usqInt)(FFITypeSignedLongLong)) >> 1)) {
  		result = (atomicType & 1
  			? signed64BitIntegerFor(intRet)
  			: positive64BitIntegerFor(intRet));
  		goto l10;
  	}
  #  if SPURVM
  	result = characterObjectOf(intRet & 0x3FFFFFFF);
  	goto l10;
  #  else
  	result = characterObjectOf(intRet & 0xFF);
  	goto l10;
  #  endif
  	result = null;
  	l10:	/* 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->ffiRetSpec = retSpec);
  	(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);
  		/* begin encodeStructReturnTypeIn: */
  		(calloutState->structReturnType = ((calloutState->structReturnSize)) <= (2 * BytesPerWord));
  	}
  	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
  			? (/* begin signedMachineIntegerFor: */
  				(BytesPerWord == 8
  						? signed64BitIntegerFor(((sqIntptr_t) retVal))
  						: signed32BitIntegerFor(((sqIntptr_t) retVal))))
  			: (/* begin positiveMachineIntegerFor: */
  				(BytesPerWord == 8
  						? positive64BitIntegerFor(((usqIntptr_t) retVal))
  						: positive32BitIntegerFor(((usqIntptr_t) retVal)))));
  	}
  	if ((((usqInt)(atomicType)) >> 1) == (((usqInt)(FFITypeSignedLongLong)) >> 1)) {
  		return (atomicType & 1
  			? signed64BitIntegerFor(retVal)
  			: positive64BitIntegerFor(retVal));
  	}
  #  if SPURVM
  	return characterObjectOf(retVal & 0x3FFFFFFF);
  #  else
  	return characterObjectOf(retVal & 0xFF);
  #  endif
  	return 0;
  }
  
  
  /*	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
  		if (isCharacterObject(oop)) {
  			return characterValueOf(oop);
  		}
  #    endif
  		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
  		}
  	}
  	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) {
  			storeIntegerofObjectwithValue(ExternalFunctionStackSizeIndex, lit, -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)
  {
      sqInt ok;
  
  	if (fileName == null) {
  
  		/* disable logging */
  		ok = ffiLogFileNameOfLength(null, 0);
  		if (!ok) {
  			return 0;
  		}
  		ffiLogEnabled = 0;
  	}
  	else {
  
  		/* enable logging */
  		ok = ffiLogFileNameOfLength(fileName, strlen(fileName));
  		if (!ok) {
  			return 0;
  		}
  		ffiLogEnabled = 1;
  	}
  	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(((usqIntptr_t)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 = ((void *) (((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)
  {
      unsigned int *argSpec;
      unsigned int *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(((usqIntptr_t)ptrAddress))) {
  			return FFIErrorInvalidPointer;
  		}
  		/* begin ffiPushStructure:ofSize:typeSpec:ofLength:in: */
  		structSize = ((calloutState->ffiArgHeader)) & FFIStructSizeMask;
  		argSpec = (calloutState->ffiArgSpec);
  		argSpecSize = (calloutState->ffiArgSpecSize);
  		if (structIsHomogenousFloatArrayOfSizetypeSpecofLength(structSize, argSpec, argSpecSize)) {
  			availableRegisterSpace = (NumFloatRegArgs - ((calloutState->floatRegisterIndex))) * BytesPerWord;
  			if (structSize <= availableRegisterSpace) {
  
  				/* Stage C, step C.2, all in floating-point registers (!!) */
  				memcpy(((void *) ((&(((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)])))), ptrAddress, structSize);
  				(calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + ((((usqInt)((structSize + 7))) >> 3)));
  				return 0;
  			}
  			availableRegisterSpace = 0;
  			(calloutState->floatRegisterIndex = 8);
  		}
  		else {
  			availableRegisterSpace = (NumIntRegArgs - ((calloutState->integerRegisterIndex))) * BytesPerWord;
  		}
  		stackPartSize = structSize;
  		if (availableRegisterSpace > 0) {
  			if (structSize <= availableRegisterSpace) {
  
  				/* all in integer registers */
  				memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ptrAddress, structSize);
  				(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + ((((usqInt)((structSize + 7))) >> 3)));
  				return 0;
  			}
  			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);
  			if (structIsHomogenousFloatArrayOfSizetypeSpecofLength(structSize1, argSpec1, argSpecSize1)) {
  				availableRegisterSpace1 = (NumFloatRegArgs - ((calloutState->floatRegisterIndex))) * BytesPerWord;
  				if (structSize1 <= availableRegisterSpace1) {
  
  					/* Stage C, step C.2, all in floating-point registers (!!) */
  					memcpy(((void *) ((&(((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)])))), ptrAddress, structSize1);
  					(calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + ((((usqInt)((structSize1 + 7))) >> 3)));
  					return 0;
  				}
  				availableRegisterSpace1 = 0;
  				(calloutState->floatRegisterIndex = 8);
  			}
  			else {
  				availableRegisterSpace1 = (NumIntRegArgs - ((calloutState->integerRegisterIndex))) * BytesPerWord;
  			}
  			stackPartSize1 = structSize1;
  			if (availableRegisterSpace1 > 0) {
  				if (structSize1 <= availableRegisterSpace1) {
  
  					/* all in integer registers */
  					memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ptrAddress, structSize1);
  					(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + ((((usqInt)((structSize1 + 7))) >> 3)));
  					return 0;
  				}
  				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(((usqIntptr_t)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;
  }
  
  
  /*	See IHI0055B_aapcs64.pdf sections 4.3.5 & 5.4.2 Stage C; we don't yet
  	support HVA's
   */
  
  	/* ThreadedARM64FFIPlugin>>#ffiPushStructure:ofSize:typeSpec:ofLength:in: */
  static sqInt
  ffiPushStructureofSizetypeSpecofLengthin(void *pointer, sqInt structSize, unsigned int *argSpec, sqInt argSpecSize, CalloutState *calloutState)
  {
      sqInt availableRegisterSpace;
      sqInt roundedSize;
      sqInt stackPartSize;
  
  	if (structIsHomogenousFloatArrayOfSizetypeSpecofLength(structSize, argSpec, argSpecSize)) {
  		availableRegisterSpace = (NumFloatRegArgs - ((calloutState->floatRegisterIndex))) * BytesPerWord;
  		if (structSize <= availableRegisterSpace) {
  
  			/* Stage C, step C.2, all in floating-point registers (!!) */
  			memcpy(((void *) ((&(((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)])))), pointer, structSize);
  			(calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + ((((usqInt)((structSize + 7))) >> 3)));
  			return 0;
  		}
  		availableRegisterSpace = 0;
  		(calloutState->floatRegisterIndex = 8);
  	}
  	else {
  		availableRegisterSpace = (NumIntRegArgs - ((calloutState->integerRegisterIndex))) * BytesPerWord;
  	}
  	stackPartSize = structSize;
  	if (availableRegisterSpace > 0) {
  		if (structSize <= availableRegisterSpace) {
  
  			/* all in integer registers */
  			memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), pointer, structSize);
  			(calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + ((((usqInt)((structSize + 7))) >> 3)));
  			return 0;
  		}
  		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 integer
  	registers. 
   */
  
  	/* ThreadedARM64FFIPlugin>>#ffiReturnStruct:ofType:in: */
  static sqInt
  ffiReturnStructofTypein(void *longLongRetPtr, 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), longLongRetPtr, (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" PluginVersionInfo;
  }
  
  	/* 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;
  }
  
  
  /*	Answer if oop is an Alien. We could ask if isWordsOrBytes: first, but that
  	doesn't help. We still have to do the is:KindOf: walk.
  	We're not interested in fast falsehood, but as fast as possible truth, and
  	with the current API this is it. */
  
  	/* InterpreterPlugin>>#isAlien: */
  static sqInt
  isAlien(sqInt oop)
  {
  	return isKindOfClass(oop, 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;
  }
  
  
  /*	We can't easily distinguish union from structures with available flags.
  	But we have a trick: a union should have one field size equal to its own
  	size. 
   */
  
  	/* ThreadedFFIPlugin>>#isUnionSpec:OfLength:StartingAt: */
  static sqInt
  isUnionSpecOfLengthStartingAt(unsigned int *specs, sqInt specSize, sqInt startIndex)
  {
      sqInt index;
      unsigned int spec;
      unsigned int thisSize;
      unsigned int unionSize;
  
  	index = startIndex;
  	spec = specs[index];
  	assert((spec & ((FFIFlagPointer + FFIFlagAtomic) + FFIFlagStructure)) == FFIFlagStructure);
  	unionSize = spec & FFIStructSizeMask;
  	while (1) {
  		index += 1;
  		if (!(index < specSize)) break;
  		spec = specs[index];
  		if (spec == FFIFlagStructure) {
  			return 0;
  		}
  		thisSize = spec & FFIStructSizeMask;
  		if (thisSize == unionSize) {
  			return 1;
  		}
  		if ((spec & (FFIFlagPointer + FFIFlagStructure)) == FFIFlagStructure) {
  
  			/* Asking for alignment is a trick for skipping this sub structure/union */
  			alignmentOfStructSpecOfLengthStartingAt(specs, specSize, (&index));
  		}
  	}
  	return 0;
  }
  
  	/* ThreadedFFIPlugin>>#msg: */
  static sqInt
  msg(char *s)
  {
  	fprintf(stderr, "\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 externalFunction;
      sqInt meth;
      sqInt nArgs;
      sqInt result;
      sqInt retryCount;
  
  	meth = primitiveMethod();
  	if (!((literalCountOf(meth)) > 0)) {
  		primitiveFailFor(PrimErrBadMethod);
  		return;
  	}
  	externalFunction = literalofMethod(0, meth);
  #  if COGMTVM
  	nArgs = methodArgumentCount();
  	retryCount = 0;
  	while (1) {
  		result = ffiCallArgArrayOrNilNumArgs(externalFunction, null, nArgs);
  		if (!((result == PrimErrObjectMayMove)
  		 && (((retryCount += 1)) <= (nArgs + 1)))) break;
  		tenuringIncrementalGC();
  	}
  #  else /* COGMTVM */
  	ffiCallArgArrayOrNilNumArgs(externalFunction, null, methodArgumentCount());
  #  endif
  	return;
  }
  
  
  /*	Perform a function call to a foreign function.
  	Only invoked from ExternalFunction>>invokeWithArguments: */
  
  	/* ThreadedFFIPlugin>>#primitiveCalloutWithArgs */
  EXPORT(void)
  primitiveCalloutWithArgs(void)
  {
      sqInt argArray;
      sqInt externalFunction;
      sqInt nArgs;
      sqInt result;
      sqInt retryCount;
  
  	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);
  		result = ffiCallArgArrayOrNilNumArgs(externalFunction, argArray, nArgs);
  		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);
  	ffiCallArgArrayOrNilNumArgs(externalFunction, argArray, nArgs);
  #  endif /* COGMTVM */
  	return;
  }
  
  
  /*	Two forms of C Data Model infomation.
  	With 0 arguments answer the string naming the C data model, LP32, LP64,
  	LLP64, etc.
  	WIth 1 argument, which must be a ByteArray of at least 9 elements, answer
  	the sizes of
  	char, short, int, long, long long, wchar_t, float, double, void *. */
  
  	/* ThreadedFFIPlugin>>#primitiveCDataModel */
  EXPORT(sqInt)
  primitiveCDataModel(void)
  {
      char * cascade0;
      sqInt errorCode;
      char * model;
      sqInt sizes;
  
  	model = ((char *) 0);
  	if ((methodArgumentCount()) == 1) {
  		sizes = stackValue(0);
  		if (!((isBytes(sizes))
  			 && ((slotSizeOf(sizes)) == 9))) {
  			return primitiveFailFor(PrimErrBadArgument);
  		}
  		cascade0 = ((char *) (firstIndexableField(sizes)));
  		cascade0[0] = (sizeof(char));
  		cascade0[1] = (sizeof(short));
  		cascade0[2] = (sizeof(int));
  		cascade0[3] = (sizeof(long));
  		cascade0[4] = (sizeof(long long));
  		cascade0[5] = (sizeof(wchar_t));
  		cascade0[6] = (sizeof(float));
  		cascade0[7] = (sizeof(double));
  		cascade0[8] = (sizeof(void *));
  		return methodReturnValue(sizes);
  	}
  	if (!((methodArgumentCount()) == 0)) {
  		return primitiveFailFor(PrimErrBadNumArgs);
  	}
  
  	/* Set bit 0 if char is wrong, bit 1 if short is wrong, 2 for int, 3 for long, 4 for long long, 5 for void * */
  	errorCode = 0;
  	if ((sizeof(char)) != 1) {
  		errorCode += 1;
  	}
  	if ((sizeof(short)) != 2) {
  
  		/* N.B. SILP64 exists on Cray supercomputers; we don't care... */
  		errorCode += 2;
  	}
  	if ((sizeof(long long)) != 8) {
  		errorCode += 16;
  	}
  	if ((sizeof(void *)) == 8) {
  
  		/* LP64 LLP64 ILP64 */
  		if ((sizeof(int)) == 8) {
  
  			/* ILP64 */
  			if ((sizeof(long)) == 8) {
  				model = "ILP64";
  			}
  			else {
  				errorCode += 8;
  			}
  		}
  		if ((sizeof(int)) == 4) {
  
  			/* LP64 or LLP64 */
  			if ((sizeof(long)) == 8) {
  
  				/* LP64 */
  				model = "LP64";
  			}
  			if ((sizeof(long)) == 4) {
  
  				/* LLP64 */
  				model = "LLP64";
  			}
  			if (((sizeof(long)) != 8)
  			 && ((sizeof(long)) != 4)) {
  				errorCode += 8;
  			}
  		}
  		if (((sizeof(int)) != 8)
  		 && ((sizeof(int)) != 4)) {
  			errorCode += 4;
  		}
  	}
  	if ((sizeof(void *)) == 4) {
  
  		/* LP32 ILP32 */
  		if ((sizeof(long)) != 4) {
  			errorCode += 8;
  		}
  		if ((sizeof(int)) == 4) {
  
  			/* ILP32 */
  			model = "ILP32";
  		}
  		if ((sizeof(int)) == 2) {
  
  			/* LP32 */
  			model = "LP32";
  		}
  		if (((sizeof(int)) != 4)
  		 && ((sizeof(int)) != 2)) {
  			errorCode += 4;
  		}
  	}
  	if (((sizeof(void *)) != 8)
  	 && ((sizeof(void *)) != 4)) {
  		errorCode += 32;
  	}
  	if (errorCode != 0) {
  		return primitiveFailForOSError(errorCode);
  	}
  	if (!model) {
  		return primitiveFailFor(PrimErrNotFound);
  	}
  	methodReturnString(model);
  	return 0;
  }
  
  
  /*	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));
  	methodReturnFloat(floatValue);
  	return 0;
  }
  
  
  /*	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));
  	methodReturnFloat(floatValue);
  	return 0;
  }
  
  
  /*	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(((usqIntptr_t)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)
  {
      sqInt logFile;
      sqInt ok;
  
  	if (!((methodArgumentCount()) == 1)) {
  		return primitiveFail();
  	}
  	logFile = stackValue(0);
  	if (logFile == (nilObject())) {
  
  		/* disable logging */
  		ok = ffiLogFileNameOfLength(null, 0);
  		if (!ok) {
  			return primitiveFail();
  		}
  		ffiLogEnabled = 0;
  	}
  	else {
  
  		/* enable logging */
  		if (!(isBytes(logFile))) {
  			return primitiveFail();
  		}
  		ok = ffiLogFileNameOfLength(firstIndexableField(logFile), byteSizeOf(logFile));
  		if (!ok) {
  			return primitiveFail();
  		}
  		ffiLogEnabled = 1;
  	}
  	return pop(1);
  }
  
  
  /*	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 the alignment of an element of an atomic type, or a structure,
  	within a structure on the current platform.
   */
  
  	/* ThreadedFFIPlugin>>#primitiveStructureElementAlignment */
  EXPORT(sqInt)
  primitiveStructureElementAlignment(void)
  {
      void *alignment;
      sqInt typeCode;
  
  	typeCode = stackValue(0);
  	if (!((isIntegerObject(typeCode))
  		 && ((((((typeCode = integerValueOf(typeCode))) >= FFITypeUnsignedByte) && (typeCode <= FFITypeDoubleFloat)))
  		 || (typeCode == FFIFlagStructure)))) {
  		return primitiveFailFor(PrimErrBadArgument);
  	}
  	switch (typeCode) {
  	case FFITypeUnsignedByte:
  	case FFITypeSignedByte:
  		alignment = (&(((((structByte *) 0))->element)));
  		break;
  
  	case FFITypeUnsignedShort:
  	case FFITypeSignedShort:
  		alignment = (&(((((structShort *) 0))->element)));
  		break;
  
  	case FFITypeUnsignedInt:
  	case FFITypeSignedInt:
  		alignment = (&(((((structInt *) 0))->element)));
  		break;
  
  	case FFITypeUnsignedLongLong:
  	case FFITypeSignedLongLong:
  		alignment = (&(((((structLongLong *) 0))->element)));
  		break;
  
  	case FFITypeSingleFloat:
  		alignment = (&(((((structFloat *) 0))->element)));
  		break;
  
  	case FFITypeDoubleFloat:
  		alignment = (&(((((structDouble *) 0))->element)));
  		break;
  
  	default:
  		alignment = (&(((((structStruct *) 0))->element)));;
  	}
  	return methodReturnInteger(((usqIntptr_t)alignment));
  }
  
  
  /*	Return thrue register if structReturnType is true */
  
  	/* ThreadedARM64FFIPlugin>>#returnStructInRegisters: */
  static sqInt
  returnStructInRegisters(CalloutState *calloutState)
  {
  	return (calloutState->structReturnType);
  }
  
  
  /*	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;
  
  
  	/* This may seem tautological, but in a real plugin it checks that the VM provides
  	   the version the plugin was compiled against which is the version the plugin expects. */
  	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;
  #if !defined(integerObjectOf)
  		integerObjectOf = interpreterProxy->integerObjectOf;
  #endif
  #if !defined(integerValueOf)
  		integerValueOf = interpreterProxy->integerValueOf;
  #endif
  		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 !defined(isImmediate)
  #if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
  		isImmediate = interpreterProxy->isImmediate;
  #else
  #if !defined(isImmediate)
  		isImmediate = 0;
  #endif
  #endif
  #endif /* !defined(isImmediate) */
  		isInMemory = interpreterProxy->isInMemory;
  #if !defined(isIntegerObject)
  		isIntegerObject = interpreterProxy->isIntegerObject;
  #endif
  		isPointers = interpreterProxy->isPointers;
  		isWords = interpreterProxy->isWords;
  		isYoung = interpreterProxy->isYoung;
  		literalofMethod = interpreterProxy->literalofMethod;
  		literalCountOf = interpreterProxy->literalCountOf;
  		methodArgumentCount = interpreterProxy->methodArgumentCount;
  		methodReturnFloat = interpreterProxy->methodReturnFloat;
  		methodReturnInteger = interpreterProxy->methodReturnInteger;
  		methodReturnString = interpreterProxy->methodReturnString;
  		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;
  #if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 14)
  		primitiveFailForOSError = interpreterProxy->primitiveFailForOSError;
  #else
  #if !defined(primitiveFailForOSError)
  		primitiveFailForOSError = 0;
  #endif
  #endif
  		primitiveMethod = interpreterProxy->primitiveMethod;
  		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 size field of an alienOop which is assumed to be an Alien of at
  	least 8 bytes (32-bits) or 16 bytes (64 bits)
   */
  
  	/* InterpreterPlugin>>#sizeField: */
  static sqInt
  sizeField(sqInt alienOop)
  {
  	return longAt(alienOop + BaseHeaderSize);
  }
  
  
  /*	Answer the start of an Alien'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. */
  
  	/* InterpreterPlugin>>#startOfData: */
  static sqInt
  startOfData(sqInt alienOop)
  {
  	return ((longAt(alienOop + BaseHeaderSize)) > 0
  		? (alienOop + BaseHeaderSize) + BytesPerOop
  		: longAt((alienOop + BaseHeaderSize) + BytesPerOop));
  }
  
  	/* ThreadedARM64FFIPlugin>>#structIsHomogenousFloatArrayOfSize:typeSpec:ofLength: */
  static sqInt
  structIsHomogenousFloatArrayOfSizetypeSpecofLength(sqInt structSize, unsigned int *argSpec, sqInt argSpecSize)
  {
      unsigned int firstField;
      sqInt idx;
      sqInt typeOfFirstField;
      sqInt typeSpec;
  
  	if (!((structSize <= (4 * (sizeof(double))))
  		 && (argSpecSize <= 5))) {
  
  		/* header plus up to four fields */
  		return 0;
  	}
  	/* begin atomicTypeOf: */
  	typeSpec = (firstField = argSpec[1]);
  	typeOfFirstField = ((usqInt)((typeSpec & FFIAtomicTypeMask))) >> FFIAtomicTypeShift;
  	if ((typeOfFirstField != FFITypeSingleFloat)
  	 && (typeOfFirstField != FFITypeDoubleFloat)) {
  		return 0;
  	}
  	for (idx = 2; idx < argSpecSize; idx += 1) {
  		if (firstField != (argSpec[idx])) {
  			return 0;
  		}
  	}
  	return 1;
  }
  
  
  #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, "primitiveCDataModel\000\000", (void*)primitiveCDataModel},
  	{(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, "primitiveStructureElementAlignment\000\000", (void*)primitiveStructureElementAlignment},
  	{(void*)_m, "setInterpreter", (void*)setInterpreter},
  	{NULL, NULL, NULL}
  };
  
  #else /* ifdef SQ_BUILTIN_PLUGIN */
  
  signed char primitiveCalloutAccessorDepth = 2;
  signed char primitiveCalloutWithArgsAccessorDepth = 4;
  signed char primitiveCDataModelAccessorDepth = 0;
  signed char primitiveCreateManualSurfaceAccessorDepth = 0;
  signed char primitiveDestroyManualSurfaceAccessorDepth = 0;
  signed char primitiveFFIAllocateAccessorDepth = 1;
  signed char primitiveFFIDoubleAtAccessorDepth = 1;
  signed char primitiveFFIDoubleAtPutAccessorDepth = 1;
  signed char primitiveFFIFloatAtAccessorDepth = 1;
  signed char primitiveFFIFloatAtPutAccessorDepth = 1;
  signed char primitiveFFIFreeAccessorDepth = 1;
  signed char primitiveFFIIntegerAtAccessorDepth = 1;
  signed char primitiveFFIIntegerAtPutAccessorDepth = 1;
  signed char primitiveForceLoadAccessorDepth = 2;
  signed char primitiveLoadSymbolFromModuleAccessorDepth = 2;
  signed char primitiveLogCallsToAccessorDepth = 0;
  signed char primitiveSetManualSurfacePointerAccessorDepth = 0;
  signed char primitiveStructureElementAlignmentAccessorDepth = 0;
  
  #endif /* ifdef SQ_BUILTIN_PLUGIN */
  