Revision: 2898 Author: eliot Date: 2014-04-21 12:44:55 -0700 (Mon, 21 Apr 2014) Log Message: ----------- CogVM source as per VMMaker.oscog-eem.685.
Add the new ARMFFIPlugin derived from ThreadedARMFFIPlugin (thanks Doug!!). Generate the ThreadedIA32Plugin as IA32FFIPlugin and include either based on the relevant defines from a now skeletal SqueakFFIPrims/SqueakFFIPrims.c.
Add history and product directories for a better organised build (arriving RSN).
Modified Paths: -------------- branches/Cog/src/plugins/SqueakFFIPrims/SqueakFFIPrims.c
Added Paths: ----------- branches/Cog/history/ branches/Cog/products/ branches/Cog/src/plugins/SqueakFFIPrims/ARM32FFIPlugin.c branches/Cog/src/plugins/SqueakFFIPrims/IA32FFIPlugin.c
Added: branches/Cog/src/plugins/SqueakFFIPrims/ARM32FFIPlugin.c =================================================================== --- branches/Cog/src/plugins/SqueakFFIPrims/ARM32FFIPlugin.c (rev 0) +++ branches/Cog/src/plugins/SqueakFFIPrims/ARM32FFIPlugin.c 2014-04-21 19:44:55 UTC (rev 2898) @@ -0,0 +1,5819 @@ +/* Automatically generated by + VMPluginCodeGenerator VMMaker.oscog-eem.685 uuid: 07bc1e83-6566-4de0-af79-d6c7874ffcdd + from + ThreadedARMFFIPlugin VMMaker.oscog-eem.685 uuid: 07bc1e83-6566-4de0-af79-d6c7874ffcdd + */ +static char __buildInfo[] = "ThreadedARMFFIPlugin VMMaker.oscog-eem.685 uuid: 07bc1e83-6566-4de0-af79-d6c7874ffcdd " __DATE__ ; + + + +#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. */ +/* The virtual machine proxy definition */ +#include "sqVirtualMachine.h" +/* Configuration options */ +#include "sqConfig.h" +/* Platform specific definitions */ +#include "sqPlatformSpecific.h" + +#define true 1 +#define false 0 +#define null 0 /* using 'null' because nil is predefined in Think C */ +#ifdef SQUEAK_BUILTIN_PLUGIN +#undef EXPORT +// was #undef EXPORT(returnType) but screws NorCroft cc +#define EXPORT(returnType) static returnType +#endif + +#include "sqMemoryAccess.h" + + +/* ThreadedFFIPlugin class>>preambleCCode */ + +#include "sqAssert.h" /* for assert */ + +#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)) +# define getsp() ({ void *esp; asm volatile ("movl %%esp,%0" : "=r"(esp) : ); esp;}) +# elif defined(__GNUC__) && (defined(__arm__)) +# define setsp(sp) asm volatile ("ldr %%sp, %0" : : "m"(sp)) +# define getsp() ({ void *sp; asm volatile ("mov %0, %%sp" : "=r"(sp) : ); sp;}) +#endif +#if !defined(getsp) +# define getsp() 0 +#endif +#if !defined(setsp) +# define setsp(ignored) 0 +#endif + +#if !defined(STACK_ALIGN_BYTES) +# if __APPLE__ && __MACH__ && __i386__ +# define STACK_ALIGN_BYTES 16 +# elif __linux__ && __i386__ +# define STACK_ALIGN_BYTES 16 +# elif defined(__amd64__) || defined(__x86_64__) || defined(__amd64) || defined(__x86_64) +# define STACK_ALIGN_BYTES 16 +# elif defined(powerpc) || defined(__powerpc__) || defined(_POWER) || defined(__POWERPC__) || defined(__PPC__) +# define STACK_ALIGN_BYTES 16 +# elif defined(__sparc64__) || defined(__sparcv9__) || defined(__sparc_v9__) /* must preceed 32-bit sparc defs */ +# define STACK_ALIGN_BYTES 16 +# elif defined(sparc) || defined(__sparc__) || defined(__sparclite__) +# define STACK_ALIGN_BYTES 8 +# elif defined(__arm__) +# define STACK_ALIGN_BYTES 8 +# else +# define STACK_ALIGN_BYTES 0 +# endif +#endif /* !defined(STACK_ALIGN_BYTES) */ + +#if !defined(STACK_OFFSET_BYTES) +# define STACK_OFFSET_BYTES 0 +#endif + +#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 +# else +# define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 0 +# endif +#endif /* defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__) */ + +#if defined(__arm__) +# define WIN32_X86_STRUCT_RETURN 0 +# define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 0 +#endif /* defined(__arm__) */ + +#if !defined(ALLOCA_LIES_SO_USE_GETSP) +# if defined(__MINGW32__) && (__GNUC__ >= 3) + /* + * cygwin -mno-cygwin (MinGW) gcc 3.4.x's alloca is a library routine that answers + * %esp + 4, so the outgoing stack is offset by one word if uncorrected. + * Grab the actual stack pointer to correct. + */ +# define ALLOCA_LIES_SO_USE_GETSP 1 +# else +# define ALLOCA_LIES_SO_USE_GETSP 0 +# endif +#endif /* !defined(ALLOCA_LIES_SO_USE_GETSP) */ + +/* The dispatchOn:in:with:with: generates an unwanted call on error. Just squash it. */ +#define error(foo) 0 + +/* but print assert failures. */ +void +warning(char *s) { /* Print an error message but don't exit. */ + printf("\n%s\n", s); +} + +/* end ThreadedFFIPlugin class>>preambleCCode */ + +typedef struct { + char *argVector; + char *currentArg; + char *limit; + sqInt structReturnSize; + sqInt callFlags; + void *ffiArgSpec; + sqInt ffiArgSpecSize; + sqInt ffiArgHeader; + sqInt ffiRetHeader; + sqInt stringArgIndex; + char *stringArgs [15]; + sqInt integerRegisterIndex; + sqInt integerRegisters [4]; + sqInt floatRegisterIndex; + sqInt backfillFloatRegisterIndex; + float floatRegisters [16]; + } CalloutState; + +#define ThreadedFFICalloutStateForARM CalloutState + + + +/*** Constants ***/ +#define DefaultMaxStackSize 16384 +#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 FFITypeVoid 0 +#define MaxNumArgs 15 +#define NumFloatRegArgs 16 +#define NumIntRegArgs 4 +#define PrimErrBadArgument 3 +#define PrimErrBadMethod 12 +#define PrimErrBadNumArgs 5 +#define PrimErrBadReceiver 2 +#define PrimErrNoCMemory 10 +#define PrimErrObjectMayMove 14 + + +/*** Function Prototypes ***/ +static sqInt atomicTypeOf(sqInt typeSpec); +static void cleanupCalloutState(CalloutState *calloutState); +static void dummyFloatFunctionwithwithwithwithwithwithwith(double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8); +static sqInt externalFunctionHasStackSizeSlot(void); +static sqInt 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 ffiPushDoubleFloatin(double value, CalloutState *calloutState); +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 ffiPushSingleFloatin(float value, CalloutState *calloutState); +static sqInt ffiPushStringOfLengthin(char *pointer, sqInt length, CalloutState *calloutState); +static sqInt ffiPushStructureContentsOfin(sqInt oop, CalloutState *calloutState); +static sqInt ffiPushStructureofSizetypeSpecofLengthin(void *pointer, sqInt structSize, sqInt *argSpec, sqInt argSpecSize, CalloutState *calloutState); +static sqInt ffiPushUnsignedBytein(sqInt value, CalloutState *calloutState); +static sqInt ffiPushUnsignedCharin(sqInt value, CalloutState *calloutState); +static sqInt ffiPushUnsignedIntin(sqInt value, CalloutState *calloutState); +static sqInt ffiPushUnsignedLongLongOopin(sqInt oop, CalloutState *calloutState); +static sqInt ffiPushUnsignedLongLongin(usqLong value, CalloutState *calloutState); +static sqInt ffiPushUnsignedShortin(sqInt value, CalloutState *calloutState); +static sqInt ffiPushVoidin(sqInt ignored, CalloutState *calloutState); +static sqInt ffiReturnCStringFrom(sqInt cPointer); +static sqInt ffiReturnPointerofTypein(usqLong retVal, sqInt retType, CalloutState *calloutState); +static sqInt ffiReturnStructofTypein(usqLong longLongRet, sqInt ffiRetType, CalloutState *calloutState); +static sqInt ffiReturnType(sqInt specOnStack); +static sqInt ffiSupportsCallingConvention(sqInt aCallingConvention); +static sqInt ffiValidateExternalDataAtomicType(sqInt oop, sqInt atomicType); +static VirtualMachine * getInterpreter(void); +EXPORT(const char*) getModuleName(void); +static sqInt halt(void); +EXPORT(sqInt) initialiseModule(void); +static sqInt isAlien(sqInt anOop); +static sqInt isAtomicType(sqInt typeSpec); +static sqInt isDirectAlien(sqInt oop); +static sqInt msg(char *s); +static sqInt 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) primitiveLogCallsTo(void); +EXPORT(sqInt) primitiveSetManualSurfacePointer(void); +static sqInt registerArgsSlop(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) +static sqInt (*booleanValueOf)(sqInt obj); +static sqInt (*byteSizeOf)(sqInt oop); +static sqInt (*characterTable)(void); +static sqInt (*characterValueOf)(sqInt aCharacter); +static sqInt (*classAlien)(void); +static sqInt (*classByteArray)(void); +static sqInt (*classCharacter)(void); +static sqInt (*classExternalAddress)(void); +static sqInt (*classExternalData)(void); +static sqInt (*classExternalFunction)(void); +static sqInt (*classExternalLibrary)(void); +static sqInt (*classExternalStructure)(void); +static sqInt (*classFloat)(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 (*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 (*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 (*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)(sqInt integerValue); +static sqInt (*positive32BitValueOf)(sqInt oop); +static sqInt (*positive64BitIntegerFor)(sqLong integerValue); +static sqLong (*positive64BitValueOf)(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 (*pushInteger)(sqInt integerValue); +static sqInt (*pushRemappableOop)(sqInt oop); +static sqInt (*signed32BitIntegerFor)(sqInt integerValue); +static int (*signed32BitValueOf)(sqInt oop); +static sqInt (*signed64BitIntegerFor)(sqLong integerValue); +static sqLong (*signed64BitValueOf)(sqInt oop); +static long (*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 sqInt (*tenuringIncrementalGC)(void); +static sqInt (*trueObject)(void); +#else /* !defined(SQUEAK_BUILTIN_PLUGIN) */ +extern sqInt booleanValueOf(sqInt obj); +extern sqInt byteSizeOf(sqInt oop); +extern sqInt characterTable(void); +#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 classCharacter(void); +extern sqInt classExternalAddress(void); +extern sqInt classExternalData(void); +extern sqInt classExternalFunction(void); +extern sqInt classExternalLibrary(void); +extern sqInt classExternalStructure(void); +extern sqInt classFloat(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 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 isImmediate(sqInt anObject); +#else +# define isImmediate(anObject) 0 +#endif +extern sqInt isInMemory(sqInt address); +extern sqInt isIntegerObject(sqInt objectPointer); +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 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(sqInt integerValue); +extern sqInt positive32BitValueOf(sqInt oop); +extern sqInt positive64BitIntegerFor(sqLong integerValue); +extern sqLong positive64BitValueOf(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 pushInteger(sqInt integerValue); +extern sqInt pushRemappableOop(sqInt oop); +extern sqInt signed32BitIntegerFor(sqInt integerValue); +extern int signed32BitValueOf(sqInt oop); +extern sqInt signed64BitIntegerFor(sqLong integerValue); +extern sqLong signed64BitValueOf(sqInt oop); +extern long 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 sqInt tenuringIncrementalGC(void); +extern sqInt trueObject(void); +extern +#endif +struct VirtualMachine* interpreterProxy; +static const char *moduleName = +#ifdef SQUEAK_BUILTIN_PLUGIN + "ARM32FFIPlugin VMMaker.oscog-eem.685 (i)" +#else + "ARM32FFIPlugin VMMaker.oscog-eem.685 (e)" +#endif +; + + +/*** Macros ***/ +#define allocaLiesSoUseGetsp() ALLOCA_LIES_SO_USE_GETSP +#define cStackAlignment() STACK_ALIGN_BYTES +#define dispatchFunctionPointer(aFunctionPointer) (aFunctionPointer)() +#define dispatchFunctionPointerwithwithwithwith(aFunctionPointer, int1, int2, int3, int4) (aFunctionPointer)(int1, int2, int3, int4) +#define ffiAlloc(bytes) (usqInt)malloc(bytes) +#define ffiFree(pointer) free((void *)(pointer)) +#define isCalleePopsConvention(callType) (PLATFORM_API_USES_CALLEE_POPS_CONVENTION && (callType) == FFICallTypeApi) + + +static sqInt +atomicTypeOf(sqInt typeSpec) +{ + return ((usqInt) (typeSpec & FFIAtomicTypeMask)) >> FFIAtomicTypeShift; +} + + +/* Free any temporary arg strings. */ + +static void +cleanupCalloutState(CalloutState *calloutState) +{ + while (((calloutState->stringArgIndex)) > 0) { + free(((calloutState->stringArgs))[(calloutState->stringArgIndex = ((calloutState->stringArgIndex)) - 1)]); + } +} + +static void +dummyFloatFunctionwithwithwithwithwithwithwith(double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8) +{ +} + +static sqInt +externalFunctionHasStackSizeSlot(void) +{ + return externalFunctionInstSize > ExternalFunctionStackSizeIndex; +} + + +/* return an int 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. + */ + +static sqInt +ffiAddressOfstartingAtsize(sqInt rcvr, sqInt byteOffset, sqInt byteSize) +{ + int addr; + sqInt rcvrClass; + sqInt rcvrSize; + + if (!(isBytes(rcvr))) { + return primitiveFail(); + } + if (!(byteOffset > 0)) { + return primitiveFail(); + } + rcvrClass = fetchClassOf(rcvr); + rcvrSize = byteSizeOf(rcvr); + if (rcvrClass == (classExternalAddress())) { + if (!(rcvrSize == 4)) { + return primitiveFail(); + } + + /* don't you dare to read from object memory! */ + +addr = fetchPointerofObject(0, rcvr); + if ((addr == 0) + || (isInMemory(addr))) { + return primitiveFail(); + } + } + else { +if (!(((byteOffset + byteSize) - 1) <= rcvrSize)) { + return primitiveFail(); + } + addr = ((int) (firstIndexableField(rcvr))); + } + addr = (addr + byteOffset) - 1; + return addr; +} + + +/* Support for generic callout. Prepare an argument by value for a callout. */ + +static sqInt +ffiArgByValuein(sqInt oop, CalloutState *calloutState) +{ + sqInt atomicType; + double floatValue; + sqInt intValue; + sqInt oopClass; + sqInt oopClass1; + 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 (isIntegerObject(oop)) { + intValue = integerValueOf(oop); + goto l1; + } + if (oop == (nilObject())) { + intValue = 0; + goto l1; + } + if (oop == (falseObject())) { + intValue = 0; + goto l1; + } + if (oop == (trueObject())) { + intValue = 1; + goto l1; + } + oopClass = fetchClassOf(oop); + if (oopClass == (classFloat())) { + intValue = ((sqInt)(floatValueOf(oop))); + goto l1; + } + if (oopClass == (classCharacter())) { + intValue = characterValueOf(oop); + goto l1; + } + if (oopClass == (classLargePositiveInteger())) { + intValue = positive32BitValueOf(oop); + goto l1; + } + intValue = signedMachineIntegerValueOf(oop); + l1: /* 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: */ + oopClass1 = fetchClassOf(oop); + if (oopClass1 == (classFloat())) { + floatValue = floatValueOf(oop); + goto l2; + } + floatValue = ((double) (ffiIntegerValueOf(oop)) ); +l2: /* end ffiFloatValueOf: */; + if (failed()) { + return FFIErrorCoercionFailed; + } + if (atomicType == FFITypeSingleFloat) { +/* begin ffiPushSingleFloat:in: */ + if (((calloutState->floatRegisterIndex)) < NumFloatRegArgs) { + if (((calloutState->backfillFloatRegisterIndex)) > 0) { + ((calloutState->floatRegisters))[(calloutState->backfillFloatRegisterIndex)] = floatValue; + (calloutState->backfillFloatRegisterIndex = 0); + } + else { +((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)] = floatValue; + (calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + 1); + } + } + else { +if ((((calloutState->currentArg)) + 4) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + storeSingleFloatAtPointerfrom((calloutState->currentArg), floatValue); + (calloutState->currentArg = ((calloutState->currentArg)) + 4); + } + return 0; + } + else { +/* begin ffiPushDoubleFloat:in: */ + if (((calloutState->floatRegisterIndex)) < (NumFloatRegArgs - 1)) { + if ((((calloutState->floatRegisterIndex)) & 1) == 1) { + (calloutState->backfillFloatRegisterIndex = (calloutState->floatRegisterIndex)); + (calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + 1); + } + (((double*) ((&(((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)])))))[0] = floatValue; + (calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + 2); + } + else { +if ((((calloutState->currentArg)) + 8) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + (calloutState->floatRegisterIndex = NumFloatRegArgs); + storeFloatAtPointerfrom((calloutState->currentArg), floatValue); + (calloutState->currentArg = ((calloutState->currentArg)) + 8); + } + 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. */ + +static sqInt +ffiArgumentSpecClassin(sqInt oop, sqInt argSpec, sqInt argClass, CalloutState *calloutState) +{ + sqInt *argSpec1; + sqInt *argSpec2; + sqInt argSpecSize; + sqInt argSpecSize1; + sqInt atomicType; + sqInt atomicType1; + sqInt atomicType2; + sqInt availableRegisterSpace; + sqInt availableRegisterSpace1; + char *copy; + sqInt err; + double floatValue; + sqInt intValue; + sqInt isAlien; + sqInt isString; + sqInt isStruct; + sqInt length; + sqInt nilOop; + sqInt oopClass; + sqInt oopClass1; + sqInt oopClass2; + char *pointer; + void *pointer1; + void *pointer2; + void *pointer3; + int ptrAddress; + sqInt ptrClass; + sqInt ptrType; + sqInt roundedSize; + sqInt roundedSize1; + sqInt spec; + sqInt specOop; + sqInt specType; + sqInt stackPartSize; + sqInt stackPartSize1; + sqInt structSize; + sqInt structSize1; + sqInt typeSpec; + sqInt typeSpec1; + sqInt typeSpec2; + sqInt valueOop; + sqInt valueOop1; + + + /* Prefetch class (we'll need it) */ + +oopClass = fetchClassOf(oop); + + /* Do the necessary type checks */ + +nilOop = nilObject(); + if (!(argClass == nilOop)) { + + /* Type check 1: + Is the required class of the argument a subclass of ExternalStructure? */ + + if (!(includesBehaviorThatOf(argClass, classExternalStructure()))) { + return FFIErrorWrongType; + } + if (!((nilOop == oop) + || (includesBehaviorThatOf(oopClass, argClass)))) { + return FFIErrorCoercionFailed; + } + } + isStruct = 0; + if (!((isImmediate(oop)) + || (oop == nilOop))) { + + /* #isPointers: will fail if oop is immediate so don't even attempt to use it */ + +if (isPointers(oop)) { + 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 = fetchPointerofObject(0, valueOop); + if (isInMemory(ptrAddress)) { + return FFIErrorInvalidPointer; + } + /* begin ffiPushStructure:ofSize:typeSpec:ofLength:in: */ + structSize = ((calloutState->ffiArgHeader)) & FFIStructSizeMask; + argSpec2 = (calloutState->ffiArgSpec); + argSpecSize = (calloutState->ffiArgSpecSize); + availableRegisterSpace = (NumIntRegArgs - ((calloutState->integerRegisterIndex))) * 4; + stackPartSize = structSize; + if (availableRegisterSpace > 0) { +if (structSize <= availableRegisterSpace) { + + /* all in registers */ + +stackPartSize = 0; + memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ((void *) ptrAddress), structSize); + (calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + (((usqInt) (structSize + 3) >> 2))); + } + else { + + /* some in registers rest on stack */ + +stackPartSize = structSize - availableRegisterSpace; + memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ((void *) ptrAddress), availableRegisterSpace); + (calloutState->integerRegisterIndex = NumIntRegArgs); + } + } + if (stackPartSize > 0) { +roundedSize = (((stackPartSize + 3) | 3) - 3); + if ((((calloutState->currentArg)) + roundedSize) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + memcpy((calloutState->currentArg), (&((((char *) (((void *) ptrAddress))))[availableRegisterSpace])), stackPartSize); + (calloutState->currentArg = ((calloutState->currentArg)) + roundedSize); + } + return 0; + } + if (ptrClass == (classByteArray())) { + + /* The following is a somewhat pessimistic test but I like being sure... */ + +if (!((byteSizeOf(valueOop)) == (((calloutState->ffiArgHeader)) & FFIStructSizeMask))) { + return FFIErrorStructSize; + } + ptrAddress = ((int) (firstIndexableField(valueOop))); + if (!(((calloutState->ffiArgHeader)) & FFIFlagPointer)) { + + /* Since this involves passing the address of the first indexable field we need to fail + the call if it is threaded and the object is young, since it may move during the call. */ + + +# if COGMTVM + if ((((calloutState->callFlags)) & FFICallFlagThreaded) + && (isYoung(valueOop))) { + return -PrimErrObjectMayMove; + } + +# endif /* COGMTVM */ + + /* begin ffiPushStructure:ofSize:typeSpec:ofLength:in: */ + structSize1 = ((calloutState->ffiArgHeader)) & FFIStructSizeMask; + argSpec1 = (calloutState->ffiArgSpec); + argSpecSize1 = (calloutState->ffiArgSpecSize); + availableRegisterSpace1 = (NumIntRegArgs - ((calloutState->integerRegisterIndex))) * 4; + stackPartSize1 = structSize1; + if (availableRegisterSpace1 > 0) { +if (structSize1 <= availableRegisterSpace1) { + + /* all in registers */ + +stackPartSize1 = 0; + memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ((void *) ptrAddress), structSize1); + (calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + (((usqInt) (structSize1 + 3) >> 2))); + } + else { + + /* some in registers rest on stack */ + +stackPartSize1 = structSize1 - availableRegisterSpace1; + memcpy(((void *) ((&(((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)])))), ((void *) ptrAddress), availableRegisterSpace1); + (calloutState->integerRegisterIndex = NumIntRegArgs); + } + } + if (stackPartSize1 > 0) { +roundedSize1 = (((stackPartSize1 + 3) | 3) - 3); + if ((((calloutState->currentArg)) + roundedSize1) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + memcpy((calloutState->currentArg), (&((((char *) (((void *) ptrAddress))))[availableRegisterSpace1])), stackPartSize1); + (calloutState->currentArg = ((calloutState->currentArg)) + roundedSize1); + } + return 0; + } + if (!((((calloutState->ffiArgHeader)) & FFIStructSizeMask) == 4)) { + return FFIErrorStructSize; + } + ptrAddress = fetchPointerofObject(0, valueOop); + if (isInMemory(ptrAddress)) { + return FFIErrorInvalidPointer; + } + /* begin ffiPushPointer:in: */ + if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) { + ((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = ptrAddress; + (calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1); + } + else { +if ((((calloutState->currentArg)) + 4) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + longAtput((calloutState->currentArg), ptrAddress); + (calloutState->currentArg = ((calloutState->currentArg)) + 4); + } + 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)] = null; + (calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1); + } + else { +if ((((calloutState->currentArg)) + 4) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + longAtput((calloutState->currentArg), null); + (calloutState->currentArg = ((calloutState->currentArg)) + 4); + } + 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; + } + 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: */ + /* begin atomicTypeOf: */ + typeSpec2 = (calloutState->ffiArgHeader); + atomicType2 = ((usqInt) (typeSpec2 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift; + if (atomicType2 == FFITypeBool) { + + /* No bools on input */ + +return FFIErrorCoercionFailed; + } + isAlien = ((isString = includesBehaviorThatOf(oopClass, classString())) + ? 0 + : includesBehaviorThatOf(oopClass, classAlien())); + if ((((usqInt) atomicType2) >> 1) == (((usqInt) FFITypeSignedChar) >> 1)) { + + /* string value (char*) */ + /* note: the only types allowed for passing into char* types are + ByteArray, String, Symbol, Alien and *no* other byte indexed objects + (e.g., CompiledMethod, LargeInteger). We only check for strings + here and fall through to the byte* check otherwise. */ + + if (isString) { + + /* String/Symbol */ + /* Strings must be allocated by the ffi support code */ + +/* begin ffiPushString:OfLength:in: */ + pointer = firstIndexableField(oop); + length = byteSizeOf(oop); + if (((calloutState->stringArgIndex)) >= MaxNumArgs) { + return -PrimErrBadNumArgs; + } + copy = malloc(length + 1); + if (copy == null) { +return -PrimErrNoCMemory; + } + memcpy(copy, pointer, length); + copy[length] = 0; + ((calloutState->stringArgs))[(calloutState->stringArgIndex)] = copy; + (calloutState->stringArgIndex = ((calloutState->stringArgIndex)) + 1); + /* begin ffiPushPointer:in: */ + if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) { + ((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = copy; + (calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1); + } + else { +if ((((calloutState->currentArg)) + 4) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + longAtput((calloutState->currentArg), copy); + (calloutState->currentArg = ((calloutState->currentArg)) + 4); + } + return 0; + } + atomicType2 = 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) + || (isDirectAlien(oop))) + && (isYoung(oop)))) { + return -PrimErrObjectMayMove; + } + +# endif /* COGMTVM */ + + if ((atomicType2 == FFITypeVoid) + || ((((usqInt) atomicType2) >> 1) == (((usqInt) FFITypeSignedByte) >> 1))) { + + /* byte* -- see comment on string above */ + +if (isString + || (oopClass == (classByteArray()))) { + + /* String/Symbol/ByteArray */ + +/* begin ffiPushPointer:in: */ + pointer1 = firstIndexableField(oop); + if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) { + ((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = pointer1; + (calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1); + } + else { +if ((((calloutState->currentArg)) + 4) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + longAtput((calloutState->currentArg), pointer1); + (calloutState->currentArg = ((calloutState->currentArg)) + 4); + } + return 0; + } + if (isAlien) { +/* begin ffiPushPointer:in: */ + pointer2 = pointerForOop(((longAt(oop + BaseHeaderSize)) > 0 + ? (oop + BaseHeaderSize) + BytesPerOop + : longAt((oop + BaseHeaderSize) + BytesPerOop))); + if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) { + ((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = pointer2; + (calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1); + } + else { +if ((((calloutState->currentArg)) + 4) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + longAtput((calloutState->currentArg), pointer2); + (calloutState->currentArg = ((calloutState->currentArg)) + 4); + } + return 0; + } + if (!(atomicType2 == FFITypeVoid)) { + return FFIErrorCoercionFailed; + } + } + if ((atomicType2 <= FFITypeSignedInt) + || (atomicType2 == FFITypeSingleFloat)) { + + /* require a word subclass to work */ + +if (isWords(oop)) { + /* begin ffiPushPointer:in: */ + pointer3 = firstIndexableField(oop); + if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) { + ((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = pointer3; + (calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1); + } + else { +if ((((calloutState->currentArg)) + 4) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + longAtput((calloutState->currentArg), pointer3); + (calloutState->currentArg = ((calloutState->currentArg)) + 4); + } + return 0; + } + } + return FFIErrorCoercionFailed; + } + } + if (!isStruct) { +return FFIErrorCoercionFailed; + } + return ffiPushPointerContentsOfin(valueOop, calloutState); + } + if (((calloutState->ffiArgHeader)) & FFIFlagAtomic) { + + /* argument is atomic value */ + +/* begin ffiArgByValue:in: */ + /* begin atomicTypeOf: */ + typeSpec1 = (calloutState->ffiArgHeader); + atomicType1 = ((usqInt) (typeSpec1 & FFIAtomicTypeMask)) >> FFIAtomicTypeShift; + if ((atomicType1 < 0) + || (atomicType1 > FFITypeDoubleFloat)) { +return FFIErrorBadAtomicType; + } + if (atomicType1 < FFITypeSingleFloat) { + + /* integer types */ + +if ((((usqInt) atomicType1) >> 1) == (((usqInt) FFITypeSignedLongLong) >> 1)) { + + /* ffi support code must coerce longlong */ + +intValue = valueOop; + } + else { +/* begin ffiIntegerValueOf: */ + if (isIntegerObject(valueOop)) { + intValue = integerValueOf(valueOop); + goto l1; + } + if (valueOop == (nilObject())) { + intValue = 0; + goto l1; + } + if (valueOop == (falseObject())) { + intValue = 0; + goto l1; + } + if (valueOop == (trueObject())) { + intValue = 1; + goto l1; + } + oopClass2 = fetchClassOf(valueOop); + if (oopClass2 == (classFloat())) { + intValue = ((sqInt)(floatValueOf(valueOop))); + goto l1; + } + if (oopClass2 == (classCharacter())) { + intValue = characterValueOf(valueOop); + goto l1; + } + if (oopClass2 == (classLargePositiveInteger())) { + intValue = positive32BitValueOf(valueOop); + goto l1; + } + intValue = signedMachineIntegerValueOf(valueOop); + l1: /* end ffiIntegerValueOf: */; + } + if (failed()) { + return FFIErrorCoercionFailed; + } + + switch (atomicType1) { + 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: */ + oopClass1 = fetchClassOf(valueOop); + if (oopClass1 == (classFloat())) { + floatValue = floatValueOf(valueOop); + goto l2; + } + floatValue = ((double) (ffiIntegerValueOf(valueOop)) ); + l2: /* end ffiFloatValueOf: */; + if (failed()) { + return FFIErrorCoercionFailed; + } + if (atomicType1 == FFITypeSingleFloat) { +/* begin ffiPushSingleFloat:in: */ + if (((calloutState->floatRegisterIndex)) < NumFloatRegArgs) { + if (((calloutState->backfillFloatRegisterIndex)) > 0) { + ((calloutState->floatRegisters))[(calloutState->backfillFloatRegisterIndex)] = floatValue; + (calloutState->backfillFloatRegisterIndex = 0); + } + else { +((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)] = floatValue; + (calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + 1); + } + } + else { +if ((((calloutState->currentArg)) + 4) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + storeSingleFloatAtPointerfrom((calloutState->currentArg), floatValue); + (calloutState->currentArg = ((calloutState->currentArg)) + 4); + } + return 0; + } + else { +/* begin ffiPushDoubleFloat:in: */ + if (((calloutState->floatRegisterIndex)) < (NumFloatRegArgs - 1)) { + if ((((calloutState->floatRegisterIndex)) & 1) == 1) { + (calloutState->backfillFloatRegisterIndex = (calloutState->floatRegisterIndex)); + (calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + 1); + } + (((double*) ((&(((calloutState->floatRegisters))[(calloutState->floatRegisterIndex)])))))[0] = floatValue; + (calloutState->floatRegisterIndex = ((calloutState->floatRegisterIndex)) + 2); + } + else { +if ((((calloutState->currentArg)) + 8) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + (calloutState->floatRegisterIndex = NumFloatRegArgs); + storeFloatAtPointerfrom((calloutState->currentArg), floatValue); + (calloutState->currentArg = ((calloutState->currentArg)) + 8); + } + 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 or Alien. + */ + +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; + 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 = 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)] = copy; + (calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1); + } + else { +if ((((calloutState->currentArg)) + 4) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + longAtput((calloutState->currentArg), copy); + (calloutState->currentArg = ((calloutState->currentArg)) + 4); + } + 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) + || (isDirectAlien(oop))) + && (isYoung(oop)))) { + return -PrimErrObjectMayMove; + } + +# endif /* COGMTVM */ + + if ((atomicType == FFITypeVoid) + || ((((usqInt) atomicType) >> 1) == (((usqInt) FFITypeSignedByte) >> 1))) { + + /* byte* -- see comment on string above */ + +if (isString + || (oopClass == (classByteArray()))) { + + /* String/Symbol/ByteArray */ + +/* begin ffiPushPointer:in: */ + pointer1 = firstIndexableField(oop); + if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) { + ((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = pointer1; + (calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1); + } + else { +if ((((calloutState->currentArg)) + 4) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + longAtput((calloutState->currentArg), pointer1); + (calloutState->currentArg = ((calloutState->currentArg)) + 4); + } + return 0; + } + if (isAlien) { +/* begin ffiPushPointer:in: */ + pointer2 = pointerForOop(((longAt(oop + BaseHeaderSize)) > 0 + ? (oop + BaseHeaderSize) + BytesPerOop + : longAt((oop + BaseHeaderSize) + BytesPerOop))); + if (((calloutState->integerRegisterIndex)) < NumIntRegArgs) { + ((calloutState->integerRegisters))[(calloutState->integerRegisterIndex)] = pointer2; + (calloutState->integerRegisterIndex = ((calloutState->integerRegisterIndex)) + 1); + } + else { +if ((((calloutState->currentArg)) + 4) > ((calloutState->limit))) { + return FFIErrorCallFrameTooBig; + } + longAtput((calloutState->currentArg), pointer2); + (calloutState->currentArg = ((calloutState->currentArg)) + 4); + } + return 0; + } + if (!(atomicType == FFITypeVoid)) { + return FFIErrorCoercionFailed; + } + } + if ((atomicType <= FFITypeSignedInt)
@@ Diff output truncated at 50000 characters. @@
vm-dev@lists.squeakfoundation.org