/* Automatically generated by
	VMPluginCodeGenerator VMMaker.oscog-eem.2481 uuid: 43e5789a-92ab-47cd-9c5b-ffe711bbfa4e
   from
	ThreadedX64Win64FFIPlugin VMMaker.oscog-eem.2481 uuid: 43e5789a-92ab-47cd-9c5b-ffe711bbfa4e
 */
static char __buildInfo[] = "ThreadedX64Win64FFIPlugin VMMaker.oscog-eem.2481 uuid: 43e5789a-92ab-47cd-9c5b-ffe711bbfa4e " __DATE__ ;



#include "config.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* Default EXPORT macro that does nothing (see comment in sq.h): */
#define EXPORT(returnType) returnType

/* Do not include the entire sq.h file but just those parts needed. */
#include "sqConfig.h"			/* Configuration options */
#include "sqVirtualMachine.h"	/*  The virtual machine proxy definition */
#include "sqPlatformSpecific.h"	/* Platform specific definitions */

#define true 1
#define false 0
#define null 0  /* using 'null' because nil is predefined in Think C */
#ifdef SQUEAK_BUILTIN_PLUGIN
# undef EXPORT
# define EXPORT(returnType) static returnType
#endif

#include "sqMemoryAccess.h"


/* ThreadedFFIPlugin class>>preambleCCode */

#include "sqAssert.h" /* for assert */
#define ThreadedFFIPlugin 1 /* to filter-out unwanted declarations from sqFFI.h */
#include "sqFFI.h" /* for logging and surface functions */
#include "sqCogStackAlignment.h" /* for STACK_ALIGN_BYTES and getsp() */

#ifdef _MSC_VER
# define alloca _alloca
#endif
#if defined(__GNUC__) && (defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__))
# define setsp(sp) asm volatile ("movl %0,%%esp" : : "m"(sp))
# elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__) ||  defined(__amd64) || defined(__x86_64))
# define setsp(sp) asm volatile ("movq %0,%%rsp" : : "m"(sp))
# elif defined(__GNUC__) && (defined(__arm__))
# define setsp(sp) asm volatile ("ldr %%sp, %0" : : "m"(sp))
#endif
#if !defined(getsp)
# define getsp() 0
#endif 
#if !defined(setsp)
# define setsp(ignored) 0
#endif 

#if !defined(STACK_ALIGN_BYTES)
#  define STACK_ALIGN_BYTES 0
#endif /* !defined(STACK_ALIGN_BYTES) */

/* For ABI that require stack alignment greater than natural word size */
#define MUST_ALIGN_STACK (STACK_ALIGN_BYTES > sizeof(void*))

#if defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__)
/* Both Mac OS X x86 and Win32 x86 return structs of a power of two in size
 * less than or equal to eight bytes in length in registers. Linux never does so.
 */
# if __linux__
#	define WIN32_X86_STRUCT_RETURN 0
# else
#	define WIN32_X86_STRUCT_RETURN 1
# endif
# if _WIN32
#	define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 1
# endif
# elif defined(__amd64__) || defined(__x86_64__) ||  defined(__amd64) || defined(__x86_64)
# if _WIN32 | _WIN64
#	define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 1
# endif
#endif /* defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__) */

#if !defined(ALLOCA_LIES_SO_SETSP_BEFORE_CALL)
# if defined(__MINGW32__) && !defined(__clang__) && (__GNUC__ >= 3) && (defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__))
    /*
     * cygwin -mno-cygwin (MinGW) gcc 3.4.x's alloca is a library routine that answers
     * %esp + xx, so the outgoing stack is offset by one or more word if uncorrected.
     * Grab the actual stack pointer to correct.
     */
#	define ALLOCA_LIES_SO_SETSP_BEFORE_CALL 1
# else
#	define ALLOCA_LIES_SO_SETSP_BEFORE_CALL 0
# endif
#endif /* !defined(ALLOCA_LIES_SO_SETSP_BEFORE_CALL) */

#if !defined(PLATFORM_API_USES_CALLEE_POPS_CONVENTION)
# define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 0
#endif

/* This alignment stuff is a hack for integerAt:put:size:signed:/primitiveFFIIntegerAt[Put].
 * The assumption right now is that all processors support unaligned access.  That only
 * holds true for x86, x86-64 & ARMv6 & later.  But this keeps us going until we can address
 * it properly.
 */
#define unalignedShortAt(a) shortAt(a)
#define unalignedShortAtput(a,v) shortAtput(a,v)
#define unalignedLong32At(a) long32At(a)
#define unalignedLong32Atput(a,v) long32Atput(a,v)
#define unalignedLong64At(a) long64At(a)
#define unalignedLong64Atput(a,v) long64Atput(a,v)

/* The dispatchOn:in:with:with: generates an unwanted call on error.  Just squash it. */
#define error(foo) 0
#ifndef SQUEAK_BUILTIN_PLUGIN
/* but print assert failures. */
void
warning(char *s) { /* Print an error message but don't exit. */
	printf("\n%s\n", s);
}
#endif

/* sanitize */
#ifdef SQUEAK_BUILTIN_PLUGIN
# define EXTERN 
#else
# define EXTERN extern
#endif

/* end ThreadedFFIPlugin class>>preambleCCode */


/*** Constants ***/
#define DefaultMaxStackSize 16384
#define DisownVMForFFICall 16
#define DisownVMForThreading 32
#define ExternalFunctionArgTypesIndex 2
#define ExternalFunctionFlagsIndex 1
#define ExternalFunctionStackSizeIndex 3
#define FFIAtomicTypeMask 0xF000000
#define FFIAtomicTypeShift 24
#define FFICallFlagThreaded 0x100
#define FFICallTypeApi 1
#define FFICallTypeCDecl 0
#define FFICallTypesMask 0xFF
#define FFIErrorAddressNotFound 13
#define FFIErrorAttemptToPassVoid 14
#define FFIErrorBadAddress 11
#define FFIErrorBadArg 3
#define FFIErrorBadArgs 2
#define FFIErrorBadAtomicType 5
#define FFIErrorBadExternalFunction 17
#define FFIErrorBadExternalLibrary 16
#define FFIErrorBadReturn 10
#define FFIErrorCallFrameTooBig 19
#define FFIErrorCallType 9
#define FFIErrorCoercionFailed 6
#define FFIErrorIntAsPointer 4
#define FFIErrorInvalidPointer 18
#define FFIErrorModuleNotFound 15
#define FFIErrorNoModule 12
#define FFIErrorNotFunction 1
#define FFIErrorStructSize 8
#define FFIErrorWrongType 7
#define FFIFlagAtomic 0x40000
#define FFIFlagPointer 0x20000
#define FFIFlagStructure 0x10000
#define FFINoCalloutAvailable -1
#define FFIStructSizeMask 0xFFFF
#define FFITypeBool 1
#define FFITypeDoubleFloat 13
#define FFITypeSignedByte 3
#define FFITypeSignedChar 11
#define FFITypeSignedInt 7
#define FFITypeSignedLongLong 9
#define FFITypeSignedShort 5
#define FFITypeSingleFloat 12
#define FFITypeUnsignedByte 2
#define FFITypeUnsignedInt 6
#define FFITypeVoid 0
#define MaxNumArgs 15
#define NumFloatRegArgs 4
#define NumIntRegArgs 4
#define PrimErrBadArgument 3
#define PrimErrBadMethod 12
#define PrimErrBadNumArgs 5
#define PrimErrBadReceiver 2
#define PrimErrFFIException 22
#define PrimErrNoCMemory 10
#define PrimErrNotFound 11
#define PrimErrObjectMayMove 14
#if !defined(SPURVM) /* Allow this to be overridden on the compiler command line */
# define SPURVM 1
#endif
#define WordSize 8

typedef struct {
	char *argVector;
	char *currentArg;
	char *limit;
	sqInt	structReturnSize;
	sqInt	callFlags;
	void *ffiArgSpec;
	sqInt	ffiArgSpecSize;
	sqInt	ffiArgHeader;
	sqInt	ffiRetHeader;
	sqInt	stringArgIndex;
	char *stringArgs [MaxNumArgs];
	char	floatRegisterSignature;
	char	integerRegisterIndex;
	char	floatRegisterIndex;
	sqInt		integerRegisters [NumIntRegArgs];
	double		floatRegisters [NumFloatRegArgs];
 } CalloutState;

#define ThreadedFFICalloutStateForX64Win64 CalloutState
#define ThreadedFFICalloutStateForX64 CalloutState
#define ThreadedFFICalloutState CalloutState



/*** Function Prototypes ***/
static sqInt atomicTypeOf(sqInt typeSpec);
static void cleanupCalloutState(CalloutState *calloutState);
static sqInt externalFunctionHasStackSizeSlot(void);
static void * ffiAddressOfstartingAtsize(sqInt rcvr, sqInt byteOffset, sqInt byteSize);
static sqInt ffiArgByValuein(sqInt oop, CalloutState *calloutState);
static sqInt ffiArgumentSpecClassin(sqInt oop, sqInt argSpec, sqInt argClass, CalloutState *calloutState);
static sqInt ffiAtomicArgByReferenceClassin(sqInt oop, sqInt oopClass, CalloutState *calloutState);
static sqInt ffiAtomicStructByReferenceClassin(sqInt oop, sqInt oopClass, CalloutState *calloutState);
static sqInt ffiCalloutToSpecOnStackin(void *procAddr, sqInt specOnStack, CalloutState *calloutState);
static sqInt ffiCallArgArrayOrNilNumArgs(sqInt externalFunction, sqInt argArrayOrNil, sqInt nArgs);
static sqInt ffiCheckReturnWithin(sqInt retSpec, sqInt retClass, CalloutState *calloutState);
static sqInt ffiContentsOfHandleerrCode(sqInt oop, sqInt errCode);
static sqInt ffiCreateIntegralResultOopofAtomicTypein(usqLong retVal, sqInt atomicType, CalloutState *calloutState);
static sqInt ffiFail(sqInt reason);
static double ffiFloatValueOf(sqInt oop);
static sqInt ffiIntegerValueOf(sqInt oop);
static sqInt ffiLoadCalloutAddressFrom(sqInt oop);
static sqInt ffiLoadCalloutAddress(sqInt lit);
static sqInt ffiLoadCalloutModule(sqInt module);
static void ffiLogCallout(sqInt lit);
EXPORT(sqInt) ffiLogCallsTo(char *fileName);
static sqInt ffiPushPointerContentsOfin(sqInt oop, CalloutState *calloutState);
static sqInt ffiPushPointerin(void *pointer, CalloutState *calloutState);
static sqInt ffiPushSignedBytein(sqInt value, CalloutState *calloutState);
static sqInt ffiPushSignedCharin(sqInt value, CalloutState *calloutState);
static sqInt ffiPushSignedIntin(sqInt value, CalloutState *calloutState);
static sqInt ffiPushSignedLongLongOopin(sqInt oop, CalloutState *calloutState);
static sqInt ffiPushSignedLongLongin(sqLong value, CalloutState *calloutState);
static sqInt ffiPushSignedShortin(sqInt value, CalloutState *calloutState);
static sqInt ffiPushStringOfLengthin(char *pointer, sqInt length, CalloutState *calloutState);
static sqInt ffiPushStructureContentsOfin(sqInt oop, CalloutState *calloutState);
static sqInt ffiPushStructureofSizetypeSpecofLengthin(void *pointer, sqInt structSize, sqInt *argSpec, sqInt argSpecSize, CalloutState *calloutState);
static sqInt ffiPushUnsignedBytein(sqInt value, CalloutState *calloutState);
static sqInt ffiPushUnsignedCharin(sqInt value, CalloutState *calloutState);
static sqInt ffiPushUnsignedIntin(sqInt value, CalloutState *calloutState);
static sqInt ffiPushUnsignedLongLongOopin(sqInt oop, CalloutState *calloutState);
static sqInt ffiPushUnsignedLongLongin(usqLong value, CalloutState *calloutState);
static sqInt ffiPushUnsignedShortin(sqInt value, CalloutState *calloutState);
static sqInt ffiPushVoidin(sqInt ignored, CalloutState *calloutState);
static sqInt ffiReturnCStringFrom(sqInt cPointer);
static sqInt ffiReturnPointerofTypein(usqLong retVal, sqInt retType, CalloutState *calloutState);
static sqInt ffiReturnStructofTypein(usqLong intRet, 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 incrementFloatRegisterIndex(CalloutState * self_in_incrementFloatRegisterIndex);
static sqInt incrementIntegerRegisterIndex(CalloutState * self_in_incrementIntegerRegisterIndex);
EXPORT(sqInt) initialiseModule(void);
static sqInt isAlien(sqInt anOop);
static sqInt isAtomicType(sqInt typeSpec);
static sqInt isDirectAlien(sqInt oop);
static sqInt msg(char *s);
static sqInt nonRegisterStructReturnIsViaImplicitFirstArgument(void);
EXPORT(void) primitiveCallout(void);
EXPORT(void) primitiveCalloutWithArgs(void);
EXPORT(sqInt) primitiveCreateManualSurface(void);
EXPORT(sqInt) primitiveDestroyManualSurface(void);
EXPORT(sqInt) primitiveFFIAllocate(void);
EXPORT(sqInt) primitiveFFIDoubleAt(void);
EXPORT(sqInt) primitiveFFIDoubleAtPut(void);
EXPORT(sqInt) primitiveFFIFloatAt(void);
EXPORT(sqInt) primitiveFFIFloatAtPut(void);
EXPORT(sqInt) primitiveFFIFree(void);
EXPORT(sqInt) primitiveFFIGetLastError(void);
EXPORT(sqInt) primitiveFFIIntegerAt(void);
EXPORT(sqInt) primitiveFFIIntegerAtPut(void);
EXPORT(sqInt) primitiveForceLoad(void);
EXPORT(sqInt) primitiveLoadSymbolFromModule(void);
EXPORT(sqInt) primitiveLogCallsTo(void);
EXPORT(sqInt) primitiveSetManualSurfacePointer(void);
static sqInt returnStructInRegisters(sqInt returnStructSize);
EXPORT(sqInt) setInterpreter(struct VirtualMachine *anInterpreter);
static sqInt sizeField(sqInt oop);
static sqInt startOfData(sqInt oop);


/*** Variables ***/
static sqInt externalFunctionInstSize;
static sqInt ffiLastError;
static sqInt ffiLogEnabled;

#if defined(SQUEAK_BUILTIN_PLUGIN)

# define isIntegerObject(oop) ((oop) & 1)

# if SPURVM
extern sqInt classIndexOf(sqInt);
#	define LargeNegativeIntegerClassIndex 32
#	define LargePositiveIntegerClassIndex 33
#	if BytesPerOop == 4
#	  define isImmediate(oop) ((oop) & 3)
#	else
#	  define isImmediate(oop) ((oop) & 7)
#	endif
#	define isKindOfInteger(oop) (isImmediate(oop) ? isIntegerObject(oop) : (unsigned)(classIndexOf(oop) - LargeNegativeIntegerClassIndex) <= 1)
#	define isLargeIntegerObject(oop) (!isImmediate(oop) && (unsigned)(classIndexOf(oop) - LargeNegativeIntegerClassIndex) <= 1)
#	define isLargeNegativeIntegerObject(oop) (!isImmediate(oop) && classIndexOf(oop) == LargeNegativeIntegerClassIndex)
#	define isLargePositiveIntegerObject(oop) (!isImmediate(oop) && classIndexOf(oop) == LargePositiveIntegerClassIndex)
# endif /* SPURVM */
#endif /* defined(SQUEAK_BUILTIN_PLUGIN) */

#if !defined(isKindOfInteger)
# define isLargeNegativeIntegerObject(oop) (fetchClassOf(oop) == classLargeNegativeInteger())
# define isLargePositiveIntegerObject(oop) (fetchClassOf(oop) == classLargePositiveInteger())
# define isLargeIntegerObject(oop) (isLargeNegativeIntegerObject(oop) || isLargePositiveIntegerObject(oop))
# define isKindOfInteger(oop) (isIntegerObject(oop) || isLargeNegativeIntegerObject(oop) || isLargePositiveIntegerObject(oop))
#endif

#if !defined(SQUEAK_BUILTIN_PLUGIN)
static sqInt (*booleanValueOf)(sqInt obj);
static sqInt (*byteSizeOf)(sqInt oop);
static sqInt (*characterObjectOf)(sqInt characterCode);
static sqInt (*characterValueOf)(sqInt aCharacter);
static sqInt (*classAlien)(void);
static sqInt (*classByteArray)(void);
static sqInt (*classExternalAddress)(void);
static sqInt (*classExternalData)(void);
static sqInt (*classExternalFunction)(void);
static sqInt (*classExternalLibrary)(void);
static sqInt (*classExternalStructure)(void);
static sqInt (*classLargePositiveInteger)(void);
static sqInt (*classString)(void);
static sqInt (*disownVM)(sqInt flags);
static sqInt (*failed)(void);
static sqInt (*falseObject)(void);
static sqInt (*fetchClassOf)(sqInt oop);
static sqInt (*fetchIntegerofObject)(sqInt fieldIndex, sqInt objectPointer);
static sqInt (*fetchLong32ofObject)(sqInt fieldIndex, sqInt oop);
static sqInt (*fetchPointerofObject)(sqInt index, sqInt oop);
static void * (*firstIndexableField)(sqInt oop);
static sqInt (*floatObjectOf)(double aFloat);
static double (*floatValueOf)(sqInt oop);
static sqInt (*includesBehaviorThatOf)(sqInt aClass, sqInt aSuperclass);
static sqInt (*instanceSizeOf)(sqInt classObj);
static sqInt (*instantiateClassindexableSize)(sqInt classPointer, sqInt size);
static sqInt (*integerObjectOf)(sqInt value);
static sqInt (*integerValueOf)(sqInt oop);
static void * (*ioLoadModuleOfLength)(sqInt moduleNameIndex, sqInt moduleLength);
static void * (*ioLoadSymbolOfLengthFromModule)(sqInt functionNameIndex, sqInt functionLength, sqInt moduleHandle);
static sqInt (*isKindOfClass)(sqInt oop, sqInt aClass);
static sqInt (*isArray)(sqInt oop);
static sqInt (*isBytes)(sqInt oop);
static sqInt (*isCharacterObject)(sqInt oop);
static sqInt (*isFloatObject)(sqInt oop);
static sqInt (*isImmediate)(sqInt anObject);
static sqInt (*isInMemory)(sqInt address);
static sqInt (*isIntegerObject)(sqInt objectPointer);
static sqInt (*isPointers)(sqInt oop);
static sqInt (*isWords)(sqInt oop);
static sqInt (*isYoung)(sqInt anOop);
static sqInt (*literalofMethod)(sqInt offset, sqInt methodPointer);
static sqInt (*literalCountOf)(sqInt methodPointer);
static sqInt (*methodArgumentCount)(void);
static sqInt (*methodReturnInteger)(sqInt integer);
static sqInt (*methodReturnValue)(sqInt oop);
static sqInt (*nilObject)(void);
static sqInt (*ownVM)(sqInt flags);
static sqInt (*pop)(sqInt nItems);
static sqInt (*popthenPush)(sqInt nItems, sqInt oop);
static sqInt (*popRemappableOop)(void);
static sqInt (*positive32BitIntegerFor)(unsigned int integerValue);
static usqInt (*positive32BitValueOf)(sqInt oop);
static sqInt (*positive64BitIntegerFor)(usqLong integerValue);
static usqLong (*positive64BitValueOf)(sqInt oop);
static usqIntptr_t (*positiveMachineIntegerValueOf)(sqInt oop);
static sqInt (*primitiveErrorTable)(void);
static sqInt (*primitiveFail)(void);
static sqInt (*primitiveFailFor)(sqInt reasonCode);
static sqInt (*primitiveMethod)(void);
static sqInt (*pushFloat)(double f);
static sqInt (*pushRemappableOop)(sqInt oop);
static sqInt (*signed32BitIntegerFor)(sqInt integerValue);
static sqInt (*signed64BitIntegerFor)(sqLong integerValue);
static sqLong (*signed64BitValueOf)(sqInt oop);
static sqIntptr_t (*signedMachineIntegerValueOf)(sqInt oop);
static sqInt (*slotSizeOf)(sqInt oop);
static sqInt (*stackIntegerValue)(sqInt offset);
static sqInt (*stackObjectValue)(sqInt offset);
static sqInt (*stackValue)(sqInt offset);
static sqInt (*storeIntegerofObjectwithValue)(sqInt index, sqInt oop, sqInt integer);
static sqInt (*storePointerofObjectwithValue)(sqInt index, sqInt oop, sqInt valuePointer);
static void (*tenuringIncrementalGC)(void);
static sqInt (*trueObject)(void);
#else /* !defined(SQUEAK_BUILTIN_PLUGIN) */
extern sqInt booleanValueOf(sqInt obj);
extern sqInt byteSizeOf(sqInt oop);
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
extern sqInt characterObjectOf(sqInt characterCode);
#else
# define characterObjectOf(characterCode) 0
#endif
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
extern sqInt characterValueOf(sqInt aCharacter);
#else
# define characterValueOf(aCharacter) 0
#endif
extern sqInt classAlien(void);
extern sqInt classByteArray(void);
extern sqInt classExternalAddress(void);
extern sqInt classExternalData(void);
extern sqInt classExternalFunction(void);
extern sqInt classExternalLibrary(void);
extern sqInt classExternalStructure(void);
extern sqInt classLargePositiveInteger(void);
extern sqInt classString(void);
extern sqInt disownVM(sqInt flags);
extern sqInt failed(void);
extern sqInt falseObject(void);
extern sqInt fetchClassOf(sqInt oop);
extern sqInt fetchIntegerofObject(sqInt fieldIndex, sqInt objectPointer);
extern sqInt fetchLong32ofObject(sqInt fieldIndex, sqInt oop);
extern sqInt fetchPointerofObject(sqInt index, sqInt oop);
extern void * firstIndexableField(sqInt oop);
extern sqInt floatObjectOf(double aFloat);
extern double floatValueOf(sqInt oop);
extern sqInt includesBehaviorThatOf(sqInt aClass, sqInt aSuperclass);
extern sqInt instanceSizeOf(sqInt classObj);
extern sqInt instantiateClassindexableSize(sqInt classPointer, sqInt size);
extern sqInt integerObjectOf(sqInt value);
extern sqInt integerValueOf(sqInt oop);
extern void * ioLoadModuleOfLength(sqInt moduleNameIndex, sqInt moduleLength);
extern void * ioLoadSymbolOfLengthFromModule(sqInt functionNameIndex, sqInt functionLength, sqInt moduleHandle);
extern sqInt isKindOfClass(sqInt oop, sqInt aClass);
extern sqInt isArray(sqInt oop);
extern sqInt isBytes(sqInt oop);
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
extern sqInt isCharacterObject(sqInt oop);
#else
# define isCharacterObject(oop) 0
#endif
extern sqInt isFloatObject(sqInt oop);
#if !defined(isImmediate)
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
extern sqInt isImmediate(sqInt anObject);
#else
# define isImmediate(anObject) 0
#endif
#endif /* !defined(isImmediate) */
extern sqInt isInMemory(sqInt address);
#if !defined(isIntegerObject)
extern sqInt isIntegerObject(sqInt objectPointer);
#endif
extern sqInt isPointers(sqInt oop);
extern sqInt isWords(sqInt oop);
extern sqInt isYoung(sqInt anOop);
extern sqInt literalofMethod(sqInt offset, sqInt methodPointer);
extern sqInt literalCountOf(sqInt methodPointer);
extern sqInt methodArgumentCount(void);
extern sqInt methodReturnInteger(sqInt integer);
extern sqInt methodReturnValue(sqInt oop);
extern sqInt nilObject(void);
extern sqInt ownVM(sqInt flags);
extern sqInt pop(sqInt nItems);
extern sqInt popthenPush(sqInt nItems, sqInt oop);
extern sqInt popRemappableOop(void);
extern sqInt positive32BitIntegerFor(unsigned int integerValue);
extern usqInt positive32BitValueOf(sqInt oop);
extern sqInt positive64BitIntegerFor(usqLong integerValue);
extern usqLong positive64BitValueOf(sqInt oop);
extern usqIntptr_t positiveMachineIntegerValueOf(sqInt oop);
extern sqInt primitiveErrorTable(void);
extern sqInt primitiveFail(void);
extern sqInt primitiveFailFor(sqInt reasonCode);
extern sqInt primitiveMethod(void);
extern sqInt pushFloat(double f);
extern sqInt pushRemappableOop(sqInt oop);
extern sqInt signed32BitIntegerFor(sqInt integerValue);
extern sqInt signed64BitIntegerFor(sqLong integerValue);
extern sqLong signed64BitValueOf(sqInt oop);
extern sqIntptr_t signedMachineIntegerValueOf(sqInt oop);
extern sqInt slotSizeOf(sqInt oop);
extern sqInt stackIntegerValue(sqInt offset);
extern sqInt stackObjectValue(sqInt offset);
extern sqInt stackValue(sqInt offset);
extern sqInt storeIntegerofObjectwithValue(sqInt index, sqInt oop, sqInt integer);
extern sqInt storePointerofObjectwithValue(sqInt index, sqInt oop, sqInt valuePointer);
extern void tenuringIncrementalGC(void);
extern sqInt trueObject(void);
extern
#endif
struct VirtualMachine* interpreterProxy;
static const char *moduleName =
#ifdef SQUEAK_BUILTIN_PLUGIN
	"X64Win64FFIPlugin VMMaker.oscog-eem.2481 (i)"
#else
	"X64Win64FFIPlugin VMMaker.oscog-eem.2481 (e)"
#endif
;


/*** Macros ***/
#define allocaLiesSoSetSpBeforeCall() ALLOCA_LIES_SO_SETSP_BEFORE_CALL
#define cStackAlignment() STACK_ALIGN_BYTES
#define dispatchFunctionPointer(aFunctionPointer) (aFunctionPointer)()
#define dispatchFunctionPointerwithwithwithwith(aFunctionPointer, int1, int2, int3, int4) (aFunctionPointer)(int1, int2, int3, int4)
#define dispatchFunctionPointerwithwithwithwithwithwith(aFunctionPointer, int1, int2, int3, int4, int5, int6) (aFunctionPointer)(int1, int2, int3, int4, int5, int6)
#define ffiAlloc(bytes) (usqInt)malloc(bytes)
#define ffiFree(pointer) free((void *)(pointer))
#define isCalleePopsConvention(callType) (PLATFORM_API_USES_CALLEE_POPS_CONVENTION && (callType) == FFICallTypeApi)
#define mustAlignStack() MUST_ALIGN_STACK


	/* ThreadedFFIPlugin>>#atomicTypeOf: */
static sqInt
atomicTypeOf(sqInt typeSpec)
{
	return ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
}


/*	Free any temporary arg strings. */

	/* ThreadedFFIPlugin>>#cleanupCalloutState: */
static void
cleanupCalloutState(CalloutState *calloutState)
{
	while (((calloutState->stringArgIndex)) > 0) {
		free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
	}
}

	/* ThreadedFFIPlugin>>#externalFunctionHasStackSizeSlot */
static sqInt
externalFunctionHasStackSizeSlot(void)
{
	return externalFunctionInstSize > ExternalFunctionStackSizeIndex;
}


/*	Answer a long of the address of the byteSize slot (byte, short, int,
	whatever) at byteOffset in rcvr.
	Nominally intended for use with ExternalAddress objects, this code will
	work (for obscure historical
	reasons) with plain Byte or Word Arrays as well. Answer 0 on error. */

	/* ThreadedFFIPlugin>>#ffiAddressOf:startingAt:size: */
static void *
ffiAddressOfstartingAtsize(sqInt rcvr, sqInt byteOffset, sqInt byteSize)
{
    sqInt addr;
    sqInt rcvrClass;
    sqInt rcvrSize;

	if (!(isBytes(rcvr))) {
		return 0;
	}
	if (!(byteOffset > 0)) {
		return 0;
	}
	rcvrClass = fetchClassOf(rcvr);
	rcvrSize = byteSizeOf(rcvr);
	if (rcvrClass == (classExternalAddress())) {
		if (!(rcvrSize == BytesPerWord)) {
			return 0;
		}

		/* Hack!! */
		/* don't you dare to read from object memory (unless is pinned)! */
		addr = fetchPointerofObject(0, rcvr);
		if (addr == 0) {

			/* or: [(interpreterProxy isInMemory: addr) or: [(interpreterProxy isPinned: rcvr) not]] */
			return 0;
		}
	}
	else {
		if (!(((byteOffset + byteSize) - 1) <= rcvrSize)) {
			return 0;
		}
		addr = ((sqIntptr_t) (firstIndexableField(rcvr)));
	}
	addr = (addr + byteOffset) - 1;
	return ((void *)addr);
}


/*	Support for generic callout. Prepare an argument by value for a callout. */

	/* ThreadedFFIPlugin>>#ffiArgByValue:in: */
static sqInt
ffiArgByValuein(sqInt oop, CalloutState *calloutState)
{
    sqInt atomicType;
    double floatValue;
    sqInt intValue;
    sqInt typeSpec;

	/* begin atomicTypeOf: */
	typeSpec = (calloutState->ffiArgHeader);
	atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
	if ((atomicType < 0)
	 || (atomicType > FFITypeDoubleFloat)) {
		return FFIErrorBadAtomicType;
	}
	if (atomicType < FFITypeSingleFloat) {

		/* integer types */
		if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)) {

			/* ffi support code must coerce longlong */
			intValue = oop;
		}
		else {
			/* begin ffiIntegerValueOf: */
			if (oop & (BytesPerWord - 1)) {
				if (isIntegerObject(oop)) {
					intValue = integerValueOf(oop);
					goto l2;
				}
				
#        if SPURVM
				if (isCharacterObject(oop)) {

					/* Immediate in Spur */
					intValue = characterValueOf(oop);
					goto l2;
				}
				if (isFloatObject(oop)) {

					/* Immediate in 64-bit Spur */
					intValue = floatValueOf(oop);
					goto l2;
				}
#        endif /* SPURVM */
			}
			else {
				
#        if SPURVM

				/* No non-immediate characters in Spur */
#        else /* SPURVM */
				if (isCharacterObject(oop)) {
					intValue = characterValueOf(oop);
					goto l2;
				}
#        endif /* SPURVM */
				if (isFloatObject(oop)) {
					intValue = floatValueOf(oop);
					goto l2;
				}
				if (oop == (nilObject())) {
					intValue = 0;
					goto l2;
				}
				if (oop == (falseObject())) {
					intValue = 0;
					goto l2;
				}
				if (oop == (trueObject())) {
					intValue = 1;
					goto l2;
				}
				if (isLargePositiveIntegerObject(oop)) {
					
#          if BytesPerWord == 8

					/* Use cppIf: to get the return type of the function right.  Should be sqInt on 32-bits. */
					intValue = positive64BitValueOf(oop);
					goto l2;
#          else /* BytesPerWord == 8 */
					intValue = positive32BitValueOf(oop);
					goto l2;
#          endif /* BytesPerWord == 8 */
				}
			}
			intValue = signedMachineIntegerValueOf(oop);
	l2:	/* end ffiIntegerValueOf: */;
		}
		if (failed()) {
			return FFIErrorCoercionFailed;
		}
		
		switch (atomicType) {
		case 0:
			return FFIErrorAttemptToPassVoid;
		case 1:
			return ffiPushUnsignedIntin(intValue, calloutState);
		case 2:
			return ffiPushUnsignedBytein(intValue, calloutState);
		case 3:
			return ffiPushSignedBytein(intValue, calloutState);
		case 4:
			return ffiPushUnsignedShortin(intValue, calloutState);
		case 5:
			return ffiPushSignedShortin(intValue, calloutState);
		case 6:
			return ffiPushUnsignedIntin(intValue, calloutState);
		case 7:
			return ffiPushSignedIntin(intValue, calloutState);
		case 8:
			return ffiPushUnsignedLongLongOopin(intValue, calloutState);
		case 9:
			return ffiPushSignedLongLongOopin(intValue, calloutState);
		case 10:
			return ffiPushUnsignedCharin(intValue, calloutState);
		case 11:
			return ffiPushSignedCharin(intValue, calloutState);

		default:
			error("Case not found");
			return -1;
		}
	}
	/* begin ffiFloatValueOf: */
	if (isFloatObject(oop)) {
		floatValue = floatValueOf(oop);
		goto l3;
	}
	floatValue = ((double) (ffiIntegerValueOf(oop)) );
	l3:	/* end ffiFloatValueOf: */;
	if (failed()) {
		return FFIErrorCoercionFailed;
	}
	if (atomicType == FFITypeSingleFloat) {
		/* begin ffiPushSingleFloat:in: */
		if (((calloutState->floatRegisterIndex)) < NumFloatRegArgs) {
			(((float *) (((calloutState->floatRegisters)) + ((calloutState->floatRegisterIndex)))))[0] = floatValue;
			/* begin incrementFloatRegisterIndex */
			(calloutState->floatRegisterSignature) = ((calloutState->floatRegisterSignature)) + (1U << ((calloutState->floatRegisterIndex)));
			(calloutState->integerRegisterIndex) = ((calloutState->floatRegisterIndex) = ((calloutState->floatRegisterIndex)) + 1);
		}
		else {
			if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
				return FFIErrorCallFrameTooBig;
			}
			long64AtPointerput((calloutState->currentArg), 0);
			storeSingleFloatAtPointerfrom((calloutState->currentArg), floatValue);
			(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
		}
		return 0;
	}
	else {
		/* begin ffiPushDoubleFloat:in: */
		if (((calloutState->floatRegisterIndex)) < NumFloatRegArgs) {
			((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)] = floatValue;
			/* begin incrementFloatRegisterIndex */
			(calloutState->floatRegisterSignature) = ((calloutState->floatRegisterSignature)) + (1U << ((calloutState->floatRegisterIndex)));
			(calloutState->integerRegisterIndex) = ((calloutState->floatRegisterIndex) = ((calloutState->floatRegisterIndex)) + 1);
		}
		else {
			if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
				return FFIErrorCallFrameTooBig;
			}
			storeFloatAtPointerfrom((calloutState->currentArg), floatValue);
			(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
		}
		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)
{
    usqLong arg;
    usqLong arg1;
    sqInt *argSpec1;
    sqInt *argSpec2;
    sqInt argSpecSize;
    sqInt argSpecSize1;
    sqInt atomicType;
    sqInt atomicType1;
    sqInt atomicType2;
    char *copy;
    sqInt err;
    double floatValue;
    sqInt intValue;
    sqInt isAlien;
    sqInt isString;
    sqInt isStruct;
    sqInt length;
    sqInt nilOop;
    sqInt oopClass;
    char *pointer;
    void *pointer1;
    void *pointer2;
    void *pointer3;
    void *pointer4;
    void *pointer5;
    void *pointer6;
    void * ptrAddress;
    sqInt ptrClass;
    sqInt ptrType;
    sqInt spec;
    sqInt specOop;
    sqInt specType;
    sqInt structSize;
    sqInt structSize1;
    sqInt typeSpec;
    sqInt typeSpec1;
    sqInt typeSpec2;
    sqInt valueOop;
    sqInt valueOop1;

	arg = 0;
	arg1 = 0;

	/* Prefetch class (we'll need it) */
	oopClass = fetchClassOf(oop);

	/* Do the necessary type checks */
	nilOop = nilObject();
	if (!(argClass == nilOop)) {

		/* Type check 1:
		   Is the required class of the argument a subclass of ExternalStructure? */
		if (!(includesBehaviorThatOf(argClass, classExternalStructure()))) {
			return FFIErrorWrongType;
		}
		if (!((nilOop == oop)
			 || (includesBehaviorThatOf(oopClass, argClass)))) {
			return FFIErrorCoercionFailed;
		}
	}
	isStruct = 0;
	if ((oop != nilOop)
	 && (isPointers(oop))) {

		/* #isPointers: will fail if oop is immediate so don't even attempt to use it */
		isStruct = includesBehaviorThatOf(oopClass, classExternalStructure());
		if (!((argClass == nilOop)
			 || (isStruct))) {
			return FFIErrorCoercionFailed;
		}
	}
	if (isStruct) {
		valueOop = fetchPointerofObject(0, oop);
	}
	else {
		valueOop = oop;
	}
	if (!(isWords(argSpec))) {
		return FFIErrorWrongType;
	}
	(calloutState->ffiArgSpecSize = slotSizeOf(argSpec));
	if (((calloutState->ffiArgSpecSize)) == 0) {
		return FFIErrorWrongType;
	}
	(calloutState->ffiArgSpec = firstIndexableField(argSpec));
	(calloutState->ffiArgHeader = longAt((calloutState->ffiArgSpec)));
	if (((calloutState->ffiArgHeader)) & FFIFlagStructure) {

		/* argument must be ExternalStructure */
		if (!isStruct) {
			return FFIErrorCoercionFailed;
		}
		if (((calloutState->ffiArgHeader)) & FFIFlagAtomic) {
			return FFIErrorWrongType;
		}
		/* begin ffiPushStructureContentsOf:in: */
		ptrClass = fetchClassOf(valueOop);
		if (ptrClass == (classExternalAddress())) {

			/* ExternalAddress is bytes */

			/* There is no way we can make sure the structure is valid.
			   But we can at least check for attempts to pass pointers to ST memory. */
			ptrAddress = ((void *)(fetchPointerofObject(0, valueOop)));
			if (isInMemory(ptrAddress)) {
				return FFIErrorInvalidPointer;
			}
			/* begin ffiPushStructure:ofSize:typeSpec:ofLength:in: */
			structSize = ((calloutState->ffiArgHeader)) & FFIStructSizeMask;
			argSpec2 = (calloutState->ffiArgSpec);
			argSpecSize = (calloutState->ffiArgSpecSize);
			if (structSize <= 0) {
				return FFIErrorStructSize;
			}
			if ((structSize <= WordSize)
			 && ((structSize & (structSize - 1)) == 0)) {
				memcpy((&arg), ptrAddress, structSize);
				/* begin ffiPushUnsignedLongLong:in: */
				if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
					((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = arg;
					(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
				}
				else {
					if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
						return FFIErrorCallFrameTooBig;
					}
					longAtput((calloutState->currentArg), arg);
					(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
				}
				return 0;
			}
			flag("quick hack");
			/* begin ffiPushPointer:in: */
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				longAtput((calloutState->currentArg), ptrAddress);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			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 (structSize1 <= 0) {
					return FFIErrorStructSize;
				}
				if ((structSize1 <= WordSize)
				 && ((structSize1 & (structSize1 - 1)) == 0)) {
					memcpy((&arg1), ptrAddress, structSize1);
					/* begin ffiPushUnsignedLongLong:in: */
					if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
						((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = arg1;
						(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
					}
					else {
						if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
							return FFIErrorCallFrameTooBig;
						}
						longAtput((calloutState->currentArg), arg1);
						(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
					}
					return 0;
				}
				flag("quick hack");
				/* begin ffiPushPointer:in: */
				if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
					((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
					(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
				}
				else {
					if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
						return FFIErrorCallFrameTooBig;
					}
					longAtput((calloutState->currentArg), ptrAddress);
					(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
				}
				return 0;
			}
			if (!((((calloutState->ffiArgHeader)) & FFIStructSizeMask) == BytesPerWord)) {
				return FFIErrorStructSize;
			}
			ptrAddress = ((void *)(fetchPointerofObject(0, valueOop)));
			if (isInMemory(ptrAddress)) {
				return FFIErrorInvalidPointer;
			}
			/* begin ffiPushPointer:in: */
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				longAtput((calloutState->currentArg), ptrAddress);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			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->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				longAtput((calloutState->currentArg), null);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			return 0;
		}
		if (((calloutState->ffiArgHeader)) & FFIFlagAtomic) {

			/* e.g., ExternalData */
			if (isStruct) {
				/* begin ffiAtomicStructByReference:Class:in: */
				if (!(oopClass == (classExternalData()))) {
					return FFIErrorCoercionFailed;
				}
				/* begin atomicTypeOf: */
				typeSpec = (calloutState->ffiArgHeader);
				atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
				if (atomicType != FFITypeVoid) {
					/* begin ffiValidateExternalData:AtomicType: */
					ptrType = fetchPointerofObject(1, oop);
					if (!((isPointers(ptrType))
						 && ((slotSizeOf(ptrType)) >= 2))) {
						err = FFIErrorWrongType;
						goto l3;
					}
					specOop = fetchPointerofObject(0, ptrType);
					if (!((isWords(specOop))
						 && ((slotSizeOf(specOop)) > 0))) {
						err = FFIErrorWrongType;
						goto l3;
					}
					spec = fetchPointerofObject(0, specOop);
					if (!(spec & FFIFlagAtomic)) {
						err = FFIErrorWrongType;
						goto l3;
					}
					/* begin atomicTypeOf: */
					specType = ((usqInt) (spec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
					if (specType != atomicType) {

						/* Allow for signed/unsigned conversion but nothing else.
						   See FFIConstants class>>#initializeTypeConstants */
						if (!((atomicType >= FFITypeUnsignedByte)
							 && ((atomicType <= FFITypeSignedChar)
							 && ((((usqInt) atomicType) >> 1) == (((usqInt) specType) >> 1))))) {
							err = FFIErrorCoercionFailed;
							goto l3;
						}
					}
					err = 0;
	l3:	/* end ffiValidateExternalData:AtomicType: */;
					if (err != 0) {
						return err;
					}
				}
				valueOop1 = fetchPointerofObject(0, oop);
				return ffiPushPointerContentsOfin(valueOop1, calloutState);
			}
			else {
				/* begin ffiAtomicArgByReference:Class:in: */
				typeSpec1 = (calloutState->ffiArgHeader);
				atomicType1 = ((usqInt) (typeSpec1 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
				if (atomicType1 == FFITypeBool) {

					/* No bools on input */
					return FFIErrorCoercionFailed;
				}
				isAlien = ((isString = includesBehaviorThatOf(oopClass, classString()))
					? 0
					: includesBehaviorThatOf(oopClass, classAlien()));
				if ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {

					/* string value (char*) */
					/* note: the only types allowed for passing into char* types are
					   ByteArray, String, Symbol, Alien and *no* other byte indexed objects
					   (e.g., CompiledMethod, LargeInteger). We only check for strings
					   here and fall through to the byte* check otherwise. */
					if (isString) {

						/* String/Symbol */
						/* Strings must be allocated by the ffi support code */
						/* begin ffiPushString:OfLength:in: */
						pointer = ((char *) (firstIndexableField(oop)));
						length = byteSizeOf(oop);
						if (((calloutState->stringArgIndex)) >= MaxNumArgs) {
							return -PrimErrBadNumArgs;
						}
						copy = malloc(length + 1);
						if (copy == null) {
							return -PrimErrNoCMemory;
						}
						memcpy(copy, pointer, length);
						copy[length] = 0;
						((calloutState->stringArgs))[(calloutState->stringArgIndex)] = copy;
						(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) + 1);
						/* begin ffiPushPointer:in: */
						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)copy));
							(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
						}
						else {
							if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
								return FFIErrorCallFrameTooBig;
							}
							longAtput((calloutState->currentArg), copy);
							(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
						}
						return 0;
					}
					atomicType1 = FFITypeUnsignedByte;
				}
				
#        if COGMTVM

				/* Since all the following pass the address of the first indexable field we need to fail
				   the call if it is threaded and the object is young, since it may move during the call. */
				if ((((calloutState->callFlags)) & FFICallFlagThreaded)
				 && (((!isAlien)
				 || ((assert(isAlien(oop)),
				(longAt(oop + BaseHeaderSize)) > 0)))
				 && (isYoung(oop)))) {
					return -PrimErrObjectMayMove;
				}
#        endif /* COGMTVM */
				if ((atomicType1 == FFITypeVoid)
				 || ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedByte) >> 1))) {

					/* byte* -- see comment on string above */
					if (isString
					 || (oopClass == (classByteArray()))) {

						/* String/Symbol/ByteArray */
						/* begin ffiPushPointer:in: */
						pointer1 = ((void *) (firstIndexableField(oop)));
						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer1));
							(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
						}
						else {
							if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
								return FFIErrorCallFrameTooBig;
							}
							longAtput((calloutState->currentArg), pointer1);
							(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
						}
						return 0;
					}
					if (oopClass == (classExternalAddress())) {
						/* begin ffiPushPointer:in: */
						pointer2 = ((void *) (longAt(oop + BaseHeaderSize)));
						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer2));
							(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
						}
						else {
							if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
								return FFIErrorCallFrameTooBig;
							}
							longAtput((calloutState->currentArg), pointer2);
							(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
						}
						return 0;
					}
					if (isAlien) {
						/* begin ffiPushPointer:in: */
						pointer3 = pointerForOop(((longAt(oop + BaseHeaderSize)) > 0
							? (oop + BaseHeaderSize) + BytesPerOop
							: longAt((oop + BaseHeaderSize) + BytesPerOop)));
						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer3));
							(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
						}
						else {
							if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
								return FFIErrorCallFrameTooBig;
							}
							longAtput((calloutState->currentArg), pointer3);
							(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
						}
						return 0;
					}
					if (!(atomicType1 == FFITypeVoid)) {
						return FFIErrorCoercionFailed;
					}
				}
				if (atomicType1 <= FFITypeDoubleFloat) {
					if ((isWords(oop))
					 || (oopClass == (classByteArray()))) {
						/* begin ffiPushPointer:in: */
						pointer4 = ((void *) (firstIndexableField(oop)));
						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer4));
							(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
						}
						else {
							if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
								return FFIErrorCallFrameTooBig;
							}
							longAtput((calloutState->currentArg), pointer4);
							(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
						}
						return 0;
					}
					if (oopClass == (classExternalAddress())) {
						/* begin ffiPushPointer:in: */
						pointer5 = ((void *) (longAt(oop + BaseHeaderSize)));
						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer5));
							(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
						}
						else {
							if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
								return FFIErrorCallFrameTooBig;
							}
							longAtput((calloutState->currentArg), pointer5);
							(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
						}
						return 0;
					}
					if (isAlien) {
						/* begin ffiPushPointer:in: */
						pointer6 = pointerForOop(((longAt(oop + BaseHeaderSize)) > 0
							? (oop + BaseHeaderSize) + BytesPerOop
							: longAt((oop + BaseHeaderSize) + BytesPerOop)));
						if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
							((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer6));
							(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
						}
						else {
							if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
								return FFIErrorCallFrameTooBig;
							}
							longAtput((calloutState->currentArg), pointer6);
							(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
						}
						return 0;
					}
				}
				return FFIErrorCoercionFailed;
			}
		}
		if (!isStruct) {
			return FFIErrorCoercionFailed;
		}
		return ffiPushPointerContentsOfin(valueOop, calloutState);
	}
	if (((calloutState->ffiArgHeader)) & FFIFlagAtomic) {

		/* argument is atomic value */
		/* begin ffiArgByValue:in: */
		typeSpec2 = (calloutState->ffiArgHeader);
		atomicType2 = ((usqInt) (typeSpec2 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
		if ((atomicType2 < 0)
		 || (atomicType2 > FFITypeDoubleFloat)) {
			return FFIErrorBadAtomicType;
		}
		if (atomicType2 < FFITypeSingleFloat) {

			/* integer types */
			if ((((usqInt) atomicType2) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)) {

				/* ffi support code must coerce longlong */
				intValue = valueOop;
			}
			else {
				/* begin ffiIntegerValueOf: */
				if (valueOop & (BytesPerWord - 1)) {
					if (isIntegerObject(valueOop)) {
						intValue = integerValueOf(valueOop);
						goto l9;
					}
					
#          if SPURVM
					if (isCharacterObject(valueOop)) {

						/* Immediate in Spur */
						intValue = characterValueOf(valueOop);
						goto l9;
					}
					if (isFloatObject(valueOop)) {

						/* Immediate in 64-bit Spur */
						intValue = floatValueOf(valueOop);
						goto l9;
					}
#          endif /* SPURVM */
				}
				else {
					
#          if SPURVM

					/* No non-immediate characters in Spur */
#          else /* SPURVM */
					if (isCharacterObject(valueOop)) {
						intValue = characterValueOf(valueOop);
						goto l9;
					}
#          endif /* SPURVM */
					if (isFloatObject(valueOop)) {
						intValue = floatValueOf(valueOop);
						goto l9;
					}
					if (valueOop == (nilObject())) {
						intValue = 0;
						goto l9;
					}
					if (valueOop == (falseObject())) {
						intValue = 0;
						goto l9;
					}
					if (valueOop == (trueObject())) {
						intValue = 1;
						goto l9;
					}
					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 l9;
#            else /* BytesPerWord == 8 */
						intValue = positive32BitValueOf(valueOop);
						goto l9;
#            endif /* BytesPerWord == 8 */
					}
				}
				intValue = signedMachineIntegerValueOf(valueOop);
	l9:	/* 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 l6;
		}
		floatValue = ((double) (ffiIntegerValueOf(valueOop)) );
	l6:	/* end ffiFloatValueOf: */;
		if (failed()) {
			return FFIErrorCoercionFailed;
		}
		if (atomicType2 == FFITypeSingleFloat) {
			/* begin ffiPushSingleFloat:in: */
			if (((calloutState->floatRegisterIndex)) < NumFloatRegArgs) {
				(((float *) (((calloutState->floatRegisters)) + ((calloutState->floatRegisterIndex)))))[0] = floatValue;
				/* begin incrementFloatRegisterIndex */
				(calloutState->floatRegisterSignature) = ((calloutState->floatRegisterSignature)) + (1U << ((calloutState->floatRegisterIndex)));
				(calloutState->integerRegisterIndex) = ((calloutState->floatRegisterIndex) = ((calloutState->floatRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				long64AtPointerput((calloutState->currentArg), 0);
				storeSingleFloatAtPointerfrom((calloutState->currentArg), floatValue);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			return 0;
		}
		else {
			/* begin ffiPushDoubleFloat:in: */
			if (((calloutState->floatRegisterIndex)) < NumFloatRegArgs) {
				((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)] = floatValue;
				/* begin incrementFloatRegisterIndex */
				(calloutState->floatRegisterSignature) = ((calloutState->floatRegisterSignature)) + (1U << ((calloutState->floatRegisterIndex)));
				(calloutState->integerRegisterIndex) = ((calloutState->floatRegisterIndex) = ((calloutState->floatRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				storeFloatAtPointerfrom((calloutState->currentArg), floatValue);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			return 0;
		}
	}
	return FFIErrorWrongType;
}


/*	Support for generic callout. Prepare a pointer reference to an atomic type
	for callout.
	Note: 
	for type 'void*' we allow ByteArray/String/Symbol, wordVariableSubclass,
	Alien or ExternalAddress.
	for other types we allow ByteArray, wordVariableSubclass, Alien or
	ExternalAddress. 
 */

	/* ThreadedFFIPlugin>>#ffiAtomicArgByReference:Class:in: */
static sqInt
ffiAtomicArgByReferenceClassin(sqInt oop, sqInt oopClass, CalloutState *calloutState)
{
    sqInt atomicType;
    char *copy;
    sqInt isAlien;
    sqInt isString;
    sqInt length;
    char *pointer;
    void *pointer1;
    void *pointer2;
    void *pointer3;
    void *pointer4;
    void *pointer5;
    void *pointer6;
    sqInt typeSpec;

	/* begin atomicTypeOf: */
	typeSpec = (calloutState->ffiArgHeader);
	atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
	if (atomicType == FFITypeBool) {

		/* No bools on input */
		return FFIErrorCoercionFailed;
	}
	isAlien = ((isString = includesBehaviorThatOf(oopClass, classString()))
		? 0
		: includesBehaviorThatOf(oopClass, classAlien()));
	if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {

		/* string value (char*) */
		/* note: the only types allowed for passing into char* types are
		   ByteArray, String, Symbol, Alien and *no* other byte indexed objects
		   (e.g., CompiledMethod, LargeInteger). We only check for strings
		   here and fall through to the byte* check otherwise. */
		if (isString) {

			/* String/Symbol */
			/* Strings must be allocated by the ffi support code */
			/* begin ffiPushString:OfLength:in: */
			pointer = ((char *) (firstIndexableField(oop)));
			length = byteSizeOf(oop);
			if (((calloutState->stringArgIndex)) >= MaxNumArgs) {
				return -PrimErrBadNumArgs;
			}
			copy = malloc(length + 1);
			if (copy == null) {
				return -PrimErrNoCMemory;
			}
			memcpy(copy, pointer, length);
			copy[length] = 0;
			((calloutState->stringArgs))[(calloutState->stringArgIndex)] = copy;
			(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) + 1);
			/* begin ffiPushPointer:in: */
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)copy));
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				longAtput((calloutState->currentArg), copy);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			return 0;
		}
		atomicType = FFITypeUnsignedByte;
	}
	
#  if COGMTVM

	/* Since all the following pass the address of the first indexable field we need to fail
	   the call if it is threaded and the object is young, since it may move during the call. */
	if ((((calloutState->callFlags)) & FFICallFlagThreaded)
	 && (((!isAlien)
	 || ((assert(isAlien(oop)),
	(longAt(oop + BaseHeaderSize)) > 0)))
	 && (isYoung(oop)))) {
		return -PrimErrObjectMayMove;
	}
#  endif /* COGMTVM */
	if ((atomicType == FFITypeVoid)
	 || ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedByte) >> 1))) {

		/* byte* -- see comment on string above */
		if (isString
		 || (oopClass == (classByteArray()))) {

			/* String/Symbol/ByteArray */
			/* begin ffiPushPointer:in: */
			pointer1 = ((void *) (firstIndexableField(oop)));
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer1));
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				longAtput((calloutState->currentArg), pointer1);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			return 0;
		}
		if (oopClass == (classExternalAddress())) {
			/* begin ffiPushPointer:in: */
			pointer2 = ((void *) (longAt(oop + BaseHeaderSize)));
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer2));
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				longAtput((calloutState->currentArg), pointer2);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			return 0;
		}
		if (isAlien) {
			/* begin ffiPushPointer:in: */
			pointer3 = pointerForOop(((longAt(oop + BaseHeaderSize)) > 0
				? (oop + BaseHeaderSize) + BytesPerOop
				: longAt((oop + BaseHeaderSize) + BytesPerOop)));
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer3));
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				longAtput((calloutState->currentArg), pointer3);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			return 0;
		}
		if (!(atomicType == FFITypeVoid)) {
			return FFIErrorCoercionFailed;
		}
	}
	if (atomicType <= FFITypeDoubleFloat) {
		if ((isWords(oop))
		 || (oopClass == (classByteArray()))) {
			/* begin ffiPushPointer:in: */
			pointer4 = ((void *) (firstIndexableField(oop)));
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer4));
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				longAtput((calloutState->currentArg), pointer4);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			return 0;
		}
		if (oopClass == (classExternalAddress())) {
			/* begin ffiPushPointer:in: */
			pointer5 = ((void *) (longAt(oop + BaseHeaderSize)));
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer5));
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				longAtput((calloutState->currentArg), pointer5);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			return 0;
		}
		if (isAlien) {
			/* begin ffiPushPointer:in: */
			pointer6 = pointerForOop(((longAt(oop + BaseHeaderSize)) > 0
				? (oop + BaseHeaderSize) + BytesPerOop
				: longAt((oop + BaseHeaderSize) + BytesPerOop)));
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer6));
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				longAtput((calloutState->currentArg), pointer6);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			return 0;
		}
	}
	return FFIErrorCoercionFailed;
}


/*	Support for generic callout. Prepare an external pointer reference to an
	atomic type for callout.
 */

	/* ThreadedFFIPlugin>>#ffiAtomicStructByReference:Class:in: */
static sqInt
ffiAtomicStructByReferenceClassin(sqInt oop, sqInt oopClass, CalloutState *calloutState)
{
    sqInt atomicType;
    sqInt err;
    sqInt ptrType;
    sqInt spec;
    sqInt specOop;
    sqInt specType;
    sqInt typeSpec;
    sqInt valueOop;


	/* must be external data to pass pointers to atomic type */
	if (!(oopClass == (classExternalData()))) {
		return FFIErrorCoercionFailed;
	}
	/* begin atomicTypeOf: */
	typeSpec = (calloutState->ffiArgHeader);
	atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
	if (atomicType != FFITypeVoid) {
		/* begin ffiValidateExternalData:AtomicType: */
		ptrType = fetchPointerofObject(1, oop);
		if (!((isPointers(ptrType))
			 && ((slotSizeOf(ptrType)) >= 2))) {
			err = FFIErrorWrongType;
			goto l3;
		}
		specOop = fetchPointerofObject(0, ptrType);
		if (!((isWords(specOop))
			 && ((slotSizeOf(specOop)) > 0))) {
			err = FFIErrorWrongType;
			goto l3;
		}
		spec = fetchPointerofObject(0, specOop);
		if (!(spec & FFIFlagAtomic)) {
			err = FFIErrorWrongType;
			goto l3;
		}
		/* begin atomicTypeOf: */
		specType = ((usqInt) (spec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
		if (specType != atomicType) {

			/* Allow for signed/unsigned conversion but nothing else.
			   See FFIConstants class>>#initializeTypeConstants */
			if (!((atomicType >= FFITypeUnsignedByte)
				 && ((atomicType <= FFITypeSignedChar)
				 && ((((usqInt) atomicType) >> 1) == (((usqInt) specType) >> 1))))) {
				err = FFIErrorCoercionFailed;
				goto l3;
			}
		}
		err = 0;
	l3:	/* end ffiValidateExternalData:AtomicType: */;
		if (err != 0) {
			return err;
		}
	}
	valueOop = fetchPointerofObject(0, oop);
	return ffiPushPointerContentsOfin(valueOop, calloutState);
}


/*	Go out, call this guy and create the return value. This *must* be inlined
	because of
	the alloca of the outgoing stack frame in
	ffiCall:WithFlags:NumArgs:Args:AndTypes: 
 */

	/* ThreadedX64Win64FFIPlugin>>#ffiCalloutTo:SpecOnStack:in: */
static sqInt
ffiCalloutToSpecOnStackin(void *procAddr, sqInt specOnStack, CalloutState *calloutState)
{
    sqInt argTypes;
    sqInt argTypes1;
    sqInt atomicType;
    sqInt atomicType1;
    sqInt byteSize;
    sqInt classOop;
    sqInt cPointer;
    char *cString;
    sqInt ffiRetType;
    double floatRet;
    sqInt i;
    usqLong intRet;
    extern void loadFloatRegs(double, double, double, double);
    usqLong mask;
    sqInt myThreadIndex;
    sqInt oop;
    sqInt oop1;
    sqInt *ptr;
    sqInt retClass;
    sqInt retClass1;
    sqInt retOop;
    sqInt retOop1;
    sqInt retType;
    sqInt shift;
    sqInt specLiteral;
    sqInt specLiteral1;
    sqInt strLen;
    sqInt strOop;
    char *strPtr;
    sqInt typeSpec;
    sqInt typeSpec1;
    usqLong value;

	myThreadIndex = disownVM(
#  if COGMTVM
		(((calloutState->callFlags)) & FFICallFlagThreaded
				? DisownVMForFFICall + DisownVMForThreading
				: DisownVMForFFICall)
#  else /* COGMTVM */
		DisownVMForFFICall
#  endif /* COGMTVM */
		);
	if (((calloutState->floatRegisterSignature)) > 0) {
		loadFloatRegs(((calloutState->floatRegisters))[0], ((calloutState->floatRegisters))[1], ((calloutState->floatRegisters))[2], ((calloutState->floatRegisters))[3]);
	}
	if ((allocaLiesSoSetSpBeforeCall())
	 || (mustAlignStack())) {
		setsp((calloutState->argVector));
	}
	/* begin atomicTypeOf: */
	typeSpec = (calloutState->ffiRetHeader);
	atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
	if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSingleFloat) >> 1)) {
		if (atomicType == FFITypeSingleFloat) {
			floatRet = dispatchFunctionPointerwithwithwithwith(((float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) procAddr), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3]);
		}
		else {

			/* atomicType = FFITypeDoubleFloat */
			floatRet = dispatchFunctionPointerwithwithwithwith(((double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) procAddr), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3]);
		}
		if (isCalleePopsConvention((calloutState->callFlags))) {
			setsp((calloutState->argVector));
		}
		ownVM(myThreadIndex);
		return floatObjectOf(floatRet);
	}

	/* undo any callee argument pops because it may confuse stack management with the alloca. */
	intRet = dispatchFunctionPointerwithwithwithwith(((usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) procAddr), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3]);
	if (isCalleePopsConvention((calloutState->callFlags))) {
		setsp((calloutState->argVector));
	}
	ownVM(myThreadIndex);
	if (((calloutState->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) {

		/* Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
		   'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct. */
		if (((calloutState->ffiRetHeader)) & FFIFlagPointer) {
			/* begin ffiReturnPointer:ofType:in: */
			specLiteral = (specOnStack
				? stackValue(1)
				: literalofMethod(0, primitiveMethod()));
			argTypes = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral);
			retType = fetchPointerofObject(0, argTypes);
			retClass = fetchPointerofObject(1, retType);
			if (retClass == (nilObject())) {

				/* Create ExternalData upon return */
				/* begin atomicTypeOf: */
				typeSpec1 = (calloutState->ffiRetHeader);
				atomicType1 = ((usqInt) (typeSpec1 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
				if ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {

					/* String return */
					/* begin ffiReturnCStringFrom: */
					cPointer = ((usqInt) intRet);
					if (!(cPointer)) {
						retOop = nilObject();
						goto l3;
					}
					cString = ((char *) cPointer);
					strLen = 0;
					while (!((cString[strLen]) == 0)) {
						strLen += 1;
					}
					strOop = instantiateClassindexableSize(classString(), strLen);
					strPtr = firstIndexableField(strOop);
					for (i = 0; i < strLen; i += 1) {
						strPtr[i] = (cString[i]);
					}
					retOop = strOop;
	l3:	/* end ffiReturnCStringFrom: */;
					return retOop;
				}
				
#if SPURVM
				oop = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
				ptr = firstIndexableField(oop);
				ptr[0] = (((sqInt) intRet));
				retOop = instantiateClassindexableSize(classExternalData(), 0);
				storePointerofObjectwithValue(0, retOop, oop);

#else /* SPURVM */
				pushRemappableOop(retType);
				oop = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
				ptr = firstIndexableField(oop);
				ptr[0] = (((sqInt) intRet));
								pushRemappableOop(oop);
				retOop = instantiateClassindexableSize(classExternalData(), 0);
				oop = popRemappableOop();
				storePointerofObjectwithValue(0, retOop, oop);
				retType = popRemappableOop()
#endif /* SPURVM */
;
				storePointerofObjectwithValue(1, retOop, retType);
				return retOop;
			}
			classOop = (((calloutState->ffiRetHeader)) & FFIFlagStructure
				? classByteArray()
				: classExternalAddress());
			
#if SPURVM
			oop = instantiateClassindexableSize(classOop, BytesPerWord);

#else /* SPURVM */
			pushRemappableOop(retClass);
			oop = instantiateClassindexableSize(classOop, BytesPerWord);
			retClass = popRemappableOop()
#endif /* SPURVM */
;
			ptr = firstIndexableField(oop);
			ptr[0] = (((sqInt) intRet));
			
#if SPURVM
			retOop = instantiateClassindexableSize(retClass, 0);

#else /* SPURVM */
			pushRemappableOop(oop);
			retOop = instantiateClassindexableSize(retClass, 0);
			oop = popRemappableOop()
#endif /* SPURVM */
;
			storePointerofObjectwithValue(0, retOop, oop);
			return retOop;
		}
		/* begin ffiReturnStruct:ofType:in: */
		specLiteral1 = (specOnStack
			? stackValue(1)
			: literalofMethod(0, primitiveMethod()));
		argTypes1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral1);
		ffiRetType = fetchPointerofObject(0, argTypes1);
		retClass1 = fetchPointerofObject(1, ffiRetType);
		retOop1 = instantiateClassindexableSize(retClass1, 0);
		
#if SPURVM
		oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));

#else /* SPURVM */
		pushRemappableOop(retOop1);
		oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
		retOop1 = popRemappableOop()
#endif /* SPURVM */
;
		memcpy(firstIndexableField(oop1), ((((calloutState->structReturnSize)) <= WordSize)
		 && ((((calloutState->structReturnSize)) & (((calloutState->structReturnSize)) - 1)) == 0)
			? (&intRet)
			: (calloutState->limit)), (calloutState->structReturnSize));
		storePointerofObjectwithValue(0, retOop1, oop1);
		return retOop1;
	}
	/* begin ffiCreateIntegralResultOop:ofAtomicType:in: */
	assert(atomicType < FFITypeSingleFloat);
	if (atomicType == FFITypeBool) {

		/* Make sure bool honors the byte size requested */
		byteSize = ((calloutState->ffiRetHeader)) & FFIStructSizeMask;
		value = (byteSize == (sizeof(intRet))
			? intRet
			: intRet & (((((unsigned long long)1)) << (byteSize * 8)) - 1));
		return (value == 0
			? falseObject()
			: trueObject());
	}
	if (atomicType <= FFITypeSignedInt) {

		/* these are all generall integer returns */
		if (atomicType <= ((BytesPerWord == 8
			? FFITypeSignedInt
			: FFITypeSignedShort))) {

			/* byte/short. first extract partial word, then sign extend */

			/* # of significant bits */
			shift = ((BytesPerWord == 8)
			 && (atomicType >= FFITypeUnsignedInt)
				? 32
				: (((usqInt) atomicType) >> 1) * 8);
			value = intRet & (((((unsigned long long)1)) << shift) - 1);
			if (atomicType & 1) {

				/* make the guy signed */
				mask = (((unsigned long long)1)) << (shift - 1);
				value = (value & (mask - 1)) - (value & mask);
			}
			return integerObjectOf(value);
		}
		return (atomicType & 1
			? (BytesPerWord == 8
					? signed64BitIntegerFor(intRet)
					: signed32BitIntegerFor(intRet))
			: (BytesPerWord == 8
					? positive64BitIntegerFor(intRet)
					: positive32BitIntegerFor(intRet)));
	}
	return ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
		? (atomicType & 1
				? signed64BitIntegerFor(intRet)
				: positive64BitIntegerFor(intRet))
		: characterObjectOf(intRet & 0xFF));
}


/*	Generic callout. Does the actual work. If argArrayOrNil is nil it takes
	args from the stack
	and the spec from the method. If argArrayOrNil is not nil takes args from
	argArrayOrNil and the spec from the receiver. */

	/* ThreadedFFIPlugin>>#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 atomicType;
    sqInt atomicType1;
    sqInt byteSize;
    CalloutState *calloutState;
    sqInt classOop;
    sqInt cPointer;
    char *cString;
    sqInt err;
    sqInt ffiRetType;
    sqInt flags;
    double floatRet;
    sqInt functionName;
    sqInt i;
    sqInt i1;
    usqLong intRet;
    extern void loadFloatRegs(double, double, double, double);
    usqLong mask;
    sqInt myThreadIndex;
    sqInt oop;
    sqInt oop1;
    sqInt oop2;
    void *pointer;
    sqInt primNumArgs;
    sqIntptr_t *ptr;
    sqInt *ptr1;
    sqInt requiredStackSize;
    sqInt result;
    sqInt retClass;
    sqInt retClass1;
    sqInt retOop;
    sqInt retOop1;
    sqInt retType;
    sqInt shift;
    sqInt specLiteral;
    sqInt specLiteral1;
    sqInt stackSize;
    sqInt strLen;
    sqInt strOop;
    char *strPtr;
    CalloutState theCalloutState;
    sqInt typeSpec;
    sqInt typeSpec1;
    usqLong value;

	primNumArgs = methodArgumentCount();
	if (!(isKindOfClass(externalFunction, classExternalFunction()))) {
		return ffiFail(FFIErrorNotFunction);
	}
	flags = fetchIntegerofObject(ExternalFunctionFlagsIndex, externalFunction);
	if (failed()) {
		return ffiFail(FFIErrorBadArgs);
	}
	/* begin ffiLoadCalloutAddress: */

	/* Make sure it's an external handle */
	addressPtr = fetchPointerofObject(0, externalFunction);
	if (!((isBytes(addressPtr))
		 && ((byteSizeOf(addressPtr)) == (sizeof(sqInt))))) {
		address1 = ffiFail(FFIErrorBadAddress);
		goto l1;
	}
	address1 = fetchPointerofObject(0, addressPtr);
	l1:	/* end ffiContentsOfHandle:errCode: */;
	if (failed()) {
		address = 0;
		goto l2;
	}
	if (address1 == 0) {

		/* Go look it up in the module */
		if (externalFunctionInstSize > ExternalFunctionStackSizeIndex) {
			storePointerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, integerObjectOf(-1));
		}
		if ((slotSizeOf(externalFunction)) < 5) {
			address = ffiFail(FFIErrorNoModule);
			goto l2;
		}
		address1 = ffiLoadCalloutAddressFrom(externalFunction);
		if (failed()) {
			address = 0;
			goto l2;
		}
		ptr = firstIndexableField(addressPtr);
		ptr[0] = address1;
	}
	address = address1;
	l2:	/* end ffiLoadCalloutAddress: */;
	if (failed()) {
		return 0;
	}

	/* must be array of arg types */
	argTypeArray = fetchPointerofObject(ExternalFunctionArgTypesIndex, externalFunction);
	if (!((isArray(argTypeArray))
		 && ((slotSizeOf(argTypeArray)) == (nArgs + 1)))) {
		return ffiFail(FFIErrorBadArgs);
	}
	
#  if COGMTVM
	if (!(((flags & FFICallTypesMask) == FFICallTypeCDecl)
		 || ((flags & FFICallTypesMask) == FFICallTypeApi))) {
		return ffiFail(FFIErrorCallType);
	}
#  else /* COGMTVM */

	/* not masking causes threaded calls to fail, which is as they should if the plugin is not threaded. */
	if (!((flags == FFICallTypeCDecl)
		 || (flags == FFICallTypeApi))) {
		return ffiFail(FFIErrorCallType);
	}
#  endif /* COGMTVM */
	requiredStackSize = (externalFunctionInstSize > ExternalFunctionStackSizeIndex
		? fetchIntegerofObject(ExternalFunctionStackSizeIndex, externalFunction)
		: -1);
	if (failed()) {
		return primitiveFailFor((argArrayOrNil == null
			? PrimErrBadMethod
			: PrimErrBadReceiver));
	}
	stackSize = (requiredStackSize < 0
		? DefaultMaxStackSize
		: requiredStackSize);
	calloutState = (&theCalloutState);
	memset(calloutState, 0, sizeof(CalloutState));
	(calloutState->callFlags = flags);
	argType = fetchPointerofObject(0, argTypeArray);
	argSpec = fetchPointerofObject(0, argType);
	argClass = fetchPointerofObject(1, argType);
	if (((err = ffiCheckReturnWithin(argSpec, argClass, calloutState))) != 0) {
		return ffiFail(err);
	}
	allocation = alloca((stackSize + ((calloutState->structReturnSize))) + (cStackAlignment()));
	if (mustAlignStack()) {
		allocation = ((char *) ((((((usqIntptr_t)allocation)) | ((cStackAlignment()) - 1)) - ((cStackAlignment()) - 1))));
	}
	(calloutState->argVector = allocation);
	(calloutState->currentArg = allocation);
	(calloutState->limit = allocation + stackSize);
	if ((((calloutState->structReturnSize)) > 0)
	 && (1
	 && (!((((calloutState->structReturnSize)) <= WordSize)
	 && ((((calloutState->structReturnSize)) & (((calloutState->structReturnSize)) - 1)) == 0))))) {
		/* begin ffiPushPointer:in: */
		pointer = (calloutState->limit);
		if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
			((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer));
			(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
		}
		else {
			if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
				err = FFIErrorCallFrameTooBig;
				goto l4;
			}
			longAtput((calloutState->currentArg), pointer);
			(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
		}
		err = 0;
	l4:	/* end ffiPushPointer:in: */;
		if (err != 0) {
			/* begin cleanupCalloutState: */
			while (((calloutState->stringArgIndex)) > 0) {
				free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
			}
			
#      if COGMTVM
			if (err == (-PrimErrObjectMayMove)) {
				return PrimErrObjectMayMove;
			}
#      endif /* COGMTVM */
			return ffiFail(err);
		}
	}
	for (i = 1; i <= nArgs; i += 1) {
		argType = fetchPointerofObject(i, argTypeArray);
		argSpec = fetchPointerofObject(0, argType);
		argClass = fetchPointerofObject(1, argType);
		oop = (argArrayOrNil == null
			? stackValue(nArgs - i)
			: fetchPointerofObject(i - 1, argArrayOrNil));
		err = ffiArgumentSpecClassin(oop, argSpec, argClass, calloutState);
		if (err != 0) {
			/* begin cleanupCalloutState: */
			while (((calloutState->stringArgIndex)) > 0) {
				free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
			}
			
#      if COGMTVM
			if (err == (-PrimErrObjectMayMove)) {
				return PrimErrObjectMayMove;
			}
#      endif /* COGMTVM */
			return ffiFail(err);
		}
	}
	assert(!(failed()));
	/* begin ffiLogCallout: */
	if (ffiLogEnabled) {
		functionName = fetchPointerofObject(externalFunctionInstSize, externalFunction);
		if (!(isBytes(functionName))) {
			goto l3;
		}
		ffiLogCallOfLength(firstIndexableField(functionName), byteSizeOf(functionName));
	}
	l3:	/* end ffiLogCallout: */;
	if ((requiredStackSize < 0)
	 && (externalFunctionInstSize > ExternalFunctionStackSizeIndex)) {
		stackSize = ((calloutState->currentArg)) - ((calloutState->argVector));
		storeIntegerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, stackSize);
	}
	/* begin ffiCalloutTo:SpecOnStack:in: */
	myThreadIndex = disownVM(
#  if COGMTVM
		(((calloutState->callFlags)) & FFICallFlagThreaded
				? DisownVMForFFICall + DisownVMForThreading
				: DisownVMForFFICall)
#  else /* COGMTVM */
		DisownVMForFFICall
#  endif /* COGMTVM */
		);
	if (((calloutState->floatRegisterSignature)) > 0) {
		loadFloatRegs(((calloutState->floatRegisters))[0], ((calloutState->floatRegisters))[1], ((calloutState->floatRegisters))[2], ((calloutState->floatRegisters))[3]);
	}
	if ((allocaLiesSoSetSpBeforeCall())
	 || (mustAlignStack())) {
		setsp((calloutState->argVector));
	}
	/* begin atomicTypeOf: */
	typeSpec = (calloutState->ffiRetHeader);
	atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
	if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSingleFloat) >> 1)) {
		if (atomicType == FFITypeSingleFloat) {
			floatRet = dispatchFunctionPointerwithwithwithwith(((float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3]);
		}
		else {

			/* atomicType = FFITypeDoubleFloat */
			floatRet = dispatchFunctionPointerwithwithwithwith(((double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3]);
		}
		if (isCalleePopsConvention((calloutState->callFlags))) {
			setsp((calloutState->argVector));
		}
		ownVM(myThreadIndex);
		result = floatObjectOf(floatRet);
		goto l9;
	}

	/* undo any callee argument pops because it may confuse stack management with the alloca. */
	intRet = dispatchFunctionPointerwithwithwithwith(((usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3]);
	if (isCalleePopsConvention((calloutState->callFlags))) {
		setsp((calloutState->argVector));
	}
	ownVM(myThreadIndex);
	if (((calloutState->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) {

		/* Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
		   'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct. */
		if (((calloutState->ffiRetHeader)) & FFIFlagPointer) {
			/* begin ffiReturnPointer:ofType:in: */
			specLiteral = (argArrayOrNil != null
				? stackValue(1)
				: literalofMethod(0, primitiveMethod()));
			argTypes = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral);
			retType = fetchPointerofObject(0, argTypes);
			retClass = fetchPointerofObject(1, retType);
			if (retClass == (nilObject())) {

				/* Create ExternalData upon return */
				/* begin atomicTypeOf: */
				typeSpec1 = (calloutState->ffiRetHeader);
				atomicType1 = ((usqInt) (typeSpec1 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
				if ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {

					/* String return */
					/* begin ffiReturnCStringFrom: */
					cPointer = ((usqInt) intRet);
					if (!(cPointer)) {
						retOop = nilObject();
						goto l5;
					}
					cString = ((char *) cPointer);
					strLen = 0;
					while (!((cString[strLen]) == 0)) {
						strLen += 1;
					}
					strOop = instantiateClassindexableSize(classString(), strLen);
					strPtr = firstIndexableField(strOop);
					for (i1 = 0; i1 < strLen; i1 += 1) {
						strPtr[i1] = (cString[i1]);
					}
					retOop = strOop;
	l5:	/* end ffiReturnCStringFrom: */;
					result = retOop;
					goto l9;
				}
				
#if SPURVM
				oop2 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
				ptr1 = firstIndexableField(oop2);
				ptr1[0] = (((sqInt) intRet));
				retOop = instantiateClassindexableSize(classExternalData(), 0);
				storePointerofObjectwithValue(0, retOop, oop2);

#else /* SPURVM */
				pushRemappableOop(retType);
				oop2 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
				ptr1 = firstIndexableField(oop2);
				ptr1[0] = (((sqInt) intRet));
								pushRemappableOop(oop2);
				retOop = instantiateClassindexableSize(classExternalData(), 0);
				oop2 = popRemappableOop();
				storePointerofObjectwithValue(0, retOop, oop2);
				retType = popRemappableOop()
#endif /* SPURVM */
;
				storePointerofObjectwithValue(1, retOop, retType);
				result = retOop;
				goto l9;
			}
			classOop = (((calloutState->ffiRetHeader)) & FFIFlagStructure
				? classByteArray()
				: classExternalAddress());
			
#if SPURVM
			oop2 = instantiateClassindexableSize(classOop, BytesPerWord);

#else /* SPURVM */
			pushRemappableOop(retClass);
			oop2 = instantiateClassindexableSize(classOop, BytesPerWord);
			retClass = popRemappableOop()
#endif /* SPURVM */
;
			ptr1 = firstIndexableField(oop2);
			ptr1[0] = (((sqInt) intRet));
			
#if SPURVM
			retOop = instantiateClassindexableSize(retClass, 0);

#else /* SPURVM */
			pushRemappableOop(oop2);
			retOop = instantiateClassindexableSize(retClass, 0);
			oop2 = popRemappableOop()
#endif /* SPURVM */
;
			storePointerofObjectwithValue(0, retOop, oop2);
			result = retOop;
			goto l9;
		}
		/* begin ffiReturnStruct:ofType:in: */
		specLiteral1 = (argArrayOrNil != null
			? stackValue(1)
			: literalofMethod(0, primitiveMethod()));
		argTypes1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral1);
		ffiRetType = fetchPointerofObject(0, argTypes1);
		retClass1 = fetchPointerofObject(1, ffiRetType);
		retOop1 = instantiateClassindexableSize(retClass1, 0);
		
#if SPURVM
		oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));

#else /* SPURVM */
		pushRemappableOop(retOop1);
		oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
		retOop1 = popRemappableOop()
#endif /* SPURVM */
;
		memcpy(firstIndexableField(oop1), ((((calloutState->structReturnSize)) <= WordSize)
		 && ((((calloutState->structReturnSize)) & (((calloutState->structReturnSize)) - 1)) == 0)
			? (&intRet)
			: (calloutState->limit)), (calloutState->structReturnSize));
		storePointerofObjectwithValue(0, retOop1, oop1);
		result = retOop1;
		goto l9;
	}
	/* 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 l9;
	}
	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 l9;
		}
		result = (atomicType & 1
			? (BytesPerWord == 8
					? signed64BitIntegerFor(intRet)
					: signed32BitIntegerFor(intRet))
			: (BytesPerWord == 8
					? positive64BitIntegerFor(intRet)
					: positive32BitIntegerFor(intRet)));
		goto l9;
	}
	result = ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
		? (atomicType & 1
				? signed64BitIntegerFor(intRet)
				: positive64BitIntegerFor(intRet))
		: characterObjectOf(intRet & 0xFF));
	l9:	/* end ffiCalloutTo:SpecOnStack:in: */;
	/* begin cleanupCalloutState: */
	while (((calloutState->stringArgIndex)) > 0) {
		free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
	}
	popthenPush(primNumArgs + 1, result);
	return result;
}


/*	Make sure we can return an object of the given type */

	/* ThreadedFFIPlugin>>#ffiCheckReturn:With:in: */
static sqInt
ffiCheckReturnWithin(sqInt retSpec, sqInt retClass, CalloutState *calloutState)
{
	if (!(retClass == (nilObject()))) {
		if (!(includesBehaviorThatOf(retClass, classExternalStructure()))) {
			return FFIErrorBadReturn;
		}
	}
	if (!((isWords(retSpec))
		 && ((slotSizeOf(retSpec)) > 0))) {
		return FFIErrorWrongType;
	}
	(calloutState->ffiRetHeader = fetchLong32ofObject(0, retSpec));
	if (!(((calloutState->ffiRetHeader)) & FFIFlagAtomic)) {
		if (retClass == (nilObject())) {
			return FFIErrorBadReturn;
		}
	}
	if ((((calloutState->ffiRetHeader)) & (FFIFlagPointer | FFIFlagStructure)) == FFIFlagStructure) {
		(calloutState->structReturnSize = ((calloutState->ffiRetHeader)) & FFIStructSizeMask);
	}
	return 0;
}


/*	Make sure that the given oop is a valid external handle */

	/* ThreadedFFIPlugin>>#ffiContentsOfHandle:errCode: */
static sqInt
ffiContentsOfHandleerrCode(sqInt oop, sqInt errCode)
{
	if (!((isBytes(oop))
		 && ((byteSizeOf(oop)) == (sizeof(sqInt))))) {
		return ffiFail(errCode);
	}
	return fetchPointerofObject(0, oop);
}


/*	Callout support. Return the appropriate oop for the given atomic type */

	/* ThreadedFFIPlugin>>#ffiCreateIntegralResultOop:ofAtomicType:in: */
static sqInt
ffiCreateIntegralResultOopofAtomicTypein(usqLong retVal, sqInt atomicType, CalloutState *calloutState)
{
    sqInt byteSize;
    usqLong mask;
    sqInt shift;
    usqLong value;

	assert(atomicType < FFITypeSingleFloat);
	if (atomicType == FFITypeBool) {

		/* Make sure bool honors the byte size requested */
		byteSize = ((calloutState->ffiRetHeader)) & FFIStructSizeMask;
		value = (byteSize == (sizeof(retVal))
			? retVal
			: retVal & (((((unsigned long long)1)) << (byteSize * 8)) - 1));
		return (value == 0
			? falseObject()
			: trueObject());
	}
	if (atomicType <= FFITypeSignedInt) {

		/* these are all generall integer returns */
		if (atomicType <= ((BytesPerWord == 8
			? FFITypeSignedInt
			: FFITypeSignedShort))) {

			/* byte/short. first extract partial word, then sign extend */

			/* # of significant bits */
			shift = ((BytesPerWord == 8)
			 && (atomicType >= FFITypeUnsignedInt)
				? 32
				: (((usqInt) atomicType) >> 1) * 8);
			value = retVal & (((((unsigned long long)1)) << shift) - 1);
			if (atomicType & 1) {

				/* make the guy signed */
				mask = (((unsigned long long)1)) << (shift - 1);
				value = (value & (mask - 1)) - (value & mask);
			}
			return integerObjectOf(value);
		}
		return (atomicType & 1
			? (BytesPerWord == 8
					? signed64BitIntegerFor(retVal)
					: signed32BitIntegerFor(retVal))
			: (BytesPerWord == 8
					? positive64BitIntegerFor(retVal)
					: positive32BitIntegerFor(retVal)));
	}
	return ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
		? (atomicType & 1
				? signed64BitIntegerFor(retVal)
				: positive64BitIntegerFor(retVal))
		: characterObjectOf(retVal & 0xFF));
}


/*	Map the FFI error code into a primitive error code. If reason is negative
	it encodes one of the
	standard PrimErr... codes, negated to distinguish it from the FFIError
	codes. If it is an FFIError...
	code then add the size of the primitive error table + 2 to disambiguate it
	from the PrimErr... codes.
	For historic reasons the FFIError codes range from -1 on up hence adding
	size + 2 maps them to
	size of table + 1 on up. This OFFSET IS undone by ExternalFunction
	class>>externalCallFailedWith:. Thus we can communicate back both
	PrimErr.. and FFIError codes. Complex but necessary. */

	/* ThreadedFFIPlugin>>#ffiFail: */
static sqInt
ffiFail(sqInt reason)
{
	ffiLastError = reason;
	return primitiveFailFor((reason >= FFINoCalloutAvailable
		? (reason + 2) + (slotSizeOf(primitiveErrorTable()))
		: -reason));
}


/*	Support for generic callout. Return a float value that is coerced as C
	would do.
 */

	/* ThreadedFFIPlugin>>#ffiFloatValueOf: */
static double
ffiFloatValueOf(sqInt oop)
{
	if (isFloatObject(oop)) {
		return floatValueOf(oop);
	}
	return ((double) (ffiIntegerValueOf(oop)) );
}


/*	Support for generic callout. Answer an integer value that is coerced as C
	would do.
 */
/*	Cheat with a tag test */

	/* ThreadedFFIPlugin>>#ffiIntegerValueOf: */
static sqInt
ffiIntegerValueOf(sqInt oop)
{
	if (oop & (BytesPerWord - 1)) {
		if (isIntegerObject(oop)) {
			return integerValueOf(oop);
		}
		
#    if SPURVM
		if (isCharacterObject(oop)) {

			/* Immediate in Spur */
			return characterValueOf(oop);
		}
		if (isFloatObject(oop)) {

			/* Immediate in 64-bit Spur */
			return floatValueOf(oop);
		}
#    endif /* SPURVM */
	}
	else {
		
#    if SPURVM

		/* No non-immediate characters in Spur */
#    else /* SPURVM */
		if (isCharacterObject(oop)) {
			return characterValueOf(oop);
		}
#    endif /* SPURVM */
		if (isFloatObject(oop)) {
			return floatValueOf(oop);
		}
		if (oop == (nilObject())) {
			return 0;
		}
		if (oop == (falseObject())) {
			return 0;
		}
		if (oop == (trueObject())) {
			return 1;
		}
		if (isLargePositiveIntegerObject(oop)) {
			
#      if BytesPerWord == 8

			/* Use cppIf: to get the return type of the function right.  Should be sqInt on 32-bits. */
			return positive64BitValueOf(oop);
#      else /* BytesPerWord == 8 */
			return positive32BitValueOf(oop);
#      endif /* BytesPerWord == 8 */
		}
	}
	return signedMachineIntegerValueOf(oop);
}


/*	Load the function address for a call out to an external function */

	/* ThreadedFFIPlugin>>#ffiLoadCalloutAddressFrom: */
static sqInt
ffiLoadCalloutAddressFrom(sqInt oop)
{
    sqInt address;
    sqInt functionName;
    sqInt module;
    sqInt moduleHandle;


	/* First find and load the module */
	module = fetchPointerofObject(externalFunctionInstSize + 1, oop);
	moduleHandle = ffiLoadCalloutModule(module);
	if (failed()) {
		return 0;
	}
	functionName = fetchPointerofObject(externalFunctionInstSize, oop);
	if (!(isBytes(functionName))) {
		return ffiFail(FFIErrorBadExternalFunction);
	}
	address = ((sqInt)(ioLoadSymbolOfLengthFromModule(((sqInt)(firstIndexableField(functionName))), byteSizeOf(functionName), moduleHandle)));
	if ((failed())
	 || (address == 0)) {
		return ffiFail(FFIErrorAddressNotFound);
	}
	return address;
}


/*	Load the address of the foreign function from the given object */

	/* ThreadedFFIPlugin>>#ffiLoadCalloutAddress: */
static sqInt
ffiLoadCalloutAddress(sqInt lit)
{
    sqInt address;
    sqInt addressPtr;
    sqIntptr_t *ptr;


	/* Lookup the address */

	/* Make sure it's an external handle */
	addressPtr = fetchPointerofObject(0, lit);
	/* begin ffiContentsOfHandle:errCode: */
	if (!((isBytes(addressPtr))
		 && ((byteSizeOf(addressPtr)) == (sizeof(sqInt))))) {
		address = ffiFail(FFIErrorBadAddress);
		goto l1;
	}
	address = fetchPointerofObject(0, addressPtr);
	l1:	/* end ffiContentsOfHandle:errCode: */;
	if (failed()) {
		return 0;
	}
	if (address == 0) {

		/* Go look it up in the module */
		if (externalFunctionInstSize > ExternalFunctionStackSizeIndex) {
			storePointerofObjectwithValue(ExternalFunctionStackSizeIndex, lit, integerObjectOf(-1));
		}
		if ((slotSizeOf(lit)) < 5) {
			return ffiFail(FFIErrorNoModule);
		}
		address = ffiLoadCalloutAddressFrom(lit);
		if (failed()) {
			return 0;
		}
		ptr = firstIndexableField(addressPtr);
		ptr[0] = address;
	}
	return address;
}


/*	Load the given module and return its handle */

	/* ThreadedFFIPlugin>>#ffiLoadCalloutModule: */
static sqInt
ffiLoadCalloutModule(sqInt module)
{
    sqInt ffiModuleName;
    sqInt moduleHandle;
    sqInt moduleHandlePtr;
    sqInt moduleLength;
    sqInt *ptr;
    sqInt rcvr;

	if (isBytes(module)) {

		/* plain module name */
		ffiModuleName = module;
		moduleLength = byteSizeOf(ffiModuleName);
		moduleHandle = ((sqInt)(ioLoadModuleOfLength(((sqInt)(firstIndexableField(ffiModuleName))), moduleLength)));
		if ((failed())
		 || (moduleHandle == 0)) {
			return ffiFail(FFIErrorModuleNotFound);
		}
		return moduleHandle;
	}
	rcvr = stackValue(methodArgumentCount());
	if (!(isKindOfClass(rcvr, classExternalLibrary()))) {
		return ffiFail(FFIErrorNoModule);
	}
	moduleHandlePtr = fetchPointerofObject(0, rcvr);
	/* begin ffiContentsOfHandle:errCode: */
	if (!((isBytes(moduleHandlePtr))
		 && ((byteSizeOf(moduleHandlePtr)) == (sizeof(sqInt))))) {
		moduleHandle = ffiFail(FFIErrorBadExternalLibrary);
		goto l1;
	}
	moduleHandle = fetchPointerofObject(0, moduleHandlePtr);
	l1:	/* end ffiContentsOfHandle:errCode: */;
	if (failed()) {
		return 0;
	}
	if (moduleHandle == 0) {

		/* need to reload module */
		ffiModuleName = fetchPointerofObject(1, rcvr);
		if (!(isBytes(ffiModuleName))) {
			return ffiFail(FFIErrorBadExternalLibrary);
		}
		moduleLength = byteSizeOf(ffiModuleName);
		moduleHandle = ((sqInt)(ioLoadModuleOfLength(((sqInt)(firstIndexableField(ffiModuleName))), moduleLength)));
		if ((failed())
		 || (moduleHandle == 0)) {
			return ffiFail(FFIErrorModuleNotFound);
		}
		ptr = firstIndexableField(moduleHandlePtr);
		ptr[0] = moduleHandle;
	}
	return moduleHandle;
}


/*	fetch the function name */

	/* ThreadedFFIPlugin>>#ffiLogCallout: */
static void
ffiLogCallout(sqInt lit)
{
    sqInt functionName;

	if (ffiLogEnabled) {
		functionName = fetchPointerofObject(externalFunctionInstSize, lit);
		if (!(isBytes(functionName))) {
			return;
		}
		ffiLogCallOfLength(firstIndexableField(functionName), byteSizeOf(functionName));
	}
}


/*	This is a special entry point exposed such that client code can 
	enable and disable logging of FFI calls. */

	/* ThreadedFFIPlugin>>#ffiLogCallsTo: */
EXPORT(sqInt)
ffiLogCallsTo(char *fileName)
{
    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(ptrAddress)) {
			return FFIErrorInvalidPointer;
		}
		/* begin ffiPushPointer:in: */
		if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
			((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
			(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
		}
		else {
			if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
				return FFIErrorCallFrameTooBig;
			}
			longAtput((calloutState->currentArg), ptrAddress);
			(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
		}
		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->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
		}
		else {
			if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
				return FFIErrorCallFrameTooBig;
			}
			longAtput((calloutState->currentArg), ptrAddress);
			(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
		}
		return 0;
	}
	if (includesBehaviorThatOf(ptrClass, classAlien())) {
		
#    if COGMTVM
		if ((((calloutState->callFlags)) & FFICallFlagThreaded)
		 && (((assert(isAlien(oop)),
		(longAt(oop + BaseHeaderSize)) > 0))
		 && (isYoung(oop)))) {
			return -PrimErrObjectMayMove;
		}
#    endif /* COGMTVM */
		ptrAddress = ((longAt(oop + BaseHeaderSize)) > 0
			? (oop + BaseHeaderSize) + BytesPerOop
			: longAt((oop + BaseHeaderSize) + BytesPerOop));
		/* begin ffiPushPointer:in: */
		if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
			((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
			(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
		}
		else {
			if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
				return FFIErrorCallFrameTooBig;
			}
			longAtput((calloutState->currentArg), ptrAddress);
			(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
		}
		return 0;
	}
	return FFIErrorBadArg;
}

	/* ThreadedX64FFIPlugin>>#ffiPushPointer:in: */
static sqInt
ffiPushPointerin(void *pointer, CalloutState *calloutState)
{
	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer));
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), pointer);
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	return 0;
}

	/* ThreadedX64FFIPlugin>>#ffiPushSignedByte:in: */
static sqInt
ffiPushSignedBytein(sqInt value, CalloutState *calloutState)
{
	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((signed char) value));
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), ((signed char) value));
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	return 0;
}

	/* ThreadedX64FFIPlugin>>#ffiPushSignedChar:in: */
static sqInt
ffiPushSignedCharin(sqInt value, CalloutState *calloutState)
{
	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((signed char) value));
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), ((signed char) value));
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	return 0;
}

	/* ThreadedX64FFIPlugin>>#ffiPushSignedInt:in: */
static sqInt
ffiPushSignedIntin(sqInt value, CalloutState *calloutState)
{
	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = value;
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), value);
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	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)] = (((usqInt) value));
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), value);
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	return 0;
}

	/* ThreadedX64FFIPlugin>>#ffiPushSignedLongLong:in: */
static sqInt
ffiPushSignedLongLongin(sqLong value, CalloutState *calloutState)
{
	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((usqInt) value));
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), value);
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	return 0;
}

	/* ThreadedX64FFIPlugin>>#ffiPushSignedShort:in: */
static sqInt
ffiPushSignedShortin(sqInt value, CalloutState *calloutState)
{
	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((signed short) value));
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), ((signed short) value));
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	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->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), copy);
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	return 0;
}


/*	Push the contents of the given external structure */

	/* ThreadedFFIPlugin>>#ffiPushStructureContentsOf:in: */
static sqInt
ffiPushStructureContentsOfin(sqInt oop, CalloutState *calloutState)
{
    usqLong arg;
    usqLong arg1;
    sqInt *argSpec;
    sqInt *argSpec1;
    sqInt argSpecSize;
    sqInt argSpecSize1;
    void * ptrAddress;
    sqInt ptrClass;
    sqInt structSize;
    sqInt structSize1;

	arg = 0;
	arg1 = 0;
	ptrClass = fetchClassOf(oop);
	if (ptrClass == (classExternalAddress())) {

		/* ExternalAddress is bytes */

		/* There is no way we can make sure the structure is valid.
		   But we can at least check for attempts to pass pointers to ST memory. */
		ptrAddress = ((void *)(fetchPointerofObject(0, oop)));
		if (isInMemory(ptrAddress)) {
			return FFIErrorInvalidPointer;
		}
		/* begin ffiPushStructure:ofSize:typeSpec:ofLength:in: */
		structSize = ((calloutState->ffiArgHeader)) & FFIStructSizeMask;
		argSpec = (calloutState->ffiArgSpec);
		argSpecSize = (calloutState->ffiArgSpecSize);
		if (structSize <= 0) {
			return FFIErrorStructSize;
		}
		if ((structSize <= WordSize)
		 && ((structSize & (structSize - 1)) == 0)) {
			memcpy((&arg), ptrAddress, structSize);
			/* begin ffiPushUnsignedLongLong:in: */
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = arg;
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				longAtput((calloutState->currentArg), arg);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			return 0;
		}
		flag("quick hack");
		/* begin ffiPushPointer:in: */
		if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
			((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
			(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
		}
		else {
			if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
				return FFIErrorCallFrameTooBig;
			}
			longAtput((calloutState->currentArg), ptrAddress);
			(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
		}
		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 (structSize1 <= 0) {
				return FFIErrorStructSize;
			}
			if ((structSize1 <= WordSize)
			 && ((structSize1 & (structSize1 - 1)) == 0)) {
				memcpy((&arg1), ptrAddress, structSize1);
				/* begin ffiPushUnsignedLongLong:in: */
				if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
					((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = arg1;
					(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
				}
				else {
					if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
						return FFIErrorCallFrameTooBig;
					}
					longAtput((calloutState->currentArg), arg1);
					(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
				}
				return 0;
			}
			flag("quick hack");
			/* begin ffiPushPointer:in: */
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					return FFIErrorCallFrameTooBig;
				}
				longAtput((calloutState->currentArg), ptrAddress);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			return 0;
		}
		if (!((((calloutState->ffiArgHeader)) & FFIStructSizeMask) == BytesPerWord)) {
			return FFIErrorStructSize;
		}
		ptrAddress = ((void *)(fetchPointerofObject(0, oop)));
		if (isInMemory(ptrAddress)) {
			return FFIErrorInvalidPointer;
		}
		/* begin ffiPushPointer:in: */
		if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
			((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)ptrAddress));
			(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
		}
		else {
			if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
				return FFIErrorCallFrameTooBig;
			}
			longAtput((calloutState->currentArg), ptrAddress);
			(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
		}
		return 0;
	}
	return FFIErrorBadArg;
}

	/* ThreadedX64Win64FFIPlugin>>#ffiPushStructure:ofSize:typeSpec:ofLength:in: */
static sqInt
ffiPushStructureofSizetypeSpecofLengthin(void *pointer, sqInt structSize, sqInt *argSpec, sqInt argSpecSize, CalloutState *calloutState)
{
    usqLong arg;

	arg = 0;
	if (structSize <= 0) {
		return FFIErrorStructSize;
	}
	if ((structSize <= WordSize)
	 && ((structSize & (structSize - 1)) == 0)) {
		memcpy((&arg), pointer, structSize);
		/* begin ffiPushUnsignedLongLong:in: */
		if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
			((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = arg;
			(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
		}
		else {
			if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
				return FFIErrorCallFrameTooBig;
			}
			longAtput((calloutState->currentArg), arg);
			(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
		}
		return 0;
	}
	flag("quick hack");
	/* begin ffiPushPointer:in: */
	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer));
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), pointer);
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	return 0;
}

	/* ThreadedX64FFIPlugin>>#ffiPushUnsignedByte:in: */
static sqInt
ffiPushUnsignedBytein(sqInt value, CalloutState *calloutState)
{
	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((unsigned char) value));
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), ((unsigned char) value));
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	return 0;
}

	/* ThreadedX64FFIPlugin>>#ffiPushUnsignedChar:in: */
static sqInt
ffiPushUnsignedCharin(sqInt value, CalloutState *calloutState)
{
	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((unsigned char) value));
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), ((unsigned char) value));
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	return 0;
}

	/* ThreadedX64FFIPlugin>>#ffiPushUnsignedInt:in: */
static sqInt
ffiPushUnsignedIntin(sqInt value, CalloutState *calloutState)
{
	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = value;
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), value);
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	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)] = value;
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), value);
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	return 0;
}

	/* ThreadedX64FFIPlugin>>#ffiPushUnsignedLongLong:in: */
static sqInt
ffiPushUnsignedLongLongin(usqLong value, CalloutState *calloutState)
{
	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = value;
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), value);
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	return 0;
}

	/* ThreadedX64FFIPlugin>>#ffiPushUnsignedShort:in: */
static sqInt
ffiPushUnsignedShortin(sqInt value, CalloutState *calloutState)
{
	if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
		((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((unsigned short) value));
		(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
	}
	else {
		if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
			return FFIErrorCallFrameTooBig;
		}
		longAtput((calloutState->currentArg), ((unsigned short) value));
		(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
	}
	return 0;
}


/*	This is a fallback in case somebody tries to pass a 'void' value.
	We could simply ignore the argument but I think it's better to let
	the caller know what he did */

	/* ThreadedFFIPlugin>>#ffiPushVoid:in: */
static sqInt
ffiPushVoidin(sqInt ignored, CalloutState *calloutState)
{
	return FFIErrorAttemptToPassVoid;
}


/*	Create a Smalltalk string from a zero terminated C string */

	/* ThreadedFFIPlugin>>#ffiReturnCStringFrom: */
static sqInt
ffiReturnCStringFrom(sqInt cPointer)
{
    char *cString;
    sqInt i;
    sqInt strLen;
    sqInt strOop;
    char *strPtr;

	if (!(cPointer)) {
		return nilObject();
	}
	cString = ((char *) cPointer);
	strLen = 0;
	while (!((cString[strLen]) == 0)) {
		strLen += 1;
	}
	strOop = instantiateClassindexableSize(classString(), strLen);
	strPtr = firstIndexableField(strOop);
	for (i = 0; i < strLen; i += 1) {
		strPtr[i] = (cString[i]);
	}
	return strOop;
}


/*	Generic callout support. Create a pointer return value from an external
	function call
 */

	/* ThreadedFFIPlugin>>#ffiReturnPointer:ofType:in: */
static sqInt
ffiReturnPointerofTypein(usqLong retVal, sqInt retType, CalloutState *calloutState)
{
    sqInt atomicType;
    sqInt classOop;
    sqInt cPointer;
    char *cString;
    sqInt i;
    sqInt oop;
    sqInt *ptr;
    sqInt retClass;
    sqInt retOop;
    sqInt strLen;
    sqInt strOop;
    char *strPtr;
    sqInt typeSpec;

	retClass = fetchPointerofObject(1, retType);
	if (retClass == (nilObject())) {

		/* Create ExternalData upon return */
		/* begin atomicTypeOf: */
		typeSpec = (calloutState->ffiRetHeader);
		atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
		if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {

			/* String return */
			/* begin ffiReturnCStringFrom: */
			cPointer = ((usqInt) retVal);
			if (!(cPointer)) {
				retOop = nilObject();
				goto l1;
			}
			cString = ((char *) cPointer);
			strLen = 0;
			while (!((cString[strLen]) == 0)) {
				strLen += 1;
			}
			strOop = instantiateClassindexableSize(classString(), strLen);
			strPtr = firstIndexableField(strOop);
			for (i = 0; i < strLen; i += 1) {
				strPtr[i] = (cString[i]);
			}
			retOop = strOop;
	l1:	/* end ffiReturnCStringFrom: */;
			return retOop;
		}
		
#if SPURVM
		oop = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
		ptr = firstIndexableField(oop);
		ptr[0] = (((sqInt) retVal));
		retOop = instantiateClassindexableSize(classExternalData(), 0);
		storePointerofObjectwithValue(0, retOop, oop);

#else /* SPURVM */
		pushRemappableOop(retType);
		oop = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
		ptr = firstIndexableField(oop);
		ptr[0] = (((sqInt) retVal));
				pushRemappableOop(oop);
		retOop = instantiateClassindexableSize(classExternalData(), 0);
		oop = popRemappableOop();
		storePointerofObjectwithValue(0, retOop, oop);
		retType = popRemappableOop()
#endif /* SPURVM */
;
		storePointerofObjectwithValue(1, retOop, retType);
		return retOop;
	}
	classOop = (((calloutState->ffiRetHeader)) & FFIFlagStructure
		? classByteArray()
		: classExternalAddress());
	
#if SPURVM
	oop = instantiateClassindexableSize(classOop, BytesPerWord);

#else /* SPURVM */
	pushRemappableOop(retClass);
	oop = instantiateClassindexableSize(classOop, BytesPerWord);
	retClass = popRemappableOop()
#endif /* SPURVM */
;
	ptr = firstIndexableField(oop);
	ptr[0] = (((sqInt) retVal));
	
#if SPURVM
	retOop = instantiateClassindexableSize(retClass, 0);

#else /* SPURVM */
	pushRemappableOop(oop);
	retOop = instantiateClassindexableSize(retClass, 0);
	oop = popRemappableOop()
#endif /* SPURVM */
;
	storePointerofObjectwithValue(0, retOop, oop);
	return retOop;
}


/*	Create a structure return value from an external function call. The value
	has been stored in
	alloca'ed space pointed to by the calloutState or in the return value. */

	/* ThreadedX64Win64FFIPlugin>>#ffiReturnStruct:ofType:in: */
static sqInt
ffiReturnStructofTypein(usqLong intRet, sqInt ffiRetType, CalloutState *calloutState)
{
    sqInt oop;
    sqInt retClass;
    sqInt retOop;

	retClass = fetchPointerofObject(1, ffiRetType);
	retOop = instantiateClassindexableSize(retClass, 0);
	
#if SPURVM
	oop = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));

#else /* SPURVM */
	pushRemappableOop(retOop);
	oop = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
	retOop = popRemappableOop()
#endif /* SPURVM */
;
	memcpy(firstIndexableField(oop), ((((calloutState->structReturnSize)) <= WordSize)
	 && ((((calloutState->structReturnSize)) & (((calloutState->structReturnSize)) - 1)) == 0)
		? (&intRet)
		: (calloutState->limit)), (calloutState->structReturnSize));
	storePointerofObjectwithValue(0, retOop, oop);
	return retOop;
}


/*	Answer the return type object for the current invocation */

	/* ThreadedFFIPlugin>>#ffiReturnType: */
static sqInt
ffiReturnType(sqInt specOnStack)
{
    sqInt argTypes;
    sqInt specLiteral;

	specLiteral = (specOnStack
		? stackValue(1)
		: literalofMethod(0, primitiveMethod()));
	argTypes = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral);
	return fetchPointerofObject(0, argTypes);
}


/*	Check that the calling convention is valid. This test also filters out
	attempts to do a threaded call in the non-threaded VM/plugin combinatioin. */

	/* ThreadedFFIPlugin>>#ffiSupportsCallingConvention: */
static sqInt
ffiSupportsCallingConvention(sqInt aCallingConvention)
{
	return (aCallingConvention == FFICallTypeCDecl)
	 || (aCallingConvention == FFICallTypeApi);
}


/*	Validate if the given oop (an instance of ExternalData) can be passed as a
	pointer to the given atomic type.
 */

	/* ThreadedFFIPlugin>>#ffiValidateExternalData:AtomicType: */
static sqInt
ffiValidateExternalDataAtomicType(sqInt oop, sqInt atomicType)
{
    sqInt ptrType;
    sqInt spec;
    sqInt specOop;
    sqInt specType;

	ptrType = fetchPointerofObject(1, oop);
	if (!((isPointers(ptrType))
		 && ((slotSizeOf(ptrType)) >= 2))) {
		return FFIErrorWrongType;
	}
	specOop = fetchPointerofObject(0, ptrType);
	if (!((isWords(specOop))
		 && ((slotSizeOf(specOop)) > 0))) {
		return FFIErrorWrongType;
	}
	spec = fetchPointerofObject(0, specOop);
	if (!(spec & FFIFlagAtomic)) {
		return FFIErrorWrongType;
	}
	/* begin atomicTypeOf: */
	specType = ((usqInt) (spec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
	if (specType != atomicType) {

		/* Allow for signed/unsigned conversion but nothing else.
		   See FFIConstants class>>#initializeTypeConstants */
		if (!((atomicType >= FFITypeUnsignedByte)
			 && ((atomicType <= FFITypeSignedChar)
			 && ((((usqInt) atomicType) >> 1) == (((usqInt) specType) >> 1))))) {
			return FFIErrorCoercionFailed;
		}
	}
	return 0;
}


/*	Note: This is hardcoded so it can be run from Squeak.
	The module name is used for validating a module *after*
	it is loaded to check if it does really contain the module
	we're thinking it contains. This is important! */

	/* ThreadedFFIPlugin>>#getModuleName */
EXPORT(const char *)
getModuleName(void)
{
	return "SqueakFFIPrims";
}


/*	There are only 4 args passed by register int or float.
	So we can't distinguish the float index from the integer index.
	So we have to increment both.
	
	Consequently, floatRegisterIndex cannot be used anymore to detect presence
	of float parameter.
	However, we set a signature bitmap indicating which register position is
	used to pass a float.
	
	IMPLEMENTATION NOTES:
	There are code generator hacks that bypass the accessors.
	So we cannot just redefine the method floatRegisterIndex as
	^integerRegisterIndex. Instead we must maintain the two indices
 */

	/* ThreadedFFICalloutStateForX64Win64>>#incrementFloatRegisterIndex */
static sqInt
incrementFloatRegisterIndex(CalloutState * self_in_incrementFloatRegisterIndex)
{
	(self_in_incrementFloatRegisterIndex->floatRegisterSignature) = ((self_in_incrementFloatRegisterIndex->floatRegisterSignature)) + (1U << ((self_in_incrementFloatRegisterIndex->floatRegisterIndex)));
	return ((self_in_incrementFloatRegisterIndex->integerRegisterIndex) = ((self_in_incrementFloatRegisterIndex->floatRegisterIndex) = ((self_in_incrementFloatRegisterIndex->floatRegisterIndex)) + 1));
}


/*	There are only 4 args passed by register int or float.
	So we can't distinguish the float index from the integer index.
	So we have to increment both.
	
	IMPLEMENTATION NOTES:
	There are code generator hacks that bypass the accessors.
	So we cannot just redefine the method floatRegisterIndex as
	^integerRegisterIndex. Instead we must maintain the two indices */

	/* ThreadedFFICalloutStateForX64Win64>>#incrementIntegerRegisterIndex */
static sqInt
incrementIntegerRegisterIndex(CalloutState * self_in_incrementIntegerRegisterIndex)
{
	return ((self_in_incrementIntegerRegisterIndex->floatRegisterIndex) = ((self_in_incrementIntegerRegisterIndex->integerRegisterIndex) = ((self_in_incrementIntegerRegisterIndex->integerRegisterIndex)) + 1));
}

	/* ThreadedFFIPlugin>>#initialiseModule */
EXPORT(sqInt)
initialiseModule(void)
{

	/* By default, disable logging */
	ffiLastError = 0;

	/* Get the instSize of ExternalFunction to know whether it contains a cache of the stackSize,
	   and what the offset of ExternalLibraryFunction's functionName and moduleName slots are. */
	ffiLogEnabled = 0;
	externalFunctionInstSize = instanceSizeOf(classExternalFunction());
	initSurfacePluginFunctionPointers();
	return 1;
}

	/* ThreadedFFIPlugin>>#isAlien: */
static sqInt
isAlien(sqInt anOop)
{
	return includesBehaviorThatOf(fetchClassOf(anOop), classAlien());
}

	/* ThreadedFFIPlugin>>#isAtomicType: */
static sqInt
isAtomicType(sqInt typeSpec)
{
	return typeSpec & FFIFlagAtomic;
}

	/* ThreadedFFIPlugin>>#isDirectAlien: */
static sqInt
isDirectAlien(sqInt oop)
{
	assert(isAlien(oop));
	return (longAt(oop + BaseHeaderSize)) > 0;
}

	/* ThreadedFFIPlugin>>#msg: */
static sqInt
msg(char *s)
{
	fprintf(stderr, "\n%s: %s", getModuleName(), s);
	return 0;
}


/*	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. */

	/* ThreadedFFIPlugin>>#nonRegisterStructReturnIsViaImplicitFirstArgument */
static sqInt
nonRegisterStructReturnIsViaImplicitFirstArgument(void)
{
	return 1;
}


/*	IMPORTANT: IF YOU CHANGE THE NAME OF THIS METHOD YOU MUST CHANGE
	Interpreter>>primitiveCalloutToFFI
	TO REFLECT THE CHANGE. */
/*	Perform a function call to a foreign function.
	Only invoked from method containing explicit external call spec. */

	/* ThreadedFFIPlugin>>#primitiveCallout */
EXPORT(void)
primitiveCallout(void)
{
    sqInt address;
    sqInt address1;
    sqInt address11;
    sqInt address2;
    sqInt addressPtr;
    sqInt addressPtr1;
    char *allocation;
    char *allocation1;
    sqInt argClass;
    sqInt argClass1;
    sqInt argSpec;
    sqInt argSpec1;
    sqInt argType;
    sqInt argType1;
    sqInt argTypeArray;
    sqInt argTypeArray1;
    sqInt argTypes;
    sqInt argTypes1;
    sqInt argTypes2;
    sqInt argTypes3;
    sqInt atomicType;
    sqInt atomicType1;
    sqInt atomicType11;
    sqInt atomicType2;
    sqInt byteSize;
    sqInt byteSize1;
    CalloutState *calloutState;
    CalloutState *calloutState1;
    sqInt classOop;
    sqInt classOop1;
    sqInt cPointer;
    sqInt cPointer1;
    char *cString;
    char *cString1;
    sqInt err;
    sqInt err1;
    sqInt externalFunction;
    sqInt ffiRetType;
    sqInt ffiRetType1;
    sqInt flags;
    sqInt flags1;
    double floatRet;
    double floatRet1;
    sqInt functionName;
    sqInt functionName1;
    sqInt i;
    sqInt i1;
    sqInt i11;
    sqInt i2;
    usqLong intRet;
    usqLong intRet1;
    extern void loadFloatRegs(double, double, double, double);
    usqLong mask;
    usqLong mask1;
    sqInt meth;
    sqInt myThreadIndex;
    sqInt myThreadIndex1;
    sqInt nArgs;
    sqInt nArgs1;
    sqInt oop;
    sqInt oop1;
    sqInt oop11;
    sqInt oop2;
    sqInt oop21;
    sqInt oop3;
    void *pointer;
    void *pointer1;
    sqInt primNumArgs;
    sqInt primNumArgs1;
    sqIntptr_t *ptr;
    sqInt *ptr1;
    sqInt *ptr11;
    sqIntptr_t *ptr2;
    sqInt requiredStackSize;
    sqInt requiredStackSize1;
    sqInt result;
    sqInt result1;
    sqInt result2;
    sqInt retClass;
    sqInt retClass1;
    sqInt retClass11;
    sqInt retClass2;
    sqInt retOop;
    sqInt retOop1;
    sqInt retOop11;
    sqInt retOop2;
    sqInt retryCount;
    sqInt retType;
    sqInt retType1;
    sqInt shift;
    sqInt shift1;
    sqInt specLiteral;
    sqInt specLiteral1;
    sqInt specLiteral2;
    sqInt specLiteral3;
    sqInt stackSize;
    sqInt stackSize1;
    sqInt strLen;
    sqInt strLen1;
    sqInt strOop;
    sqInt strOop1;
    char *strPtr;
    char *strPtr1;
    CalloutState theCalloutState;
    CalloutState theCalloutState1;
    sqInt typeSpec;
    sqInt typeSpec1;
    sqInt typeSpec11;
    sqInt typeSpec2;
    usqLong value;
    usqLong value1;

	meth = primitiveMethod();
	if (!((literalCountOf(meth)) > 0)) {
		primitiveFailFor(PrimErrBadMethod);
		return;
	}
	externalFunction = literalofMethod(0, meth);
	
#  if COGMTVM
	nArgs = methodArgumentCount();
	retryCount = 0;
	while (1) {
		/* begin ffiCall:ArgArrayOrNil:NumArgs: */
		primNumArgs = methodArgumentCount();
		if (!(isKindOfClass(externalFunction, classExternalFunction()))) {
			result = ffiFail(FFIErrorNotFunction);
			goto l10;
		}
		flags = fetchIntegerofObject(ExternalFunctionFlagsIndex, externalFunction);
		if (failed()) {
			result = ffiFail(FFIErrorBadArgs);
			goto l10;
		}
		/* begin ffiLoadCalloutAddress: */

		/* Make sure it's an external handle */
		addressPtr = fetchPointerofObject(0, externalFunction);
		if (!((isBytes(addressPtr))
			 && ((byteSizeOf(addressPtr)) == (sizeof(sqInt))))) {
			address1 = ffiFail(FFIErrorBadAddress);
			goto l1;
		}
		address1 = fetchPointerofObject(0, addressPtr);
	l1:	/* end ffiContentsOfHandle:errCode: */;
		if (failed()) {
			address = 0;
			goto l2;
		}
		if (address1 == 0) {

			/* Go look it up in the module */
			if (externalFunctionInstSize > ExternalFunctionStackSizeIndex) {
				storePointerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, integerObjectOf(-1));
			}
			if ((slotSizeOf(externalFunction)) < 5) {
				address = ffiFail(FFIErrorNoModule);
				goto l2;
			}
			address1 = ffiLoadCalloutAddressFrom(externalFunction);
			if (failed()) {
				address = 0;
				goto l2;
			}
			ptr = firstIndexableField(addressPtr);
			ptr[0] = address1;
		}
		address = address1;
	l2:	/* end ffiLoadCalloutAddress: */;
		if (failed()) {
			result = 0;
			goto l10;
		}

		/* must be array of arg types */
		argTypeArray = fetchPointerofObject(ExternalFunctionArgTypesIndex, externalFunction);
		if (!((isArray(argTypeArray))
			 && ((slotSizeOf(argTypeArray)) == (nArgs + 1)))) {
			result = ffiFail(FFIErrorBadArgs);
			goto l10;
		}
		
#    if COGMTVM
		if (!(((flags & FFICallTypesMask) == FFICallTypeCDecl)
			 || ((flags & FFICallTypesMask) == FFICallTypeApi))) {
			result = ffiFail(FFIErrorCallType);
			goto l10;
		}
#    else /* COGMTVM */

		/* not masking causes threaded calls to fail, which is as they should if the plugin is not threaded. */
		if (!((flags == FFICallTypeCDecl)
			 || (flags == FFICallTypeApi))) {
			result = ffiFail(FFIErrorCallType);
			goto l10;
		}
#    endif /* COGMTVM */
		requiredStackSize = (externalFunctionInstSize > ExternalFunctionStackSizeIndex
			? fetchIntegerofObject(ExternalFunctionStackSizeIndex, externalFunction)
			: -1);
		if (failed()) {
			result = primitiveFailFor((null == null
				? PrimErrBadMethod
				: PrimErrBadReceiver));
			goto l10;
		}
		stackSize = (requiredStackSize < 0
			? DefaultMaxStackSize
			: requiredStackSize);
		calloutState = (&theCalloutState);
		memset(calloutState, 0, sizeof(CalloutState));
		(calloutState->callFlags = flags);
		argType = fetchPointerofObject(0, argTypeArray);
		argSpec = fetchPointerofObject(0, argType);
		argClass = fetchPointerofObject(1, argType);
		if (((err = ffiCheckReturnWithin(argSpec, argClass, calloutState))) != 0) {
			result = ffiFail(err);
			goto l10;
		}
		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);
		if ((((calloutState->structReturnSize)) > 0)
		 && (1
		 && (!((((calloutState->structReturnSize)) <= WordSize)
		 && ((((calloutState->structReturnSize)) & (((calloutState->structReturnSize)) - 1)) == 0))))) {
			/* begin ffiPushPointer:in: */
			pointer = (calloutState->limit);
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer));
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					err = FFIErrorCallFrameTooBig;
					goto l4;
				}
				longAtput((calloutState->currentArg), pointer);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			err = 0;
	l4:	/* end ffiPushPointer:in: */;
			if (err != 0) {
				/* begin cleanupCalloutState: */
				while (((calloutState->stringArgIndex)) > 0) {
					free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
				}
				
#        if COGMTVM
				if (err == (-PrimErrObjectMayMove)) {
					result = PrimErrObjectMayMove;
					goto l10;
				}
#        endif /* COGMTVM */
				result = ffiFail(err);
				goto l10;
			}
		}
		for (i = 1; i <= nArgs; i += 1) {
			argType = fetchPointerofObject(i, argTypeArray);
			argSpec = fetchPointerofObject(0, argType);
			argClass = fetchPointerofObject(1, argType);
			oop = (null == null
				? stackValue(nArgs - i)
				: fetchPointerofObject(i - 1, null));
			err = ffiArgumentSpecClassin(oop, argSpec, argClass, calloutState);
			if (err != 0) {
				/* begin cleanupCalloutState: */
				while (((calloutState->stringArgIndex)) > 0) {
					free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
				}
				
#        if COGMTVM
				if (err == (-PrimErrObjectMayMove)) {
					result = PrimErrObjectMayMove;
					goto l10;
				}
#        endif /* COGMTVM */
				result = ffiFail(err);
				goto l10;
			}
		}
		assert(!(failed()));
		/* begin ffiLogCallout: */
		if (ffiLogEnabled) {
			functionName = fetchPointerofObject(externalFunctionInstSize, externalFunction);
			if (!(isBytes(functionName))) {
				goto l3;
			}
			ffiLogCallOfLength(firstIndexableField(functionName), byteSizeOf(functionName));
		}
	l3:	/* end ffiLogCallout: */;
		if ((requiredStackSize < 0)
		 && (externalFunctionInstSize > ExternalFunctionStackSizeIndex)) {
			stackSize = ((calloutState->currentArg)) - ((calloutState->argVector));
			storeIntegerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, stackSize);
		}
		/* begin ffiCalloutTo:SpecOnStack:in: */
		myThreadIndex = disownVM(
#    if COGMTVM
			(((calloutState->callFlags)) & FFICallFlagThreaded
						? DisownVMForFFICall + DisownVMForThreading
						: DisownVMForFFICall)
#    else /* COGMTVM */
			DisownVMForFFICall
#    endif /* COGMTVM */
			);
		if (((calloutState->floatRegisterSignature)) > 0) {
			loadFloatRegs(((calloutState->floatRegisters))[0], ((calloutState->floatRegisters))[1], ((calloutState->floatRegisters))[2], ((calloutState->floatRegisters))[3]);
		}
		if ((allocaLiesSoSetSpBeforeCall())
		 || (mustAlignStack())) {
			setsp((calloutState->argVector));
		}
		/* begin atomicTypeOf: */
		typeSpec = (calloutState->ffiRetHeader);
		atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
		if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSingleFloat) >> 1)) {
			if (atomicType == FFITypeSingleFloat) {
				floatRet = dispatchFunctionPointerwithwithwithwith(((float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3]);
			}
			else {

				/* atomicType = FFITypeDoubleFloat */
				floatRet = dispatchFunctionPointerwithwithwithwith(((double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3]);
			}
			if (isCalleePopsConvention((calloutState->callFlags))) {
				setsp((calloutState->argVector));
			}
			ownVM(myThreadIndex);
			result1 = floatObjectOf(floatRet);
			goto l9;
		}

		/* undo any callee argument pops because it may confuse stack management with the alloca. */
		intRet = dispatchFunctionPointerwithwithwithwith(((usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3]);
		if (isCalleePopsConvention((calloutState->callFlags))) {
			setsp((calloutState->argVector));
		}
		ownVM(myThreadIndex);
		if (((calloutState->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) {

			/* Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
			   'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct. */
			if (((calloutState->ffiRetHeader)) & FFIFlagPointer) {
				/* begin ffiReturnPointer:ofType:in: */
				specLiteral = (null != null
					? stackValue(1)
					: literalofMethod(0, primitiveMethod()));
				argTypes = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral);
				retType = fetchPointerofObject(0, argTypes);
				retClass = fetchPointerofObject(1, retType);
				if (retClass == (nilObject())) {

					/* Create ExternalData upon return */
					/* begin atomicTypeOf: */
					typeSpec1 = (calloutState->ffiRetHeader);
					atomicType1 = ((usqInt) (typeSpec1 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
					if ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {

						/* String return */
						/* begin ffiReturnCStringFrom: */
						cPointer = ((usqInt) intRet);
						if (!(cPointer)) {
							retOop = nilObject();
							goto l5;
						}
						cString = ((char *) cPointer);
						strLen = 0;
						while (!((cString[strLen]) == 0)) {
							strLen += 1;
						}
						strOop = instantiateClassindexableSize(classString(), strLen);
						strPtr = firstIndexableField(strOop);
						for (i1 = 0; i1 < strLen; i1 += 1) {
							strPtr[i1] = (cString[i1]);
						}
						retOop = strOop;
	l5:	/* end ffiReturnCStringFrom: */;
						result1 = retOop;
						goto l9;
					}
					
#if SPURVM
					oop2 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
					ptr1 = firstIndexableField(oop2);
					ptr1[0] = (((sqInt) intRet));
					retOop = instantiateClassindexableSize(classExternalData(), 0);
					storePointerofObjectwithValue(0, retOop, oop2);

#else /* SPURVM */
					pushRemappableOop(retType);
					oop2 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
					ptr1 = firstIndexableField(oop2);
					ptr1[0] = (((sqInt) intRet));
										pushRemappableOop(oop2);
					retOop = instantiateClassindexableSize(classExternalData(), 0);
					oop2 = popRemappableOop();
					storePointerofObjectwithValue(0, retOop, oop2);
					retType = popRemappableOop()
#endif /* SPURVM */
;
					storePointerofObjectwithValue(1, retOop, retType);
					result1 = retOop;
					goto l9;
				}
				classOop = (((calloutState->ffiRetHeader)) & FFIFlagStructure
					? classByteArray()
					: classExternalAddress());
				
#if SPURVM
				oop2 = instantiateClassindexableSize(classOop, BytesPerWord);

#else /* SPURVM */
				pushRemappableOop(retClass);
				oop2 = instantiateClassindexableSize(classOop, BytesPerWord);
				retClass = popRemappableOop()
#endif /* SPURVM */
;
				ptr1 = firstIndexableField(oop2);
				ptr1[0] = (((sqInt) intRet));
				
#if SPURVM
				retOop = instantiateClassindexableSize(retClass, 0);

#else /* SPURVM */
				pushRemappableOop(oop2);
				retOop = instantiateClassindexableSize(retClass, 0);
				oop2 = popRemappableOop()
#endif /* SPURVM */
;
				storePointerofObjectwithValue(0, retOop, oop2);
				result1 = retOop;
				goto l9;
			}
			/* begin ffiReturnStruct:ofType:in: */
			specLiteral2 = (null != null
				? stackValue(1)
				: literalofMethod(0, primitiveMethod()));
			argTypes2 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral2);
			ffiRetType = fetchPointerofObject(0, argTypes2);
			retClass1 = fetchPointerofObject(1, ffiRetType);
			retOop1 = instantiateClassindexableSize(retClass1, 0);
			
#if SPURVM
			oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));

#else /* SPURVM */
			pushRemappableOop(retOop1);
			oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
			retOop1 = popRemappableOop()
#endif /* SPURVM */
;
			memcpy(firstIndexableField(oop1), ((((calloutState->structReturnSize)) <= WordSize)
			 && ((((calloutState->structReturnSize)) & (((calloutState->structReturnSize)) - 1)) == 0)
				? (&intRet)
				: (calloutState->limit)), (calloutState->structReturnSize));
			storePointerofObjectwithValue(0, retOop1, oop1);
			result1 = retOop1;
			goto l9;
		}
		/* begin ffiCreateIntegralResultOop:ofAtomicType:in: */
		assert(atomicType < FFITypeSingleFloat);
		if (atomicType == FFITypeBool) {

			/* Make sure bool honors the byte size requested */
			byteSize = ((calloutState->ffiRetHeader)) & FFIStructSizeMask;
			value = (byteSize == (sizeof(intRet))
				? intRet
				: intRet & (((((unsigned long long)1)) << (byteSize * 8)) - 1));
			result1 = (value == 0
				? falseObject()
				: trueObject());
			goto l9;
		}
		if (atomicType <= FFITypeSignedInt) {

			/* these are all generall integer returns */
			if (atomicType <= ((BytesPerWord == 8
				? FFITypeSignedInt
				: FFITypeSignedShort))) {

				/* byte/short. first extract partial word, then sign extend */

				/* # of significant bits */
				shift = ((BytesPerWord == 8)
				 && (atomicType >= FFITypeUnsignedInt)
					? 32
					: (((usqInt) atomicType) >> 1) * 8);
				value = intRet & (((((unsigned long long)1)) << shift) - 1);
				if (atomicType & 1) {

					/* make the guy signed */
					mask = (((unsigned long long)1)) << (shift - 1);
					value = (value & (mask - 1)) - (value & mask);
				}
				result1 = integerObjectOf(value);
				goto l9;
			}
			result1 = (atomicType & 1
				? (BytesPerWord == 8
						? signed64BitIntegerFor(intRet)
						: signed32BitIntegerFor(intRet))
				: (BytesPerWord == 8
						? positive64BitIntegerFor(intRet)
						: positive32BitIntegerFor(intRet)));
			goto l9;
		}
		result1 = ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
			? (atomicType & 1
					? signed64BitIntegerFor(intRet)
					: positive64BitIntegerFor(intRet))
			: characterObjectOf(intRet & 0xFF));
	l9:	/* end ffiCalloutTo:SpecOnStack:in: */;
		/* begin cleanupCalloutState: */
		while (((calloutState->stringArgIndex)) > 0) {
			free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
		}
		popthenPush(primNumArgs + 1, result1);
		result = result1;
	l10:	/* end ffiCall:ArgArrayOrNil:NumArgs: */;
		if (!((result == PrimErrObjectMayMove)
		 && (((retryCount += 1)) <= (nArgs + 1)))) break;
		tenuringIncrementalGC();
	}
#  else /* COGMTVM */
	/* begin ffiCall:ArgArrayOrNil:NumArgs: */
	nArgs1 = methodArgumentCount();
	primNumArgs1 = methodArgumentCount();
	if (!(isKindOfClass(externalFunction, classExternalFunction()))) {
		ffiFail(FFIErrorNotFunction);
		goto l20;
	}
	flags1 = fetchIntegerofObject(ExternalFunctionFlagsIndex, externalFunction);
	if (failed()) {
		ffiFail(FFIErrorBadArgs);
		goto l20;
	}
	/* begin ffiLoadCalloutAddress: */

	/* Make sure it's an external handle */
	addressPtr1 = fetchPointerofObject(0, externalFunction);
	if (!((isBytes(addressPtr1))
		 && ((byteSizeOf(addressPtr1)) == (sizeof(sqInt))))) {
		address11 = ffiFail(FFIErrorBadAddress);
		goto l13;
	}
	address11 = fetchPointerofObject(0, addressPtr1);
	l13:	/* end ffiContentsOfHandle:errCode: */;
	if (failed()) {
		address2 = 0;
		goto l19;
	}
	if (address11 == 0) {

		/* Go look it up in the module */
		if (externalFunctionInstSize > ExternalFunctionStackSizeIndex) {
			storePointerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, integerObjectOf(-1));
		}
		if ((slotSizeOf(externalFunction)) < 5) {
			address2 = ffiFail(FFIErrorNoModule);
			goto l19;
		}
		address11 = ffiLoadCalloutAddressFrom(externalFunction);
		if (failed()) {
			address2 = 0;
			goto l19;
		}
		ptr2 = firstIndexableField(addressPtr1);
		ptr2[0] = address11;
	}
	address2 = address11;
	l19:	/* end ffiLoadCalloutAddress: */;
	if (failed()) {
		goto l20;
	}

	/* must be array of arg types */
	argTypeArray1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, externalFunction);
	if (!((isArray(argTypeArray1))
		 && ((slotSizeOf(argTypeArray1)) == (nArgs1 + 1)))) {
		ffiFail(FFIErrorBadArgs);
		goto l20;
	}
	
#  if COGMTVM
	if (!(((flags1 & FFICallTypesMask) == FFICallTypeCDecl)
		 || ((flags1 & FFICallTypesMask) == FFICallTypeApi))) {
		ffiFail(FFIErrorCallType);
		goto l20;
	}
#  else /* COGMTVM */

	/* not masking causes threaded calls to fail, which is as they should if the plugin is not threaded. */
	if (!((flags1 == FFICallTypeCDecl)
		 || (flags1 == FFICallTypeApi))) {
		ffiFail(FFIErrorCallType);
		goto l20;
	}
#  endif /* COGMTVM */
	requiredStackSize1 = (externalFunctionInstSize > ExternalFunctionStackSizeIndex
		? fetchIntegerofObject(ExternalFunctionStackSizeIndex, externalFunction)
		: -1);
	if (failed()) {
		primitiveFailFor((null == null
			? PrimErrBadMethod
			: PrimErrBadReceiver));
		goto l20;
	}
	stackSize1 = (requiredStackSize1 < 0
		? DefaultMaxStackSize
		: requiredStackSize1);
	calloutState1 = (&theCalloutState1);
	memset(calloutState1, 0, sizeof(CalloutState));
	(calloutState1->callFlags = flags1);
	argType1 = fetchPointerofObject(0, argTypeArray1);
	argSpec1 = fetchPointerofObject(0, argType1);
	argClass1 = fetchPointerofObject(1, argType1);
	if (((err1 = ffiCheckReturnWithin(argSpec1, argClass1, calloutState1))) != 0) {
		ffiFail(err1);
		goto l20;
	}
	allocation1 = alloca((stackSize1 + ((calloutState1->structReturnSize))) + (cStackAlignment()));
	if (mustAlignStack()) {
		allocation1 = ((char *) ((((((usqIntptr_t)allocation1)) | ((cStackAlignment()) - 1)) - ((cStackAlignment()) - 1))));
	}
	(calloutState1->argVector = allocation1);
	(calloutState1->currentArg = allocation1);
	(calloutState1->limit = allocation1 + stackSize1);
	if ((((calloutState1->structReturnSize)) > 0)
	 && (1
	 && (!((((calloutState1->structReturnSize)) <= WordSize)
	 && ((((calloutState1->structReturnSize)) & (((calloutState1->structReturnSize)) - 1)) == 0))))) {
		/* begin ffiPushPointer:in: */
		pointer1 = (calloutState1->limit);
		if (((calloutState1->integerRegisterIndex)) < NumIntRegArgs) {
			((calloutState1->integerRegisters))[(calloutState1->integerRegisterIndex)] = (((sqInt)pointer1));
			(calloutState1->floatRegisterIndex) = ((calloutState1->integerRegisterIndex) = ((calloutState1->integerRegisterIndex)) + 1);
		}
		else {
			if ((((calloutState1->currentArg)) + WordSize) > ((calloutState1->limit))) {
				err1 = FFIErrorCallFrameTooBig;
				goto l12;
			}
			longAtput((calloutState1->currentArg), pointer1);
			(calloutState1->currentArg = ((calloutState1->currentArg)) + WordSize);
		}
		err1 = 0;
	l12:	/* end ffiPushPointer:in: */;
		if (err1 != 0) {
			/* begin cleanupCalloutState: */
			while (((calloutState1->stringArgIndex)) > 0) {
				free(((calloutState1->stringArgs))[(calloutState1->stringArgIndex = ((calloutState1->stringArgIndex)) - 1)]);
			}
			
#      if COGMTVM
			if (err1 == (-PrimErrObjectMayMove)) {
				goto l20;
			}
#      endif /* COGMTVM */
			ffiFail(err1);
			goto l20;
		}
	}
	for (i2 = 1; i2 <= nArgs1; i2 += 1) {
		argType1 = fetchPointerofObject(i2, argTypeArray1);
		argSpec1 = fetchPointerofObject(0, argType1);
		argClass1 = fetchPointerofObject(1, argType1);
		oop3 = (null == null
			? stackValue(nArgs1 - i2)
			: fetchPointerofObject(i2 - 1, null));
		err1 = ffiArgumentSpecClassin(oop3, argSpec1, argClass1, calloutState1);
		if (err1 != 0) {
			/* begin cleanupCalloutState: */
			while (((calloutState1->stringArgIndex)) > 0) {
				free(((calloutState1->stringArgs))[(calloutState1->stringArgIndex = ((calloutState1->stringArgIndex)) - 1)]);
			}
			
#      if COGMTVM
			if (err1 == (-PrimErrObjectMayMove)) {
				goto l20;
			}
#      endif /* COGMTVM */
			ffiFail(err1);
			goto l20;
		}
	}
	assert(!(failed()));
	/* begin ffiLogCallout: */
	if (ffiLogEnabled) {
		functionName1 = fetchPointerofObject(externalFunctionInstSize, externalFunction);
		if (!(isBytes(functionName1))) {
			goto l16;
		}
		ffiLogCallOfLength(firstIndexableField(functionName1), byteSizeOf(functionName1));
	}
	l16:	/* end ffiLogCallout: */;
	if ((requiredStackSize1 < 0)
	 && (externalFunctionInstSize > ExternalFunctionStackSizeIndex)) {
		stackSize1 = ((calloutState1->currentArg)) - ((calloutState1->argVector));
		storeIntegerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, stackSize1);
	}
	/* begin ffiCalloutTo:SpecOnStack:in: */
	myThreadIndex1 = disownVM(
#  if COGMTVM
		(((calloutState1->callFlags)) & FFICallFlagThreaded
				? DisownVMForFFICall + DisownVMForThreading
				: DisownVMForFFICall)
#  else /* COGMTVM */
		DisownVMForFFICall
#  endif /* COGMTVM */
		);
	if (((calloutState1->floatRegisterSignature)) > 0) {
		loadFloatRegs(((calloutState1->floatRegisters))[0], ((calloutState1->floatRegisters))[1], ((calloutState1->floatRegisters))[2], ((calloutState1->floatRegisters))[3]);
	}
	if ((allocaLiesSoSetSpBeforeCall())
	 || (mustAlignStack())) {
		setsp((calloutState1->argVector));
	}
	/* begin atomicTypeOf: */
	typeSpec2 = (calloutState1->ffiRetHeader);
	atomicType2 = ((usqInt) (typeSpec2 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
	if ((((usqInt) atomicType2) >> 1) == (((usqInt) FFITypeSingleFloat) >> 1)) {
		if (atomicType2 == FFITypeSingleFloat) {
			floatRet1 = dispatchFunctionPointerwithwithwithwith(((float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address2))), ((calloutState1->integerRegisters))[0], ((calloutState1->integerRegisters))[1], ((calloutState1->integerRegisters))[2], ((calloutState1->integerRegisters))[3]);
		}
		else {

			/* atomicType = FFITypeDoubleFloat */
			floatRet1 = dispatchFunctionPointerwithwithwithwith(((double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address2))), ((calloutState1->integerRegisters))[0], ((calloutState1->integerRegisters))[1], ((calloutState1->integerRegisters))[2], ((calloutState1->integerRegisters))[3]);
		}
		if (isCalleePopsConvention((calloutState1->callFlags))) {
			setsp((calloutState1->argVector));
		}
		ownVM(myThreadIndex1);
		result2 = floatObjectOf(floatRet1);
		goto l14;
	}

	/* undo any callee argument pops because it may confuse stack management with the alloca. */
	intRet1 = dispatchFunctionPointerwithwithwithwith(((usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address2))), ((calloutState1->integerRegisters))[0], ((calloutState1->integerRegisters))[1], ((calloutState1->integerRegisters))[2], ((calloutState1->integerRegisters))[3]);
	if (isCalleePopsConvention((calloutState1->callFlags))) {
		setsp((calloutState1->argVector));
	}
	ownVM(myThreadIndex1);
	if (((calloutState1->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) {

		/* Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
		   'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct. */
		if (((calloutState1->ffiRetHeader)) & FFIFlagPointer) {
			/* begin ffiReturnPointer:ofType:in: */
			specLiteral1 = (null != null
				? stackValue(1)
				: literalofMethod(0, primitiveMethod()));
			argTypes1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral1);
			retType1 = fetchPointerofObject(0, argTypes1);
			retClass2 = fetchPointerofObject(1, retType1);
			if (retClass2 == (nilObject())) {

				/* Create ExternalData upon return */
				/* begin atomicTypeOf: */
				typeSpec11 = (calloutState1->ffiRetHeader);
				atomicType11 = ((usqInt) (typeSpec11 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
				if ((((usqInt) atomicType11) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {

					/* String return */
					/* begin ffiReturnCStringFrom: */
					cPointer1 = ((usqInt) intRet1);
					if (!(cPointer1)) {
						retOop2 = nilObject();
						goto l18;
					}
					cString1 = ((char *) cPointer1);
					strLen1 = 0;
					while (!((cString1[strLen1]) == 0)) {
						strLen1 += 1;
					}
					strOop1 = instantiateClassindexableSize(classString(), strLen1);
					strPtr1 = firstIndexableField(strOop1);
					for (i11 = 0; i11 < strLen1; i11 += 1) {
						strPtr1[i11] = (cString1[i11]);
					}
					retOop2 = strOop1;
	l18:	/* end ffiReturnCStringFrom: */;
					result2 = retOop2;
					goto l14;
				}
				
#if SPURVM
				oop21 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
				ptr11 = firstIndexableField(oop21);
				ptr11[0] = (((sqInt) intRet1));
				retOop2 = instantiateClassindexableSize(classExternalData(), 0);
				storePointerofObjectwithValue(0, retOop2, oop21);

#else /* SPURVM */
				pushRemappableOop(retType1);
				oop21 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
				ptr11 = firstIndexableField(oop21);
				ptr11[0] = (((sqInt) intRet1));
								pushRemappableOop(oop21);
				retOop2 = instantiateClassindexableSize(classExternalData(), 0);
				oop21 = popRemappableOop();
				storePointerofObjectwithValue(0, retOop2, oop21);
				retType1 = popRemappableOop()
#endif /* SPURVM */
;
				storePointerofObjectwithValue(1, retOop2, retType1);
				result2 = retOop2;
				goto l14;
			}
			classOop1 = (((calloutState1->ffiRetHeader)) & FFIFlagStructure
				? classByteArray()
				: classExternalAddress());
			
#if SPURVM
			oop21 = instantiateClassindexableSize(classOop1, BytesPerWord);

#else /* SPURVM */
			pushRemappableOop(retClass2);
			oop21 = instantiateClassindexableSize(classOop1, BytesPerWord);
			retClass2 = popRemappableOop()
#endif /* SPURVM */
;
			ptr11 = firstIndexableField(oop21);
			ptr11[0] = (((sqInt) intRet1));
			
#if SPURVM
			retOop2 = instantiateClassindexableSize(retClass2, 0);

#else /* SPURVM */
			pushRemappableOop(oop21);
			retOop2 = instantiateClassindexableSize(retClass2, 0);
			oop21 = popRemappableOop()
#endif /* SPURVM */
;
			storePointerofObjectwithValue(0, retOop2, oop21);
			result2 = retOop2;
			goto l14;
		}
		/* begin ffiReturnStruct:ofType:in: */
		specLiteral3 = (null != null
			? stackValue(1)
			: literalofMethod(0, primitiveMethod()));
		argTypes3 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral3);
		ffiRetType1 = fetchPointerofObject(0, argTypes3);
		retClass11 = fetchPointerofObject(1, ffiRetType1);
		retOop11 = instantiateClassindexableSize(retClass11, 0);
		
#if SPURVM
		oop11 = instantiateClassindexableSize(classByteArray(), (calloutState1->structReturnSize));

#else /* SPURVM */
		pushRemappableOop(retOop11);
		oop11 = instantiateClassindexableSize(classByteArray(), (calloutState1->structReturnSize));
		retOop11 = popRemappableOop()
#endif /* SPURVM */
;
		memcpy(firstIndexableField(oop11), ((((calloutState1->structReturnSize)) <= WordSize)
		 && ((((calloutState1->structReturnSize)) & (((calloutState1->structReturnSize)) - 1)) == 0)
			? (&intRet1)
			: (calloutState1->limit)), (calloutState1->structReturnSize));
		storePointerofObjectwithValue(0, retOop11, oop11);
		result2 = retOop11;
		goto l14;
	}
	/* begin ffiCreateIntegralResultOop:ofAtomicType:in: */
	assert(atomicType2 < FFITypeSingleFloat);
	if (atomicType2 == FFITypeBool) {

		/* Make sure bool honors the byte size requested */
		byteSize1 = ((calloutState1->ffiRetHeader)) & FFIStructSizeMask;
		value1 = (byteSize1 == (sizeof(intRet1))
			? intRet1
			: intRet1 & (((((unsigned long long)1)) << (byteSize1 * 8)) - 1));
		result2 = (value1 == 0
			? falseObject()
			: trueObject());
		goto l14;
	}
	if (atomicType2 <= FFITypeSignedInt) {

		/* these are all generall integer returns */
		if (atomicType2 <= ((BytesPerWord == 8
			? FFITypeSignedInt
			: FFITypeSignedShort))) {

			/* byte/short. first extract partial word, then sign extend */

			/* # of significant bits */
			shift1 = ((BytesPerWord == 8)
			 && (atomicType2 >= FFITypeUnsignedInt)
				? 32
				: (((usqInt) atomicType2) >> 1) * 8);
			value1 = intRet1 & (((((unsigned long long)1)) << shift1) - 1);
			if (atomicType2 & 1) {

				/* make the guy signed */
				mask1 = (((unsigned long long)1)) << (shift1 - 1);
				value1 = (value1 & (mask1 - 1)) - (value1 & mask1);
			}
			result2 = integerObjectOf(value1);
			goto l14;
		}
		result2 = (atomicType2 & 1
			? (BytesPerWord == 8
					? signed64BitIntegerFor(intRet1)
					: signed32BitIntegerFor(intRet1))
			: (BytesPerWord == 8
					? positive64BitIntegerFor(intRet1)
					: positive32BitIntegerFor(intRet1)));
		goto l14;
	}
	result2 = ((((usqInt) atomicType2) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
		? (atomicType2 & 1
				? signed64BitIntegerFor(intRet1)
				: positive64BitIntegerFor(intRet1))
		: characterObjectOf(intRet1 & 0xFF));
	l14:	/* end ffiCalloutTo:SpecOnStack:in: */;
	/* begin cleanupCalloutState: */
	while (((calloutState1->stringArgIndex)) > 0) {
		free(((calloutState1->stringArgs))[(calloutState1->stringArgIndex = ((calloutState1->stringArgIndex)) - 1)]);
	}
	popthenPush(primNumArgs1 + 1, result2);
	l20:	/* end ffiCall:ArgArrayOrNil:NumArgs: */;
#  endif /* COGMTVM */
	return;
}


/*	Perform a function call to a foreign function.
	Only invoked from ExternalFunction>>invokeWithArguments: */

	/* ThreadedFFIPlugin>>#primitiveCalloutWithArgs */
EXPORT(void)
primitiveCalloutWithArgs(void)
{
    sqInt address;
    sqInt address1;
    sqInt address11;
    sqInt address2;
    sqInt addressPtr;
    sqInt addressPtr1;
    char *allocation;
    char *allocation1;
    sqInt argArray;
    sqInt argClass;
    sqInt argClass1;
    sqInt argSpec;
    sqInt argSpec1;
    sqInt argType;
    sqInt argType1;
    sqInt argTypeArray;
    sqInt argTypeArray1;
    sqInt argTypes;
    sqInt argTypes1;
    sqInt argTypes2;
    sqInt argTypes3;
    sqInt atomicType;
    sqInt atomicType1;
    sqInt atomicType11;
    sqInt atomicType2;
    sqInt byteSize;
    sqInt byteSize1;
    CalloutState *calloutState;
    CalloutState *calloutState1;
    sqInt classOop;
    sqInt classOop1;
    sqInt cPointer;
    sqInt cPointer1;
    char *cString;
    char *cString1;
    sqInt err;
    sqInt err1;
    sqInt externalFunction;
    sqInt ffiRetType;
    sqInt ffiRetType1;
    sqInt flags;
    sqInt flags1;
    double floatRet;
    double floatRet1;
    sqInt functionName;
    sqInt functionName1;
    sqInt i;
    sqInt i1;
    sqInt i11;
    sqInt i2;
    usqLong intRet;
    usqLong intRet1;
    extern void loadFloatRegs(double, double, double, double);
    usqLong mask;
    usqLong mask1;
    sqInt myThreadIndex;
    sqInt myThreadIndex1;
    sqInt nArgs;
    sqInt oop;
    sqInt oop1;
    sqInt oop11;
    sqInt oop2;
    sqInt oop21;
    sqInt oop3;
    void *pointer;
    void *pointer1;
    sqInt primNumArgs;
    sqInt primNumArgs1;
    sqIntptr_t *ptr;
    sqInt *ptr1;
    sqInt *ptr11;
    sqIntptr_t *ptr2;
    sqInt requiredStackSize;
    sqInt requiredStackSize1;
    sqInt result;
    sqInt result1;
    sqInt result2;
    sqInt retClass;
    sqInt retClass1;
    sqInt retClass11;
    sqInt retClass2;
    sqInt retOop;
    sqInt retOop1;
    sqInt retOop11;
    sqInt retOop2;
    sqInt retryCount;
    sqInt retType;
    sqInt retType1;
    sqInt shift;
    sqInt shift1;
    sqInt specLiteral;
    sqInt specLiteral1;
    sqInt specLiteral2;
    sqInt specLiteral3;
    sqInt stackSize;
    sqInt stackSize1;
    sqInt strLen;
    sqInt strLen1;
    sqInt strOop;
    sqInt strOop1;
    char *strPtr;
    char *strPtr1;
    CalloutState theCalloutState;
    CalloutState theCalloutState1;
    sqInt typeSpec;
    sqInt typeSpec1;
    sqInt typeSpec11;
    sqInt typeSpec2;
    usqLong value;
    usqLong value1;

	if (!((methodArgumentCount()) == 1)) {
		primitiveFailFor(PrimErrBadNumArgs);
		return;
	}
	
#  if COGMTVM
	retryCount = 0;
	while (1) {
		externalFunction = stackValue(1);
		argArray = stackValue(0);
		if (!(isArray(argArray))) {
			primitiveFailFor(PrimErrBadArgument);
			return;
		}
		nArgs = slotSizeOf(argArray);
		/* begin ffiCall:ArgArrayOrNil:NumArgs: */
		primNumArgs = methodArgumentCount();
		if (!(isKindOfClass(externalFunction, classExternalFunction()))) {
			result = ffiFail(FFIErrorNotFunction);
			goto l10;
		}
		flags = fetchIntegerofObject(ExternalFunctionFlagsIndex, externalFunction);
		if (failed()) {
			result = ffiFail(FFIErrorBadArgs);
			goto l10;
		}
		/* begin ffiLoadCalloutAddress: */

		/* Make sure it's an external handle */
		addressPtr = fetchPointerofObject(0, externalFunction);
		if (!((isBytes(addressPtr))
			 && ((byteSizeOf(addressPtr)) == (sizeof(sqInt))))) {
			address1 = ffiFail(FFIErrorBadAddress);
			goto l1;
		}
		address1 = fetchPointerofObject(0, addressPtr);
	l1:	/* end ffiContentsOfHandle:errCode: */;
		if (failed()) {
			address = 0;
			goto l2;
		}
		if (address1 == 0) {

			/* Go look it up in the module */
			if (externalFunctionInstSize > ExternalFunctionStackSizeIndex) {
				storePointerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, integerObjectOf(-1));
			}
			if ((slotSizeOf(externalFunction)) < 5) {
				address = ffiFail(FFIErrorNoModule);
				goto l2;
			}
			address1 = ffiLoadCalloutAddressFrom(externalFunction);
			if (failed()) {
				address = 0;
				goto l2;
			}
			ptr = firstIndexableField(addressPtr);
			ptr[0] = address1;
		}
		address = address1;
	l2:	/* end ffiLoadCalloutAddress: */;
		if (failed()) {
			result = 0;
			goto l10;
		}

		/* must be array of arg types */
		argTypeArray = fetchPointerofObject(ExternalFunctionArgTypesIndex, externalFunction);
		if (!((isArray(argTypeArray))
			 && ((slotSizeOf(argTypeArray)) == (nArgs + 1)))) {
			result = ffiFail(FFIErrorBadArgs);
			goto l10;
		}
		
#    if COGMTVM
		if (!(((flags & FFICallTypesMask) == FFICallTypeCDecl)
			 || ((flags & FFICallTypesMask) == FFICallTypeApi))) {
			result = ffiFail(FFIErrorCallType);
			goto l10;
		}
#    else /* COGMTVM */

		/* not masking causes threaded calls to fail, which is as they should if the plugin is not threaded. */
		if (!((flags == FFICallTypeCDecl)
			 || (flags == FFICallTypeApi))) {
			result = ffiFail(FFIErrorCallType);
			goto l10;
		}
#    endif /* COGMTVM */
		requiredStackSize = (externalFunctionInstSize > ExternalFunctionStackSizeIndex
			? fetchIntegerofObject(ExternalFunctionStackSizeIndex, externalFunction)
			: -1);
		if (failed()) {
			result = primitiveFailFor((argArray == null
				? PrimErrBadMethod
				: PrimErrBadReceiver));
			goto l10;
		}
		stackSize = (requiredStackSize < 0
			? DefaultMaxStackSize
			: requiredStackSize);
		calloutState = (&theCalloutState);
		memset(calloutState, 0, sizeof(CalloutState));
		(calloutState->callFlags = flags);
		argType = fetchPointerofObject(0, argTypeArray);
		argSpec = fetchPointerofObject(0, argType);
		argClass = fetchPointerofObject(1, argType);
		if (((err = ffiCheckReturnWithin(argSpec, argClass, calloutState))) != 0) {
			result = ffiFail(err);
			goto l10;
		}
		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);
		if ((((calloutState->structReturnSize)) > 0)
		 && (1
		 && (!((((calloutState->structReturnSize)) <= WordSize)
		 && ((((calloutState->structReturnSize)) & (((calloutState->structReturnSize)) - 1)) == 0))))) {
			/* begin ffiPushPointer:in: */
			pointer = (calloutState->limit);
			if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) {
				((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = (((sqInt)pointer));
				(calloutState->floatRegisterIndex) = ((calloutState->integerRegisterIndex) = ((calloutState->integerRegisterIndex)) + 1);
			}
			else {
				if ((((calloutState->currentArg)) + WordSize) > ((calloutState->limit))) {
					err = FFIErrorCallFrameTooBig;
					goto l4;
				}
				longAtput((calloutState->currentArg), pointer);
				(calloutState->currentArg = ((calloutState->currentArg)) + WordSize);
			}
			err = 0;
	l4:	/* end ffiPushPointer:in: */;
			if (err != 0) {
				/* begin cleanupCalloutState: */
				while (((calloutState->stringArgIndex)) > 0) {
					free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
				}
				
#        if COGMTVM
				if (err == (-PrimErrObjectMayMove)) {
					result = PrimErrObjectMayMove;
					goto l10;
				}
#        endif /* COGMTVM */
				result = ffiFail(err);
				goto l10;
			}
		}
		for (i = 1; i <= nArgs; i += 1) {
			argType = fetchPointerofObject(i, argTypeArray);
			argSpec = fetchPointerofObject(0, argType);
			argClass = fetchPointerofObject(1, argType);
			oop = (argArray == null
				? stackValue(nArgs - i)
				: fetchPointerofObject(i - 1, argArray));
			err = ffiArgumentSpecClassin(oop, argSpec, argClass, calloutState);
			if (err != 0) {
				/* begin cleanupCalloutState: */
				while (((calloutState->stringArgIndex)) > 0) {
					free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
				}
				
#        if COGMTVM
				if (err == (-PrimErrObjectMayMove)) {
					result = PrimErrObjectMayMove;
					goto l10;
				}
#        endif /* COGMTVM */
				result = ffiFail(err);
				goto l10;
			}
		}
		assert(!(failed()));
		/* begin ffiLogCallout: */
		if (ffiLogEnabled) {
			functionName = fetchPointerofObject(externalFunctionInstSize, externalFunction);
			if (!(isBytes(functionName))) {
				goto l3;
			}
			ffiLogCallOfLength(firstIndexableField(functionName), byteSizeOf(functionName));
		}
	l3:	/* end ffiLogCallout: */;
		if ((requiredStackSize < 0)
		 && (externalFunctionInstSize > ExternalFunctionStackSizeIndex)) {
			stackSize = ((calloutState->currentArg)) - ((calloutState->argVector));
			storeIntegerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, stackSize);
		}
		/* begin ffiCalloutTo:SpecOnStack:in: */
		myThreadIndex = disownVM(
#    if COGMTVM
			(((calloutState->callFlags)) & FFICallFlagThreaded
						? DisownVMForFFICall + DisownVMForThreading
						: DisownVMForFFICall)
#    else /* COGMTVM */
			DisownVMForFFICall
#    endif /* COGMTVM */
			);
		if (((calloutState->floatRegisterSignature)) > 0) {
			loadFloatRegs(((calloutState->floatRegisters))[0], ((calloutState->floatRegisters))[1], ((calloutState->floatRegisters))[2], ((calloutState->floatRegisters))[3]);
		}
		if ((allocaLiesSoSetSpBeforeCall())
		 || (mustAlignStack())) {
			setsp((calloutState->argVector));
		}
		/* begin atomicTypeOf: */
		typeSpec = (calloutState->ffiRetHeader);
		atomicType = ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
		if ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSingleFloat) >> 1)) {
			if (atomicType == FFITypeSingleFloat) {
				floatRet = dispatchFunctionPointerwithwithwithwith(((float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3]);
			}
			else {

				/* atomicType = FFITypeDoubleFloat */
				floatRet = dispatchFunctionPointerwithwithwithwith(((double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3]);
			}
			if (isCalleePopsConvention((calloutState->callFlags))) {
				setsp((calloutState->argVector));
			}
			ownVM(myThreadIndex);
			result1 = floatObjectOf(floatRet);
			goto l9;
		}

		/* undo any callee argument pops because it may confuse stack management with the alloca. */
		intRet = dispatchFunctionPointerwithwithwithwith(((usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address))), ((calloutState->integerRegisters))[0], ((calloutState->integerRegisters))[1], ((calloutState->integerRegisters))[2], ((calloutState->integerRegisters))[3]);
		if (isCalleePopsConvention((calloutState->callFlags))) {
			setsp((calloutState->argVector));
		}
		ownVM(myThreadIndex);
		if (((calloutState->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) {

			/* Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
			   'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct. */
			if (((calloutState->ffiRetHeader)) & FFIFlagPointer) {
				/* begin ffiReturnPointer:ofType:in: */
				specLiteral = (argArray != null
					? stackValue(1)
					: literalofMethod(0, primitiveMethod()));
				argTypes = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral);
				retType = fetchPointerofObject(0, argTypes);
				retClass = fetchPointerofObject(1, retType);
				if (retClass == (nilObject())) {

					/* Create ExternalData upon return */
					/* begin atomicTypeOf: */
					typeSpec1 = (calloutState->ffiRetHeader);
					atomicType1 = ((usqInt) (typeSpec1 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
					if ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {

						/* String return */
						/* begin ffiReturnCStringFrom: */
						cPointer = ((usqInt) intRet);
						if (!(cPointer)) {
							retOop = nilObject();
							goto l5;
						}
						cString = ((char *) cPointer);
						strLen = 0;
						while (!((cString[strLen]) == 0)) {
							strLen += 1;
						}
						strOop = instantiateClassindexableSize(classString(), strLen);
						strPtr = firstIndexableField(strOop);
						for (i1 = 0; i1 < strLen; i1 += 1) {
							strPtr[i1] = (cString[i1]);
						}
						retOop = strOop;
	l5:	/* end ffiReturnCStringFrom: */;
						result1 = retOop;
						goto l9;
					}
					
#if SPURVM
					oop2 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
					ptr1 = firstIndexableField(oop2);
					ptr1[0] = (((sqInt) intRet));
					retOop = instantiateClassindexableSize(classExternalData(), 0);
					storePointerofObjectwithValue(0, retOop, oop2);

#else /* SPURVM */
					pushRemappableOop(retType);
					oop2 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
					ptr1 = firstIndexableField(oop2);
					ptr1[0] = (((sqInt) intRet));
										pushRemappableOop(oop2);
					retOop = instantiateClassindexableSize(classExternalData(), 0);
					oop2 = popRemappableOop();
					storePointerofObjectwithValue(0, retOop, oop2);
					retType = popRemappableOop()
#endif /* SPURVM */
;
					storePointerofObjectwithValue(1, retOop, retType);
					result1 = retOop;
					goto l9;
				}
				classOop = (((calloutState->ffiRetHeader)) & FFIFlagStructure
					? classByteArray()
					: classExternalAddress());
				
#if SPURVM
				oop2 = instantiateClassindexableSize(classOop, BytesPerWord);

#else /* SPURVM */
				pushRemappableOop(retClass);
				oop2 = instantiateClassindexableSize(classOop, BytesPerWord);
				retClass = popRemappableOop()
#endif /* SPURVM */
;
				ptr1 = firstIndexableField(oop2);
				ptr1[0] = (((sqInt) intRet));
				
#if SPURVM
				retOop = instantiateClassindexableSize(retClass, 0);

#else /* SPURVM */
				pushRemappableOop(oop2);
				retOop = instantiateClassindexableSize(retClass, 0);
				oop2 = popRemappableOop()
#endif /* SPURVM */
;
				storePointerofObjectwithValue(0, retOop, oop2);
				result1 = retOop;
				goto l9;
			}
			/* begin ffiReturnStruct:ofType:in: */
			specLiteral2 = (argArray != null
				? stackValue(1)
				: literalofMethod(0, primitiveMethod()));
			argTypes2 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral2);
			ffiRetType = fetchPointerofObject(0, argTypes2);
			retClass1 = fetchPointerofObject(1, ffiRetType);
			retOop1 = instantiateClassindexableSize(retClass1, 0);
			
#if SPURVM
			oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));

#else /* SPURVM */
			pushRemappableOop(retOop1);
			oop1 = instantiateClassindexableSize(classByteArray(), (calloutState->structReturnSize));
			retOop1 = popRemappableOop()
#endif /* SPURVM */
;
			memcpy(firstIndexableField(oop1), ((((calloutState->structReturnSize)) <= WordSize)
			 && ((((calloutState->structReturnSize)) & (((calloutState->structReturnSize)) - 1)) == 0)
				? (&intRet)
				: (calloutState->limit)), (calloutState->structReturnSize));
			storePointerofObjectwithValue(0, retOop1, oop1);
			result1 = retOop1;
			goto l9;
		}
		/* begin ffiCreateIntegralResultOop:ofAtomicType:in: */
		assert(atomicType < FFITypeSingleFloat);
		if (atomicType == FFITypeBool) {

			/* Make sure bool honors the byte size requested */
			byteSize = ((calloutState->ffiRetHeader)) & FFIStructSizeMask;
			value = (byteSize == (sizeof(intRet))
				? intRet
				: intRet & (((((unsigned long long)1)) << (byteSize * 8)) - 1));
			result1 = (value == 0
				? falseObject()
				: trueObject());
			goto l9;
		}
		if (atomicType <= FFITypeSignedInt) {

			/* these are all generall integer returns */
			if (atomicType <= ((BytesPerWord == 8
				? FFITypeSignedInt
				: FFITypeSignedShort))) {

				/* byte/short. first extract partial word, then sign extend */

				/* # of significant bits */
				shift = ((BytesPerWord == 8)
				 && (atomicType >= FFITypeUnsignedInt)
					? 32
					: (((usqInt) atomicType) >> 1) * 8);
				value = intRet & (((((unsigned long long)1)) << shift) - 1);
				if (atomicType & 1) {

					/* make the guy signed */
					mask = (((unsigned long long)1)) << (shift - 1);
					value = (value & (mask - 1)) - (value & mask);
				}
				result1 = integerObjectOf(value);
				goto l9;
			}
			result1 = (atomicType & 1
				? (BytesPerWord == 8
						? signed64BitIntegerFor(intRet)
						: signed32BitIntegerFor(intRet))
				: (BytesPerWord == 8
						? positive64BitIntegerFor(intRet)
						: positive32BitIntegerFor(intRet)));
			goto l9;
		}
		result1 = ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
			? (atomicType & 1
					? signed64BitIntegerFor(intRet)
					: positive64BitIntegerFor(intRet))
			: characterObjectOf(intRet & 0xFF));
	l9:	/* end ffiCalloutTo:SpecOnStack:in: */;
		/* begin cleanupCalloutState: */
		while (((calloutState->stringArgIndex)) > 0) {
			free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]);
		}
		popthenPush(primNumArgs + 1, result1);
		result = result1;
	l10:	/* end ffiCall:ArgArrayOrNil:NumArgs: */;
		if (!((result == PrimErrObjectMayMove)
		 && (((retryCount += 1)) <= (nArgs + 1)))) break;
		tenuringIncrementalGC();
	}
#  else /* COGMTVM */
	externalFunction = stackValue(1);
	argArray = stackValue(0);
	if (!(isArray(argArray))) {
		primitiveFailFor(PrimErrBadArgument);
		return;
	}
	nArgs = slotSizeOf(argArray);
	/* begin ffiCall:ArgArrayOrNil:NumArgs: */
	primNumArgs1 = methodArgumentCount();
	if (!(isKindOfClass(externalFunction, classExternalFunction()))) {
		ffiFail(FFIErrorNotFunction);
		goto l20;
	}
	flags1 = fetchIntegerofObject(ExternalFunctionFlagsIndex, externalFunction);
	if (failed()) {
		ffiFail(FFIErrorBadArgs);
		goto l20;
	}
	/* begin ffiLoadCalloutAddress: */

	/* Make sure it's an external handle */
	addressPtr1 = fetchPointerofObject(0, externalFunction);
	if (!((isBytes(addressPtr1))
		 && ((byteSizeOf(addressPtr1)) == (sizeof(sqInt))))) {
		address11 = ffiFail(FFIErrorBadAddress);
		goto l13;
	}
	address11 = fetchPointerofObject(0, addressPtr1);
	l13:	/* end ffiContentsOfHandle:errCode: */;
	if (failed()) {
		address2 = 0;
		goto l19;
	}
	if (address11 == 0) {

		/* Go look it up in the module */
		if (externalFunctionInstSize > ExternalFunctionStackSizeIndex) {
			storePointerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, integerObjectOf(-1));
		}
		if ((slotSizeOf(externalFunction)) < 5) {
			address2 = ffiFail(FFIErrorNoModule);
			goto l19;
		}
		address11 = ffiLoadCalloutAddressFrom(externalFunction);
		if (failed()) {
			address2 = 0;
			goto l19;
		}
		ptr2 = firstIndexableField(addressPtr1);
		ptr2[0] = address11;
	}
	address2 = address11;
	l19:	/* end ffiLoadCalloutAddress: */;
	if (failed()) {
		goto l20;
	}

	/* must be array of arg types */
	argTypeArray1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, externalFunction);
	if (!((isArray(argTypeArray1))
		 && ((slotSizeOf(argTypeArray1)) == (nArgs + 1)))) {
		ffiFail(FFIErrorBadArgs);
		goto l20;
	}
	
#  if COGMTVM
	if (!(((flags1 & FFICallTypesMask) == FFICallTypeCDecl)
		 || ((flags1 & FFICallTypesMask) == FFICallTypeApi))) {
		ffiFail(FFIErrorCallType);
		goto l20;
	}
#  else /* COGMTVM */

	/* not masking causes threaded calls to fail, which is as they should if the plugin is not threaded. */
	if (!((flags1 == FFICallTypeCDecl)
		 || (flags1 == FFICallTypeApi))) {
		ffiFail(FFIErrorCallType);
		goto l20;
	}
#  endif /* COGMTVM */
	requiredStackSize1 = (externalFunctionInstSize > ExternalFunctionStackSizeIndex
		? fetchIntegerofObject(ExternalFunctionStackSizeIndex, externalFunction)
		: -1);
	if (failed()) {
		primitiveFailFor((argArray == null
			? PrimErrBadMethod
			: PrimErrBadReceiver));
		goto l20;
	}
	stackSize1 = (requiredStackSize1 < 0
		? DefaultMaxStackSize
		: requiredStackSize1);
	calloutState1 = (&theCalloutState1);
	memset(calloutState1, 0, sizeof(CalloutState));
	(calloutState1->callFlags = flags1);
	argType1 = fetchPointerofObject(0, argTypeArray1);
	argSpec1 = fetchPointerofObject(0, argType1);
	argClass1 = fetchPointerofObject(1, argType1);
	if (((err1 = ffiCheckReturnWithin(argSpec1, argClass1, calloutState1))) != 0) {
		ffiFail(err1);
		goto l20;
	}
	allocation1 = alloca((stackSize1 + ((calloutState1->structReturnSize))) + (cStackAlignment()));
	if (mustAlignStack()) {
		allocation1 = ((char *) ((((((usqIntptr_t)allocation1)) | ((cStackAlignment()) - 1)) - ((cStackAlignment()) - 1))));
	}
	(calloutState1->argVector = allocation1);
	(calloutState1->currentArg = allocation1);
	(calloutState1->limit = allocation1 + stackSize1);
	if ((((calloutState1->structReturnSize)) > 0)
	 && (1
	 && (!((((calloutState1->structReturnSize)) <= WordSize)
	 && ((((calloutState1->structReturnSize)) & (((calloutState1->structReturnSize)) - 1)) == 0))))) {
		/* begin ffiPushPointer:in: */
		pointer1 = (calloutState1->limit);
		if (((calloutState1->integerRegisterIndex)) < NumIntRegArgs) {
			((calloutState1->integerRegisters))[(calloutState1->integerRegisterIndex)] = (((sqInt)pointer1));
			(calloutState1->floatRegisterIndex) = ((calloutState1->integerRegisterIndex) = ((calloutState1->integerRegisterIndex)) + 1);
		}
		else {
			if ((((calloutState1->currentArg)) + WordSize) > ((calloutState1->limit))) {
				err1 = FFIErrorCallFrameTooBig;
				goto l12;
			}
			longAtput((calloutState1->currentArg), pointer1);
			(calloutState1->currentArg = ((calloutState1->currentArg)) + WordSize);
		}
		err1 = 0;
	l12:	/* end ffiPushPointer:in: */;
		if (err1 != 0) {
			/* begin cleanupCalloutState: */
			while (((calloutState1->stringArgIndex)) > 0) {
				free(((calloutState1->stringArgs))[(calloutState1->stringArgIndex = ((calloutState1->stringArgIndex)) - 1)]);
			}
			
#      if COGMTVM
			if (err1 == (-PrimErrObjectMayMove)) {
				goto l20;
			}
#      endif /* COGMTVM */
			ffiFail(err1);
			goto l20;
		}
	}
	for (i2 = 1; i2 <= nArgs; i2 += 1) {
		argType1 = fetchPointerofObject(i2, argTypeArray1);
		argSpec1 = fetchPointerofObject(0, argType1);
		argClass1 = fetchPointerofObject(1, argType1);
		oop3 = (argArray == null
			? stackValue(nArgs - i2)
			: fetchPointerofObject(i2 - 1, argArray));
		err1 = ffiArgumentSpecClassin(oop3, argSpec1, argClass1, calloutState1);
		if (err1 != 0) {
			/* begin cleanupCalloutState: */
			while (((calloutState1->stringArgIndex)) > 0) {
				free(((calloutState1->stringArgs))[(calloutState1->stringArgIndex = ((calloutState1->stringArgIndex)) - 1)]);
			}
			
#      if COGMTVM
			if (err1 == (-PrimErrObjectMayMove)) {
				goto l20;
			}
#      endif /* COGMTVM */
			ffiFail(err1);
			goto l20;
		}
	}
	assert(!(failed()));
	/* begin ffiLogCallout: */
	if (ffiLogEnabled) {
		functionName1 = fetchPointerofObject(externalFunctionInstSize, externalFunction);
		if (!(isBytes(functionName1))) {
			goto l16;
		}
		ffiLogCallOfLength(firstIndexableField(functionName1), byteSizeOf(functionName1));
	}
	l16:	/* end ffiLogCallout: */;
	if ((requiredStackSize1 < 0)
	 && (externalFunctionInstSize > ExternalFunctionStackSizeIndex)) {
		stackSize1 = ((calloutState1->currentArg)) - ((calloutState1->argVector));
		storeIntegerofObjectwithValue(ExternalFunctionStackSizeIndex, externalFunction, stackSize1);
	}
	/* begin ffiCalloutTo:SpecOnStack:in: */
	myThreadIndex1 = disownVM(
#  if COGMTVM
		(((calloutState1->callFlags)) & FFICallFlagThreaded
				? DisownVMForFFICall + DisownVMForThreading
				: DisownVMForFFICall)
#  else /* COGMTVM */
		DisownVMForFFICall
#  endif /* COGMTVM */
		);
	if (((calloutState1->floatRegisterSignature)) > 0) {
		loadFloatRegs(((calloutState1->floatRegisters))[0], ((calloutState1->floatRegisters))[1], ((calloutState1->floatRegisters))[2], ((calloutState1->floatRegisters))[3]);
	}
	if ((allocaLiesSoSetSpBeforeCall())
	 || (mustAlignStack())) {
		setsp((calloutState1->argVector));
	}
	/* begin atomicTypeOf: */
	typeSpec2 = (calloutState1->ffiRetHeader);
	atomicType2 = ((usqInt) (typeSpec2 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
	if ((((usqInt) atomicType2) >> 1) == (((usqInt) FFITypeSingleFloat) >> 1)) {
		if (atomicType2 == FFITypeSingleFloat) {
			floatRet1 = dispatchFunctionPointerwithwithwithwith(((float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address2))), ((calloutState1->integerRegisters))[0], ((calloutState1->integerRegisters))[1], ((calloutState1->integerRegisters))[2], ((calloutState1->integerRegisters))[3]);
		}
		else {

			/* atomicType = FFITypeDoubleFloat */
			floatRet1 = dispatchFunctionPointerwithwithwithwith(((double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address2))), ((calloutState1->integerRegisters))[0], ((calloutState1->integerRegisters))[1], ((calloutState1->integerRegisters))[2], ((calloutState1->integerRegisters))[3]);
		}
		if (isCalleePopsConvention((calloutState1->callFlags))) {
			setsp((calloutState1->argVector));
		}
		ownVM(myThreadIndex1);
		result2 = floatObjectOf(floatRet1);
		goto l14;
	}

	/* undo any callee argument pops because it may confuse stack management with the alloca. */
	intRet1 = dispatchFunctionPointerwithwithwithwith(((usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)) (((void *) address2))), ((calloutState1->integerRegisters))[0], ((calloutState1->integerRegisters))[1], ((calloutState1->integerRegisters))[2], ((calloutState1->integerRegisters))[3]);
	if (isCalleePopsConvention((calloutState1->callFlags))) {
		setsp((calloutState1->argVector));
	}
	ownVM(myThreadIndex1);
	if (((calloutState1->ffiRetHeader)) & (FFIFlagPointer + FFIFlagStructure)) {

		/* Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent
		   'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct. */
		if (((calloutState1->ffiRetHeader)) & FFIFlagPointer) {
			/* begin ffiReturnPointer:ofType:in: */
			specLiteral1 = (argArray != null
				? stackValue(1)
				: literalofMethod(0, primitiveMethod()));
			argTypes1 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral1);
			retType1 = fetchPointerofObject(0, argTypes1);
			retClass2 = fetchPointerofObject(1, retType1);
			if (retClass2 == (nilObject())) {

				/* Create ExternalData upon return */
				/* begin atomicTypeOf: */
				typeSpec11 = (calloutState1->ffiRetHeader);
				atomicType11 = ((usqInt) (typeSpec11 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift;
				if ((((usqInt) atomicType11) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) {

					/* String return */
					/* begin ffiReturnCStringFrom: */
					cPointer1 = ((usqInt) intRet1);
					if (!(cPointer1)) {
						retOop2 = nilObject();
						goto l18;
					}
					cString1 = ((char *) cPointer1);
					strLen1 = 0;
					while (!((cString1[strLen1]) == 0)) {
						strLen1 += 1;
					}
					strOop1 = instantiateClassindexableSize(classString(), strLen1);
					strPtr1 = firstIndexableField(strOop1);
					for (i11 = 0; i11 < strLen1; i11 += 1) {
						strPtr1[i11] = (cString1[i11]);
					}
					retOop2 = strOop1;
	l18:	/* end ffiReturnCStringFrom: */;
					result2 = retOop2;
					goto l14;
				}
				
#if SPURVM
				oop21 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
				ptr11 = firstIndexableField(oop21);
				ptr11[0] = (((sqInt) intRet1));
				retOop2 = instantiateClassindexableSize(classExternalData(), 0);
				storePointerofObjectwithValue(0, retOop2, oop21);

#else /* SPURVM */
				pushRemappableOop(retType1);
				oop21 = instantiateClassindexableSize(classExternalAddress(), BytesPerWord);
				ptr11 = firstIndexableField(oop21);
				ptr11[0] = (((sqInt) intRet1));
								pushRemappableOop(oop21);
				retOop2 = instantiateClassindexableSize(classExternalData(), 0);
				oop21 = popRemappableOop();
				storePointerofObjectwithValue(0, retOop2, oop21);
				retType1 = popRemappableOop()
#endif /* SPURVM */
;
				storePointerofObjectwithValue(1, retOop2, retType1);
				result2 = retOop2;
				goto l14;
			}
			classOop1 = (((calloutState1->ffiRetHeader)) & FFIFlagStructure
				? classByteArray()
				: classExternalAddress());
			
#if SPURVM
			oop21 = instantiateClassindexableSize(classOop1, BytesPerWord);

#else /* SPURVM */
			pushRemappableOop(retClass2);
			oop21 = instantiateClassindexableSize(classOop1, BytesPerWord);
			retClass2 = popRemappableOop()
#endif /* SPURVM */
;
			ptr11 = firstIndexableField(oop21);
			ptr11[0] = (((sqInt) intRet1));
			
#if SPURVM
			retOop2 = instantiateClassindexableSize(retClass2, 0);

#else /* SPURVM */
			pushRemappableOop(oop21);
			retOop2 = instantiateClassindexableSize(retClass2, 0);
			oop21 = popRemappableOop()
#endif /* SPURVM */
;
			storePointerofObjectwithValue(0, retOop2, oop21);
			result2 = retOop2;
			goto l14;
		}
		/* begin ffiReturnStruct:ofType:in: */
		specLiteral3 = (argArray != null
			? stackValue(1)
			: literalofMethod(0, primitiveMethod()));
		argTypes3 = fetchPointerofObject(ExternalFunctionArgTypesIndex, specLiteral3);
		ffiRetType1 = fetchPointerofObject(0, argTypes3);
		retClass11 = fetchPointerofObject(1, ffiRetType1);
		retOop11 = instantiateClassindexableSize(retClass11, 0);
		
#if SPURVM
		oop11 = instantiateClassindexableSize(classByteArray(), (calloutState1->structReturnSize));

#else /* SPURVM */
		pushRemappableOop(retOop11);
		oop11 = instantiateClassindexableSize(classByteArray(), (calloutState1->structReturnSize));
		retOop11 = popRemappableOop()
#endif /* SPURVM */
;
		memcpy(firstIndexableField(oop11), ((((calloutState1->structReturnSize)) <= WordSize)
		 && ((((calloutState1->structReturnSize)) & (((calloutState1->structReturnSize)) - 1)) == 0)
			? (&intRet1)
			: (calloutState1->limit)), (calloutState1->structReturnSize));
		storePointerofObjectwithValue(0, retOop11, oop11);
		result2 = retOop11;
		goto l14;
	}
	/* begin ffiCreateIntegralResultOop:ofAtomicType:in: */
	assert(atomicType2 < FFITypeSingleFloat);
	if (atomicType2 == FFITypeBool) {

		/* Make sure bool honors the byte size requested */
		byteSize1 = ((calloutState1->ffiRetHeader)) & FFIStructSizeMask;
		value1 = (byteSize1 == (sizeof(intRet1))
			? intRet1
			: intRet1 & (((((unsigned long long)1)) << (byteSize1 * 8)) - 1));
		result2 = (value1 == 0
			? falseObject()
			: trueObject());
		goto l14;
	}
	if (atomicType2 <= FFITypeSignedInt) {

		/* these are all generall integer returns */
		if (atomicType2 <= ((BytesPerWord == 8
			? FFITypeSignedInt
			: FFITypeSignedShort))) {

			/* byte/short. first extract partial word, then sign extend */

			/* # of significant bits */
			shift1 = ((BytesPerWord == 8)
			 && (atomicType2 >= FFITypeUnsignedInt)
				? 32
				: (((usqInt) atomicType2) >> 1) * 8);
			value1 = intRet1 & (((((unsigned long long)1)) << shift1) - 1);
			if (atomicType2 & 1) {

				/* make the guy signed */
				mask1 = (((unsigned long long)1)) << (shift1 - 1);
				value1 = (value1 & (mask1 - 1)) - (value1 & mask1);
			}
			result2 = integerObjectOf(value1);
			goto l14;
		}
		result2 = (atomicType2 & 1
			? (BytesPerWord == 8
					? signed64BitIntegerFor(intRet1)
					: signed32BitIntegerFor(intRet1))
			: (BytesPerWord == 8
					? positive64BitIntegerFor(intRet1)
					: positive32BitIntegerFor(intRet1)));
		goto l14;
	}
	result2 = ((((usqInt) atomicType2) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)
		? (atomicType2 & 1
				? signed64BitIntegerFor(intRet1)
				: positive64BitIntegerFor(intRet1))
		: characterObjectOf(intRet1 & 0xFF));
	l14:	/* end ffiCalloutTo:SpecOnStack:in: */;
	/* begin cleanupCalloutState: */
	while (((calloutState1->stringArgIndex)) > 0) {
		free(((calloutState1->stringArgs))[(calloutState1->stringArgIndex = ((calloutState1->stringArgIndex)) - 1)]);
	}
	popthenPush(primNumArgs1 + 1, result2);
	l20:	/* end ffiCall:ArgArrayOrNil:NumArgs: */;
#  endif /* COGMTVM */
	return;
}


/*	arguments: name(type, stack offset)
	width(Integer, 4)
	height(Integer, 3)
	rowPitch(Integer, 2)
	depth(Integer, 1)
	isMSB(Boolean, 0) */

	/* ThreadedFFIPlugin>>#primitiveCreateManualSurface */
EXPORT(sqInt)
primitiveCreateManualSurface(void)
{
    sqInt depth;
    sqInt height;
    sqInt isMSB;
    sqInt result;
    sqInt rowPitch;
    sqInt width;

	if (!((methodArgumentCount()) == 5)) {
		return primitiveFailFor(PrimErrBadNumArgs);
	}
	width = stackIntegerValue(4);
	height = stackIntegerValue(3);
	rowPitch = stackIntegerValue(2);
	depth = stackIntegerValue(1);
	isMSB = stackObjectValue(0);
	isMSB = booleanValueOf(isMSB);
	if (failed()) {
		return null;
	}
	result = createManualSurface(width, height, rowPitch, depth, isMSB);
	if (result < 0) {
		return primitiveFail();
	}
	result = signed32BitIntegerFor(result);
	return popthenPush(6, result);
}

	/* ThreadedFFIPlugin>>#primitiveDestroyManualSurface */
EXPORT(sqInt)
primitiveDestroyManualSurface(void)
{
    sqInt surfaceID;

	if (!((methodArgumentCount()) == 1)) {
		return primitiveFail();
	}
	surfaceID = stackIntegerValue(0);
	if (!(failed())) {
		if ((destroyManualSurface(surfaceID)) == 0) {
			primitiveFail();
		}
		else {
			pop(1);
		}
	}
	return 0;
}


/*	Primitive. Allocate an object on the external heap. */

	/* ThreadedFFIPlugin>>#primitiveFFIAllocate */
EXPORT(sqInt)
primitiveFFIAllocate(void)
{
    sqInt addr;
    sqInt byteSize;
    sqInt oop;
    sqIntptr_t *ptr;

	byteSize = stackIntegerValue(0);
	if (failed()) {
		return null;
	}
	addr = ffiAlloc(byteSize);
	if (addr == 0) {
		return primitiveFail();
	}
	oop = instantiateClassindexableSize(classExternalAddress(), sizeof(sqIntptr_t));
	ptr = firstIndexableField(oop);
	ptr[0] = addr;
	return popthenPush(2, oop);
}


/*	Return a (signed or unsigned) n byte integer from the given byte offset. */

	/* ThreadedFFIPlugin>>#primitiveFFIDoubleAt */
EXPORT(sqInt)
primitiveFFIDoubleAt(void)
{
    void * addr;
    sqInt byteOffset;
    double floatValue;
    sqInt rcvr;

	byteOffset = stackIntegerValue(0);
	rcvr = stackObjectValue(1);
	if (failed()) {
		return 0;
	}
	addr = ffiAddressOfstartingAtsize(rcvr, byteOffset, 8);
	if (addr == 0) {
		return primitiveFail();
	}
	memcpy((&floatValue), addr, sizeof(floatValue));
	pop(2);
	return pushFloat(floatValue);
}


/*	Return a (signed or unsigned) n byte integer from the given byte offset. */

	/* ThreadedFFIPlugin>>#primitiveFFIDoubleAtPut */
EXPORT(sqInt)
primitiveFFIDoubleAtPut(void)
{
    void * addr;
    sqInt byteOffset;
    sqInt floatOop;
    double floatValue;
    sqInt rcvr;

	floatOop = stackValue(0);
	if (isIntegerObject(floatOop)) {
		floatValue = ((double) (integerValueOf(floatOop)));
	}
	else {
		floatValue = ((double) (floatValueOf(floatOop)));
	}
	byteOffset = stackIntegerValue(1);
	rcvr = stackObjectValue(2);
	if (failed()) {
		return 0;
	}
	addr = ffiAddressOfstartingAtsize(rcvr, byteOffset, 8);
	if (addr == 0) {
		return primitiveFail();
	}
	memcpy(addr, (&floatValue), sizeof(floatValue));
	return popthenPush(3, floatOop);
}


/*	Return a (signed or unsigned) n byte integer from the given byte offset. */

	/* ThreadedFFIPlugin>>#primitiveFFIFloatAt */
EXPORT(sqInt)
primitiveFFIFloatAt(void)
{
    void * addr;
    sqInt byteOffset;
    float floatValue;
    sqInt rcvr;

	byteOffset = stackIntegerValue(0);
	rcvr = stackObjectValue(1);
	if (failed()) {
		return 0;
	}
	addr = ffiAddressOfstartingAtsize(rcvr, byteOffset, 4);
	if (addr == 0) {
		return primitiveFail();
	}
	memcpy((&floatValue), addr, sizeof(floatValue));
	pop(2);
	return pushFloat(floatValue);
}


/*	Return a (signed or unsigned) n byte integer from the given byte offset. */

	/* ThreadedFFIPlugin>>#primitiveFFIFloatAtPut */
EXPORT(sqInt)
primitiveFFIFloatAtPut(void)
{
    void * addr;
    sqInt byteOffset;
    sqInt floatOop;
    float floatValue;
    sqInt rcvr;

	floatOop = stackValue(0);
	if (isIntegerObject(floatOop)) {
		floatValue = ((float) (integerValueOf(floatOop)));
	}
	else {
		floatValue = ((float) (floatValueOf(floatOop)));
	}
	byteOffset = stackIntegerValue(1);
	rcvr = stackObjectValue(2);
	if (failed()) {
		return 0;
	}
	addr = ffiAddressOfstartingAtsize(rcvr, byteOffset, 4);
	if (addr == 0) {
		return primitiveFail();
	}
	memcpy(addr, (&floatValue), sizeof(floatValue));
	return popthenPush(3, floatOop);
}


/*	Primitive. Free the object pointed to on the external heap. */

	/* ThreadedFFIPlugin>>#primitiveFFIFree */
EXPORT(sqInt)
primitiveFFIFree(void)
{
    sqIntptr_t addr;
    sqInt oop;
    sqIntptr_t *ptr;

	oop = stackObjectValue(0);
	if (!(((fetchClassOf(oop)) == (classExternalAddress()))
		 && ((byteSizeOf(oop)) == (sizeof(sqIntptr_t))))) {
		return primitiveFail();
	}
	ptr = firstIndexableField(oop);

	/* Don't you dare to free Squeak's memory! */
	addr = ptr[0];
	if ((addr == 0)
	 || ((((((usqIntptr_t)addr)) & ((sizeof(sqIntptr_t)) - 1)) != 0)
	 || (isInMemory(addr)))) {
		return primitiveFail();
	}
	ffiFree(addr);
	return ptr[0] = 0;
}


/*	Primitive. Return the error code from a failed call to the foreign
	function interface.
	This is for backwards-compatibility. Thread-safe access to the error code
	is via the
	primitive error code. */

	/* ThreadedFFIPlugin>>#primitiveFFIGetLastError */
EXPORT(sqInt)
primitiveFFIGetLastError(void)
{
	methodReturnInteger(ffiLastError);
	return 0;
}


/*	Answer a (signed or unsigned) n byte integer from the given byte offset
	in the receiver, using the platform's endianness. */

	/* ThreadedFFIPlugin>>#primitiveFFIIntegerAt */
EXPORT(sqInt)
primitiveFFIIntegerAt(void)
{
    void * addr;
    sqInt byteOffset;
    sqInt byteSize;
    sqInt isSigned;
    usqLong mask;
    sqInt rcvr;
    usqLong value;
    sqInt valueOop;

	isSigned = booleanValueOf(stackValue(0));
	byteSize = stackIntegerValue(1);
	byteOffset = stackIntegerValue(2);
	rcvr = stackObjectValue(3);
	if (failed()) {
		return 0;
	}
	if (!((byteOffset > 0)
		 && ((((byteSize >= 1) && (byteSize <= 8)))
		 && ((byteSize & (byteSize - 1)) == 0)))) {
		return primitiveFail();
	}
	addr = ffiAddressOfstartingAtsize(rcvr, byteOffset, byteSize);
	if (addr == 0) {
		return primitiveFail();
	}
	if (byteSize <= 2) {
		if (byteSize == 1) {
			value = ((unsigned char) (byteAt(addr)));
		}
		else {
			value = ((unsigned short) (unalignedShortAt(addr)));
		}
	}
	else {
		if (byteSize == 4) {
			value = ((unsigned int) (unalignedLong32At(addr)));
		}
		else {
			value = unalignedLong64At(addr);
		}
	}
	if (byteSize < BytesPerWord) {
		if (isSigned) {

			/* sign extend value */
			mask = (((unsigned long long)1)) << ((byteSize * 8) - 1);
			value = (value & (mask - 1)) - (value & mask);
		}
		valueOop = integerObjectOf(value);
	}
	else {

		/* general 64 bit integer; note these never fail */
		if (isSigned) {
			if (byteSize < 8) {

				/* sign extend value */
				mask = (((unsigned long long)1)) << ((byteSize * 8) - 1);
				value = (value & (mask - 1)) - (value & mask);
			}
			valueOop = signed64BitIntegerFor(value);
		}
		else {
			valueOop = positive64BitIntegerFor(value);
		}
	}
	return popthenPush(4, valueOop);
}


/*	Store a (signed or unsigned) n byte integer at the given byte offset
	in the receiver, using the platform's endianness. */

	/* ThreadedFFIPlugin>>#primitiveFFIIntegerAtPut */
EXPORT(sqInt)
primitiveFFIIntegerAtPut(void)
{
    void * addr;
    sqInt byteOffset;
    sqInt byteSize;
    sqInt isSigned;
    sqLong max;
    sqInt rcvr;
    sqLong value;
    sqInt valueOop;

	isSigned = booleanValueOf(stackValue(0));
	byteSize = stackIntegerValue(1);
	valueOop = stackValue(2);
	byteOffset = stackIntegerValue(3);
	rcvr = stackObjectValue(4);
	if (failed()) {
		return 0;
	}
	if (!((byteOffset > 0)
		 && ((((byteSize >= 1) && (byteSize <= 8)))
		 && ((byteSize & (byteSize - 1)) == 0)))) {
		return primitiveFail();
	}
	addr = ffiAddressOfstartingAtsize(rcvr, byteOffset, byteSize);
	if (addr == 0) {
		return primitiveFail();
	}
	if (isSigned) {
		value = signed64BitValueOf(valueOop);
	}
	else {
		value = positive64BitValueOf(valueOop);
	}
	if (failed()) {
		return 0;
	}
	if (byteSize < 8) {
		if (isSigned) {
			max = (((unsigned long long)1)) << ((8 * byteSize) - 1);
			if (!((value >= (0 - max))
				 && (value < max))) {
				return primitiveFail();
			}
		}
		else {
			if (!((((unsigned long long)value)) < ((((unsigned long long)1)) << (8 * byteSize)))) {
				return primitiveFail();
			}
		}
	}
	if (byteSize <= 2) {
		if (byteSize == 1) {
			byteAtput(addr, value);
		}
		else {
			unalignedShortAtput(addr, value);
		}
	}
	else {
		if (byteSize == 4) {
			unalignedLong32Atput(addr, value);
		}
		else {
			unalignedLong64Atput(addr, value);
		}
	}
	return popthenPush(5, valueOop);
}


/*	Primitive. Force loading the receiver (an instance of ExternalLibrary). */

	/* ThreadedFFIPlugin>>#primitiveForceLoad */
EXPORT(sqInt)
primitiveForceLoad(void)
{
    sqInt ffiModuleName;
    sqInt moduleHandle;
    sqInt moduleHandlePtr;
    sqInt *ptr;
    sqInt rcvr;

	if (!((methodArgumentCount()) == 0)) {
		return primitiveFail();
	}
	rcvr = stackValue(0);
	if (!(isKindOfClass(rcvr, classExternalLibrary()))) {
		return ffiFail(FFIErrorBadExternalLibrary);
	}
	moduleHandlePtr = fetchPointerofObject(0, rcvr);
	/* begin ffiContentsOfHandle:errCode: */
	if (!((isBytes(moduleHandlePtr))
		 && ((byteSizeOf(moduleHandlePtr)) == (sizeof(sqInt))))) {
		moduleHandle = ffiFail(FFIErrorBadExternalLibrary);
		goto l1;
	}
	moduleHandle = fetchPointerofObject(0, moduleHandlePtr);
	l1:	/* end ffiContentsOfHandle:errCode: */;
	if (failed()) {
		return 0;
	}
	ffiModuleName = fetchPointerofObject(1, rcvr);
	if (!(isBytes(ffiModuleName))) {
		return ffiFail(FFIErrorBadExternalLibrary);
	}
	moduleHandle = ((sqInt)(ioLoadModuleOfLength(((sqInt)(firstIndexableField(ffiModuleName))), byteSizeOf(ffiModuleName))));
	if (failed()) {
		return ffiFail(FFIErrorModuleNotFound);
	}
	ptr = firstIndexableField(moduleHandlePtr);
	ptr[0] = moduleHandle;
	return 0;
}


/*	Attempt to find the address of a symbol in a loaded library.
	loadSymbol: aSymbol fromModule: moduleName
	<primitive: 'primitiveLoadSymbolFromModule' error: errorCode module:
	'SqueakFFIPrims'>  */

	/* ThreadedFFIPlugin>>#primitiveLoadSymbolFromModule */
EXPORT(sqInt)
primitiveLoadSymbolFromModule(void)
{
    void *address;
    sqInt module;
    sqInt moduleHandle;
    sqInt oop;
    void **ptr;
    sqInt symbol;

	if (!((methodArgumentCount()) == 2)) {
		return primitiveFailFor(PrimErrBadNumArgs);
	}
	module = stackValue(0);
	symbol = stackValue(1);
	moduleHandle = (module != (nilObject())
		? ffiLoadCalloutModule(module)
		: 0);
	if (failed()) {
		return primitiveFailFor(PrimErrNotFound);
	}
	address = ioLoadSymbolOfLengthFromModule(((sqInt) (firstIndexableField(symbol))), byteSizeOf(symbol), moduleHandle);
	if ((failed())
	 || (address == 0)) {
		return primitiveFailFor(PrimErrNotFound);
	}
	oop = instantiateClassindexableSize(classExternalAddress(), sizeof(void *));
	ptr = firstIndexableField(oop);
	ptr[0] = address;
	return methodReturnValue(oop);
}


/*	Enable logging of FFI calls by providing it with a log file name. */

	/* ThreadedFFIPlugin>>#primitiveLogCallsTo */
EXPORT(sqInt)
primitiveLogCallsTo(void)
{
    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 if a struct result of a given size is returned in memory or not. */

	/* ThreadedX64Win64FFIPlugin>>#returnStructInRegisters: */
static sqInt
returnStructInRegisters(sqInt returnStructSize)
{
	return (returnStructSize <= WordSize)
	 && ((returnStructSize & (returnStructSize - 1)) == 0);
}


/*	Note: This is coded so that it can be run in Squeak. */
/*	Initialization of the plugin in the simulator.
	The real routine is in the superclass. */

	/* ThreadedFFIPlugin>>#setInterpreter: */
EXPORT(sqInt)
setInterpreter(struct VirtualMachine *anInterpreter)
{
    sqInt ok;

	interpreterProxy = anInterpreter;
	ok = ((interpreterProxy->majorVersion()) == (VM_PROXY_MAJOR))
	 && ((interpreterProxy->minorVersion()) >= (VM_PROXY_MINOR));
	if (ok) {
		
#if !defined(SQUEAK_BUILTIN_PLUGIN)
		booleanValueOf = interpreterProxy->booleanValueOf;
		byteSizeOf = interpreterProxy->byteSizeOf;
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
		characterObjectOf = interpreterProxy->characterObjectOf;
#else
#if !defined(characterObjectOf)
		characterObjectOf = 0;
#endif
#endif
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
		characterValueOf = interpreterProxy->characterValueOf;
#else
#if !defined(characterValueOf)
		characterValueOf = 0;
#endif
#endif
		classAlien = interpreterProxy->classAlien;
		classByteArray = interpreterProxy->classByteArray;
		classExternalAddress = interpreterProxy->classExternalAddress;
		classExternalData = interpreterProxy->classExternalData;
		classExternalFunction = interpreterProxy->classExternalFunction;
		classExternalLibrary = interpreterProxy->classExternalLibrary;
		classExternalStructure = interpreterProxy->classExternalStructure;
		classLargePositiveInteger = interpreterProxy->classLargePositiveInteger;
		classString = interpreterProxy->classString;
		disownVM = interpreterProxy->disownVM;
		failed = interpreterProxy->failed;
		falseObject = interpreterProxy->falseObject;
		fetchClassOf = interpreterProxy->fetchClassOf;
		fetchIntegerofObject = interpreterProxy->fetchIntegerofObject;
		fetchLong32ofObject = interpreterProxy->fetchLong32ofObject;
		fetchPointerofObject = interpreterProxy->fetchPointerofObject;
		firstIndexableField = interpreterProxy->firstIndexableField;
		floatObjectOf = interpreterProxy->floatObjectOf;
		floatValueOf = interpreterProxy->floatValueOf;
		includesBehaviorThatOf = interpreterProxy->includesBehaviorThatOf;
		instanceSizeOf = interpreterProxy->instanceSizeOf;
		instantiateClassindexableSize = interpreterProxy->instantiateClassindexableSize;
		integerObjectOf = interpreterProxy->integerObjectOf;
		integerValueOf = interpreterProxy->integerValueOf;
		ioLoadModuleOfLength = interpreterProxy->ioLoadModuleOfLength;
		ioLoadSymbolOfLengthFromModule = interpreterProxy->ioLoadSymbolOfLengthFromModule;
		isKindOfClass = interpreterProxy->isKindOfClass;
		isArray = interpreterProxy->isArray;
		isBytes = interpreterProxy->isBytes;
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
		isCharacterObject = interpreterProxy->isCharacterObject;
#else
#if !defined(isCharacterObject)
		isCharacterObject = 0;
#endif
#endif
		isFloatObject = interpreterProxy->isFloatObject;
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 13)
		isImmediate = interpreterProxy->isImmediate;
#else
#if !defined(isImmediate)
		isImmediate = 0;
#endif
#endif
		isInMemory = interpreterProxy->isInMemory;
		isIntegerObject = interpreterProxy->isIntegerObject;
		isPointers = interpreterProxy->isPointers;
		isWords = interpreterProxy->isWords;
		isYoung = interpreterProxy->isYoung;
		literalofMethod = interpreterProxy->literalofMethod;
		literalCountOf = interpreterProxy->literalCountOf;
		methodArgumentCount = interpreterProxy->methodArgumentCount;
		methodReturnInteger = interpreterProxy->methodReturnInteger;
		methodReturnValue = interpreterProxy->methodReturnValue;
		nilObject = interpreterProxy->nilObject;
		ownVM = interpreterProxy->ownVM;
		pop = interpreterProxy->pop;
		popthenPush = interpreterProxy->popthenPush;
		popRemappableOop = interpreterProxy->popRemappableOop;
		positive32BitIntegerFor = interpreterProxy->positive32BitIntegerFor;
		positive32BitValueOf = interpreterProxy->positive32BitValueOf;
		positive64BitIntegerFor = interpreterProxy->positive64BitIntegerFor;
		positive64BitValueOf = interpreterProxy->positive64BitValueOf;
		positiveMachineIntegerValueOf = interpreterProxy->positiveMachineIntegerValueOf;
		primitiveErrorTable = interpreterProxy->primitiveErrorTable;
		primitiveFail = interpreterProxy->primitiveFail;
		primitiveFailFor = interpreterProxy->primitiveFailFor;
		primitiveMethod = interpreterProxy->primitiveMethod;
		pushFloat = interpreterProxy->pushFloat;
		pushRemappableOop = interpreterProxy->pushRemappableOop;
		signed32BitIntegerFor = interpreterProxy->signed32BitIntegerFor;
		signed64BitIntegerFor = interpreterProxy->signed64BitIntegerFor;
		signed64BitValueOf = interpreterProxy->signed64BitValueOf;
		signedMachineIntegerValueOf = interpreterProxy->signedMachineIntegerValueOf;
		slotSizeOf = interpreterProxy->slotSizeOf;
		stackIntegerValue = interpreterProxy->stackIntegerValue;
		stackObjectValue = interpreterProxy->stackObjectValue;
		stackValue = interpreterProxy->stackValue;
		storeIntegerofObjectwithValue = interpreterProxy->storeIntegerofObjectwithValue;
		storePointerofObjectwithValue = interpreterProxy->storePointerofObjectwithValue;
		tenuringIncrementalGC = interpreterProxy->tenuringIncrementalGC;
		trueObject = interpreterProxy->trueObject;
#endif /* !defined(SQUEAK_BUILTIN_PLUGIN) */
	}
	return ok;
}


/*	Answer the first field of oop which is assumed to be an Alien of at least
	8 bytes
 */

	/* ThreadedFFIPlugin>>#sizeField: */
static sqInt
sizeField(sqInt oop)
{
	return longAt(oop + BaseHeaderSize);
}


/*	<Alien oop> ^<Integer> */
/*	Answer the start of oop's data. For direct aliens this is the address of
	the second field. For indirect and pointer aliens it is what the second
	field points to. */

	/* ThreadedFFIPlugin>>#startOfData: */
static sqInt
startOfData(sqInt oop)
{
	return ((longAt(oop + BaseHeaderSize)) > 0
		? (oop + BaseHeaderSize) + BytesPerOop
		: longAt((oop + BaseHeaderSize) + BytesPerOop));
}


#ifdef SQUEAK_BUILTIN_PLUGIN

static char _m[] = "SqueakFFIPrims";
void* X64Win64FFIPlugin_exports[][3] = {
	{(void*)_m, "ffiLogCallsTo", (void*)ffiLogCallsTo},
	{(void*)_m, "getModuleName", (void*)getModuleName},
	{(void*)_m, "initialiseModule", (void*)initialiseModule},
	{(void*)_m, "primitiveCallout\000\002", (void*)primitiveCallout},
	{(void*)_m, "primitiveCalloutWithArgs\000\004", (void*)primitiveCalloutWithArgs},
	{(void*)_m, "primitiveCreateManualSurface\000\000", (void*)primitiveCreateManualSurface},
	{(void*)_m, "primitiveDestroyManualSurface\000\000", (void*)primitiveDestroyManualSurface},
	{(void*)_m, "primitiveFFIAllocate\000\001", (void*)primitiveFFIAllocate},
	{(void*)_m, "primitiveFFIDoubleAt\000\001", (void*)primitiveFFIDoubleAt},
	{(void*)_m, "primitiveFFIDoubleAtPut\000\001", (void*)primitiveFFIDoubleAtPut},
	{(void*)_m, "primitiveFFIFloatAt\000\001", (void*)primitiveFFIFloatAt},
	{(void*)_m, "primitiveFFIFloatAtPut\000\001", (void*)primitiveFFIFloatAtPut},
	{(void*)_m, "primitiveFFIFree\000\001", (void*)primitiveFFIFree},
	{(void*)_m, "primitiveFFIGetLastError\000\377", (void*)primitiveFFIGetLastError},
	{(void*)_m, "primitiveFFIIntegerAt\000\001", (void*)primitiveFFIIntegerAt},
	{(void*)_m, "primitiveFFIIntegerAtPut\000\001", (void*)primitiveFFIIntegerAtPut},
	{(void*)_m, "primitiveForceLoad\000\002", (void*)primitiveForceLoad},
	{(void*)_m, "primitiveLoadSymbolFromModule\000\002", (void*)primitiveLoadSymbolFromModule},
	{(void*)_m, "primitiveLogCallsTo\000\000", (void*)primitiveLogCallsTo},
	{(void*)_m, "primitiveSetManualSurfacePointer\000\000", (void*)primitiveSetManualSurfacePointer},
	{(void*)_m, "setInterpreter", (void*)setInterpreter},
	{NULL, NULL, NULL}
};

#else /* ifdef SQ_BUILTIN_PLUGIN */

signed char primitiveCalloutAccessorDepth = 2;
signed char primitiveCalloutWithArgsAccessorDepth = 4;
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;

#endif /* ifdef SQ_BUILTIN_PLUGIN */
