|
From: Brenda L. <asp...@us...> - 2003-05-12 07:26:32
|
Update of /cvsroot/squeak/squeak/platforms/unix/plugins/SqueakFFIPrims
In directory sc8-pr-cvs1:/tmp/cvs-serv30143/plugins/SqueakFFIPrims
Added Files:
00README Makefile Makefile.in acinclude.m4 any-libffi-asm.S
any-libffi.c ffi-config ffi-test-main.c ffi-test-sq.h
ffi-test.c ffi-test.h ppc-darwin-asm.S ppc-darwin.c
ppc-global.h ppc-sysv-asm.S ppc-sysv.c x86-sysv-asm.S
x86-sysv.c
Log Message:
Ian Piumarta's release 3.4.1
--- NEW FILE: 00README ---
This directory contains support code for the Squeak FFI (foreign
function interface) primitives. You should not even be here reading
this unless (i) the configure script refuses to include FFI support in
your build, or (ii) you want to try to make your FFI calls go lots
faster by avoiding the use of libffi.
About the FFI primitives
------------------------
Squeak can dynamically construct callouts to C code at runtime via one
of two mechanisms, `apicall' and `cdecl'. The `cdecl' method
constructs a `call interface description' (a data structure
representing a function's signature) which is used by libffi [1] to
construct and invoke a call to the foreign function. This method is
portable but horribly slow. The `apicall' method constructs a stack
frame on-the-fly which is used to invoke the foreign function
directly.
The `apicall' method is MUCH faster than `cdecl' (more than FOUR times
faster) but relies on horribly platform-dependent code.
Support for the `apicall' method is now available for a few platforms
on Unix:
- PowerPC and x86 using the SVr4 ABI (found on most GNU/Linux and
BSD-like systems, with the notable exception of Darwin/MacOSX)
- PowerPC using the Darwin ABI (similar to Mach)
Testing your FFI support
------------------------
First run the script `ffi-test-config' (no arguments) which will look
to see if your platform has support for the `apicall' method. If it
prints `any-libffi' then you must either install libffi [1] before you
can use the FFI primitives or implement the missing support [2]. If
it prints anything else then it has found what it thinks is suitable
support for your platform [3].
To run the test suite, just type `make' [4]. This will build a program
called `main' that tries quite hard to break the FFI support code. If
it fails using the built-in support code then you've found a bug in
either the support code or the test code [5]. If you want to try
again with libffi, then type:
make clean
make CPU=any ABI=libffi LIB=-lffi
./main
If it fails again you've found a bug either in libffi (send bug
reports to the relevant mailing list, not me) or in the test code.
To tidy up afterwards, type `make clean'.
Notes
-----
[1] libffi is now part of gcc. If you need to install it, download
just the contents of the top-level `gcc' directory and the
`libffi' subdirectory. Then `cd' to `libffi' and type:
./configure
make
sudo make install
If it breaks, you get to keep the pieces.
[2] Figure out your canonical cpu and abi (os) name. Write a bunch of
C code to create a stack frame in `${cpu}-${abi}.c' and the
assembler `trampoline' that pused it and jumps to the destination
function in the file `${cpu}-${abi}-asm.S'. This will allow the
configure script to find and use your support.
[3] If it doesn't find support code for your platform and you think it
should (based on the cpu-abi variants available) then add your
canonical host/os names to the tests in ffi-test-config. If the
resulting program works, make similar changes in `acinclude.m4' so
that the support is included in the Squeak VM. Then mail the
modified files to me [5].
[4] By default the Makefile will try to figure this out for itself
using rules similar to those in the configure script. You must be
using GNU make for this to work.
[5] Send bug reports and support code for new platforms to:
ian...@in...
--- NEW FILE: Makefile ---
### This Makefile is NOT used to build Squeak.
###
### See the file `00README' for instructions.
###
### Last edited: 2003-01-30 00:02:00 by piumarta on emilia.inria.fr
CPU= $(shell ./ffi-config -cpu)
ABI= $(shell ./ffi-config -abi)
LIB= $(shell ./ffi-config -lib)
INC= -I../../../Cross/plugins/SqueakFFIPrims
DEF= -DFFI_TEST
CFLAGS= -g -Wall -Wno-unused -O2 $(DEF) $(INC)
OBJ= ffi-test-main.o ffi-test.o $(CPU)-$(ABI).o $(CPU)-$(ABI)-asm.o
main : sq.h $(OBJ)
gcc -g -o $@ $(OBJ) $(LIB)
libffi :
$(MAKE) CPU=any ABI=libffi LIB=-lffi
sq.h :
ln -s ffi-test-sq.h sq.h
%.o : Makefile
clean :
/bin/rm -f *~ *.o main sq.h
--- NEW FILE: Makefile.in ---
# Makefile.in for FFIPlugin on Unix
#
# Author: ian...@in...
#
# Last edited: 2003-01-28 10:59:01 by piumarta on emilia.inria.fr
[make_cfg]
[make_plg]
TARGET = SqueakFFIPrims$a
OBJS = SqueakFFIPrims$o ffi-test$o $(FFI_O)
XINCLUDES = [includes]
$(TARGET) : $(OBJS) Makefile
$(LINK) $(TARGET) $(OBJS)
$(RANLIB) $(TARGET)
[make_targets]
.force :
--- NEW FILE: acinclude.m4 ---
AC_MSG_CHECKING([for FFI support])
FFI_DIR=${topdir}/platforms/unix/plugins/SqueakFFIPrims
ffi_cpu_abi=`${FFI_DIR}/ffi-config ${cfgdir} ${FFI_DIR} -cpu-abi`
if test "${ffi_cpu_abi}" != "any-libffi"; then
AC_MSG_RESULT([${ffi_cpu_abi}])
else
AC_MSG_RESULT([requires libffi])
ffi_cpu_abi=any-libffi
AC_CHECK_HEADER(ffi.h,
AC_CHECK_LIB(ffi, ffi_call,
AC_PLUGIN_USE_LIB(ffi),
AC_PLUGIN_DISABLE),
AC_PLUGIN_DISABLE)
fi
FFI_C=${ffi_cpu_abi}
FFI_S=${ffi_cpu_abi}-asm
FFI_O="${FFI_C}\$o ${FFI_S}\$o"
AC_SUBST(FFI_DIR)
AC_SUBST(FFI_C)
AC_SUBST(FFI_S)
AC_SUBST(FFI_O)
--- NEW FILE: any-libffi-asm.S ---
--- NEW FILE: any-libffi.c ---
/****************************************************************************
* PROJECT: Squeak foreign function interface
* FILE: sqUnixFFI.c
* CONTENT: Unix support for the foreign function interface
*
* AUTHOR: Andreas Raab (ar)
* ADDRESS: Walt Disney Imagineering, Glendale, CA
* EMAIL: and...@wd...
* RCSID: $Id: any-libffi.c,v 1.1 2003/05/12 07:26:28 asparagi Exp $
*
* NOTES: The Unix version of the FFI support code relies on libffi from
* http://sourceware.cygnus.com/libffi/
*
*****************************************************************************/
#include "sq.h"
#include "sqFFI.h"
#ifndef NO_FFI_SUPPORT
#include <ffi.h>
#ifndef FFI_TYPE_STRUCT /* this is private in libffi-2 */
# define FFI_TYPE_STRUCT 13
#endif
#if defined(FFI_TEST)
static int primitiveFail(void) { puts("primitive fail"); exit(1); return 0; }
#else
extern struct VirtualMachine *interpreterProxy;
# define primitiveFail() interpreterProxy->primitiveFail();
#endif
#if 1
#define HAVE_LONGLONG
#endif
/* Check if HAVE_LONGLONG is defined (should be figured out by configure */
#ifdef HAVE_LONGLONG
#define HAS_LONGLONG 1
#define LONGLONG long long
#endif
/* Error if LONGLONG is not defined */
#if HAS_LONGLONG
#ifndef LONGLONG
#error "You must define LONGLONG if HAS_LONGLONG is defined"
#endif
#endif
/* Max number of arguments in call */
#define FFI_MAX_ARGS 32
static ffi_type* ffiTypes[FFI_MAX_ARGS];
static void* ffiArgs[FFI_MAX_ARGS];
static char ffiBytes[FFI_MAX_ARGS];
static short ffiShorts[FFI_MAX_ARGS];
static int ffiInts[FFI_MAX_ARGS];
static float ffiFloats[FFI_MAX_ARGS];
static double ffiDoubles[FFI_MAX_ARGS];
static int ffiArgIndex = 0;
static ffi_type* ffiStructTypes[FFI_MAX_ARGS];
static int ffiStructIndex = 0;
/* helpers */
#define CHECK_ARGS() if(ffiArgIndex >= FFI_MAX_ARGS) return primitiveFail();
#define PUSH_TYPE(type) { CHECK_ARGS(); ffiTypes[ffiArgIndex] = &type; }
#define PUSH(where, what, type) { \
PUSH_TYPE(type); where[ffiArgIndex] = what; \
ffiArgs[ffiArgIndex] = (void*) (where + ffiArgIndex); \
ffiArgIndex++;\
}
#define BARG_PUSH(value, type) PUSH(ffiBytes, value, type)
#define SARG_PUSH(value, type) PUSH(ffiShorts, value, type)
#define IARG_PUSH(value, type) PUSH(ffiInts, value, type)
#define FARG_PUSH(value) PUSH(ffiFloats, value, ffi_type_float)
#define DARG_PUSH(value) PUSH(ffiDoubles, value, ffi_type_double)
#if HAS_LONGLONG
static LONGLONG ffiLongLongs[FFI_MAX_ARGS];
#define LARG_PUSH(value, type) PUSH(ffiLongLongs, value, type)
#endif
/* The 64bit return value storage area - aligned by the C compiler */
static double returnValue;
/* Storage area for large structure returns */
static ffi_type* structReturnType = NULL;
static void *structReturnValue = NULL;
/* The area for temporarily allocated strings */
static char *ffiTempStrings[FFI_MAX_ARGS];
/* The number of temporarily allocated strings */
static int ffiTempStringCount = 0;
/*****************************************************************************/
/*****************************************************************************/
/* ffiInitialize:
Announce that the VM is about to do an external function call. */
int ffiInitialize(void)
{
ffiArgIndex = 0;
ffiTempStringCount = 0;
ffiStructIndex = 0;
structReturnType = NULL;
structReturnValue = NULL;
return 1;
}
/* ffiSupportsCallingConvention:
Return true if the support code supports the given calling convention */
int ffiSupportsCallingConvention(int callType)
{
if(callType == FFICallTypeCDecl) return 1;
return 0;
}
/* ffiAlloc:
Allocate space from the external heap */
int ffiAlloc(int byteSize)
{
return (int)malloc(byteSize);
}
/* ffiFree:
Free space from the external heap */
int ffiFree(int pointer)
{
if(pointer) free((void*)pointer);
return 1;
}
/*****************************************************************************/
/*****************************************************************************/
int ffiPushSignedByte(int value)
{
BARG_PUSH((char)value, ffi_type_sint8);
return 1;
}
int ffiPushUnsignedByte(int value)
{
BARG_PUSH((char)value, ffi_type_uint8);
return 1;
}
int ffiPushSignedShort(int value)
{
SARG_PUSH((short)value, ffi_type_sint16);
return 1;
}
int ffiPushUnsignedShort(int value)
{
SARG_PUSH((short)value, ffi_type_uint16);
return 1;
}
int ffiPushSignedInt(int value)
{
IARG_PUSH(value, ffi_type_sint32);
return 1;
}
int ffiPushUnsignedInt(int value)
{
IARG_PUSH(value, ffi_type_uint32);
return 1;
}
int ffiPushSignedLongLong(int low, int high)
{
#if HAS_LONGLONG
LONGLONG value = (((LONGLONG) high) << 32) | ((LONGLONG) (unsigned) low);
LARG_PUSH(value, ffi_type_sint64);
return 1;
#else
return primitiveFail();
#endif
}
int ffiPushUnsignedLongLong(int low, int high)
{
#if HAS_LONGLONG
LONGLONG value = (((LONGLONG) high) << 32) | ((LONGLONG) (unsigned) low);
LARG_PUSH(value, ffi_type_uint64);
return 1;
#else
return primitiveFail();
#endif
}
int ffiPushSignedChar(int value)
{
BARG_PUSH(value, ffi_type_sint8);
return 1;
}
int ffiPushUnsignedChar(int value)
{
BARG_PUSH(value, ffi_type_uint8);
return 1;
}
int ffiPushBool(int value)
{
IARG_PUSH(value, ffi_type_uint8);
return 1;
}
int ffiPushSingleFloat(double value)
{
FARG_PUSH((float)value);
return 1;
}
int ffiPushDoubleFloat(double value)
{
DARG_PUSH(value);
return 1;
}
ffi_type* ffiCreateType(int *structSpec, int structSize)
{
ffi_type *structType, **newTypes;
int nTypes, i, typeSpec;
/* count the number of atomic types we need to create */
nTypes = 0;
for(i=0; i<structSize; i++) {
typeSpec = structSpec[i];
if(typeSpec & FFIFlagPointer) nTypes++;
else if(typeSpec & FFIFlagAtomic) nTypes++;
}
/* note: nTypes == 0 means an invalid structure */
if(nTypes == 0) {
printf("Warning: nTypes == 0 in ffiCreateTypes\n");
return NULL;
}
/* allocate the structure type */
structType = calloc(1, sizeof(ffi_type));
/* allocate the atomic type refs */
newTypes = calloc(nTypes+1, sizeof(ffi_type*));
/* number of elements in type */
structType->size = (*structSpec) & FFIStructSizeMask;
structType->alignment = 4;
structType->type = FFI_TYPE_STRUCT;
structType->elements = newTypes;
/* now go over the structure and fill in the fields */
nTypes = 0;
for(i=0; i<structSize; i++) {
typeSpec = structSpec[i];
if(typeSpec & FFIFlagPointer) {
newTypes[nTypes++] = &ffi_type_pointer;
continue;
}
if((typeSpec & FFIFlagAtomic) == 0) continue;
switch((typeSpec & FFIAtomicTypeMask) >> FFIAtomicTypeShift) {
case FFITypeBool:
newTypes[nTypes++] = &ffi_type_uint8; break;
case FFITypeUnsignedByte:
newTypes[nTypes++] = &ffi_type_uint8; break;
case FFITypeSignedByte:
newTypes[nTypes++] = &ffi_type_sint8; break;
case FFITypeUnsignedShort:
newTypes[nTypes++] = &ffi_type_uint16; break;
case FFITypeSignedShort:
newTypes[nTypes++] = &ffi_type_sint16; break;
case FFITypeUnsignedInt:
newTypes[nTypes++] = &ffi_type_uint32; break;
case FFITypeSignedInt:
newTypes[nTypes++] = &ffi_type_sint32; break;
case FFITypeUnsignedLongLong:
newTypes[nTypes++] = &ffi_type_uint64; break;
case FFITypeSignedLongLong:
newTypes[nTypes++] = &ffi_type_sint64; break;
case FFITypeUnsignedChar:
newTypes[nTypes++] = &ffi_type_uint8; break;
case FFITypeSignedChar:
newTypes[nTypes++] = &ffi_type_sint8; break;
case FFITypeSingleFloat:
newTypes[nTypes++] = &ffi_type_float; break;
case FFITypeDoubleFloat:
newTypes[nTypes++] = &ffi_type_double; break;
default:
printf("Warning: unknown atomic type (%x) in ffiCreateTypes\n",
typeSpec);
free(newTypes);
free(structType);
return NULL;
};
}
newTypes[nTypes++] = NULL;
return structType;
}
int ffiPushStructureOfLength(int pointer, int* structSpec, int structSize)
{
ffi_type *structType;
if(pointer == 0) return primitiveFail();
CHECK_ARGS(); /* fail early on */
structType = ffiCreateType(structSpec, structSize);
if(structType == NULL) return primitiveFail();
ffiStructTypes[ffiStructIndex++] = structType;
ffiTypes[ffiArgIndex] = structType;
ffiArgs[ffiArgIndex] = (void*) pointer;
ffiArgIndex++;
return 1;
}
int ffiPushPointer(int pointer)
{
IARG_PUSH(pointer, ffi_type_pointer);
return 1;
}
int ffiPushStringOfLength(int srcIndex, int length)
{
char *ptr;
ptr = (char*) malloc(length+1);
if(!ptr) return primitiveFail();
memcpy(ptr, (void*)srcIndex, length);
ptr[length] = 0;
ffiTempStrings[ffiTempStringCount++] = ptr;
IARG_PUSH((int)ptr, ffi_type_pointer);
return 1;
}
/*****************************************************************************/
/*****************************************************************************/
/* ffiCanReturn:
Return true if the support code can return the given type. */
int ffiCanReturn(int *structSpec, int specSize)
{
int header = *structSpec;
if(header & FFIFlagPointer) return 1;
if(header & FFIFlagStructure) {
int structSize = header & FFIStructSizeMask;
structReturnType = ffiCreateType(structSpec, specSize);
if(!structReturnType) return 0;
if(structSize > 8) {
structReturnValue = calloc(1,structSize);
if(!structReturnValue) return 0;
return 1;
}
}
return 1;
}
/* ffiReturnFloatValue:
Return the value from a previous ffi call with float return type. */
double ffiReturnFloatValue(void)
{
return returnValue;
}
/* ffiLongLongResultLow:
Return the low 32bit from the 64bit result of a call to an external function */
int ffiLongLongResultLow(void)
{
#if HAS_LONGLONG
return (int) ( (*(LONGLONG*)&returnValue) & (LONGLONG)0xFFFFFFFFU);
#else
return 0;
#endif
}
/* ffiLongLongResultHigh:
Return the high 32bit from the 64bit result of a call to an external function */
int ffiLongLongResultHigh(void)
{
#if HAS_LONGLONG
return (int) ( (*(LONGLONG*)&returnValue) >> 32);
#else
return 0;
#endif
}
/* ffiStoreStructure:
Store the structure result of a previous ffi call into the given address*/
int ffiStoreStructure(int address, int structSize)
{
if(structReturnValue) {
memcpy((void*)address, (void*)structReturnValue, structSize);
} else {
memcpy((void*)address, (void*)&returnValue, structSize);
}
return 1;
}
/* ffiCleanup:
Cleanup after a foreign function call has completed.
The generic support code only frees the temporarily
allocated strings. */
int ffiCleanup(void)
{
int i;
for(i=0; i<ffiTempStringCount; i++)
free(ffiTempStrings[i]);
for(i=0; i<ffiStructIndex; i++) {
free(ffiStructTypes[i]->elements);
free(ffiStructTypes[i]);
ffiStructTypes[i]=NULL;
}
if(structReturnType) {
free(structReturnType->elements);
free(structReturnType);
structReturnType = NULL;
}
if(structReturnValue) {
free(structReturnValue);
structReturnValue = NULL;
}
ffiTempStringCount = 0;
ffiStructIndex = 0;
return 1;
}
/*****************************************************************************/
/*****************************************************************************/
int ffiCallAddress(int fn, ffi_type *returnType, int atomicArgType)
{
ffi_cif cif;
ffi_status result;
int retVal;
result = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, ffiArgIndex,
returnType, ffiTypes);
if(result != FFI_OK) return primitiveFail();
if(structReturnValue) {
ffi_call(&cif, (void *)fn, (void *)structReturnValue, (void **)ffiArgs);
return (int) structReturnValue;
}
ffi_call(&cif, (void *)fn, (void *)&returnValue, (void **)ffiArgs);
retVal = *(int*)&returnValue;
#ifdef FFI_MIPS_N32
/* Note: MIPS N32 ABI returns 64bit for integer/pointer whatever.
This seems to be a bug in the fficall implementation. */
retVal = ((int*)(&returnValue))[1];
#endif
/* Promote certain return types to integral size */
switch(atomicArgType) {
case FFITypeUnsignedChar:
case FFITypeUnsignedByte: retVal = *(unsigned char*) &retVal; break;
case FFITypeSignedChar:
case FFITypeSignedByte: retVal = *(signed char*) &retVal; break;
case FFITypeUnsignedShort: retVal = *(unsigned short*) &retVal; break;
case FFITypeSignedShort: retVal = *(signed short*) &retVal; break;
case FFITypeSingleFloat: returnValue = *(float*)&returnValue; break;
}
return retVal;
}
int ffiCallAddressOfWithPointerReturn(int fn, int callType)
{
return ffiCallAddress(fn, &ffi_type_pointer,-1);
}
int ffiCallAddressOfWithStructReturn(int fn, int callType,
int *structSpec, int specSize)
{
if(!structReturnType) return primitiveFail();
return ffiCallAddress(fn, structReturnType,-1);
}
int ffiCallAddressOfWithReturnType(int fn, int callType, int typeSpec)
{
ffi_type *returnType;
int atomicType;
atomicType = (typeSpec & FFIAtomicTypeMask) >> FFIAtomicTypeShift;
switch(atomicType) {
case FFITypeVoid: returnType = &ffi_type_void; break;
case FFITypeBool: returnType = &ffi_type_uint8; break;
case FFITypeUnsignedByte: returnType = &ffi_type_uint8; break;
case FFITypeSignedByte: returnType = &ffi_type_sint8; break;
case FFITypeUnsignedShort: returnType = &ffi_type_uint16; break;
case FFITypeSignedShort: returnType = &ffi_type_sint16; break;
case FFITypeUnsignedInt: returnType = &ffi_type_uint32; break;
case FFITypeSignedInt: returnType = &ffi_type_sint32; break;
case FFITypeUnsignedLongLong: returnType = &ffi_type_uint64; break;
case FFITypeSignedLongLong: returnType = &ffi_type_sint64; break;
case FFITypeUnsignedChar: returnType = &ffi_type_uint8; break;
case FFITypeSignedChar: returnType = &ffi_type_sint8; break;
case FFITypeSingleFloat: returnType = &ffi_type_float; break;
case FFITypeDoubleFloat: returnType = &ffi_type_double; break;
default:
return primitiveFail();
}
return ffiCallAddress(fn, returnType, atomicType);
}
#if defined(FFI_TEST)
void ffiDoAssertions(void) {}
#endif
#endif /* NO_FFI_SUPPORT */
--- NEW FILE: ffi-config ---
#!/bin/sh
#
# ffi-config [cfgdir] [options...]
#
# -cpu print the supported cpu name or `any'
# -abi print the supported abu name or `libffi'
# -lib print nothing if supported, otherwise `-lffi'
# -query exit with status 0 if supported, 1 if libffi required
cfgdir=../../config
if [ $# -gt 0 ]; then
case $1 in
-*) ;;
*) cfgdir=$1; shift;;
esac
fi
ffidir=.
if [ $# -gt 0 ]; then
case $1 in
-*) ;;
*) ffidir=$1; shift;;
esac
fi
guess=`${cfgdir}/config.guess`
host=`${cfgdir}/config.sub ${guess}`
cpu=`echo ${host} | sed 's/-.*//'`
abi=`echo ${host} | sed 's/[^-]*-[^-]*-//;s/-.*//'`
lib=
case ${cpu} in
powerpc|ppc) cpu=ppc;;
i[3456789]86) cpu=x86;;
*) cpu=any;;
esac
case ${abi} in
linux) abi=sysv;;
darwin*) abi=darwin;;
*) abi=libffi; lib="-lffi";;
esac
if [ ! -f ${ffidir}/${cpu}-${abi}.c ] || [ ! -f ${ffidir}/${cpu}-${abi}-asm.S ]; then
cpu=any
abi=libffi
lib="-lffi"
fi
if [ ! -f ${ffidir}/${cpu}-${abi}.c ] || [ ! -f ${ffidir}/${cpu}-${abi}-asm.S ]; then
echo "Could not find ${cpu}-${abi}.c and ${cpu}-${abi}-asm.S" >&2
exit 1
fi
if [ $# -eq 0 ]; then
echo "${cpu}-${abi}" "${lib}"
else
while [ $# -gt 0 ]; do
case $1 in
-cpu) echo ${cpu};;
-abi) echo ${abi};;
-lib) echo ${lib};;
-cpu-abi) echo ${cpu}-${abi};;
-query) if [ ${abi} = "libffi" ]; then exit 1; else exit 0; fi;;
*) echo "$0: I don't understand \`$1'" >&1; exit 1;;
esac
shift
done
fi
exit 0
--- NEW FILE: ffi-test-main.c ---
/* ffi-test-main.c -- try hard to break the FFI from C
*
* Author: Ian...@IN...
*
* Based on a similar test suite in libffi, which contains the following text...
*
* Copyright (c) 1996, 1997, 1998, 2002, 2003 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* ``Software''), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h>
#include "sqFFI.h"
#if 0
# define dprintf(ARGS) printf ARGS
# define puts(ARG) puts(ARG)
#else
# define dprintf(ARGS)
# define puts(ARG)
#endif
#if 1
# define long_double double
# define Lf "f"
#else
# define long_double long double
# define Lf "Lf"
#endif
#define CHECK(x) !(x) ? fail(__FILE__, __LINE__) : 0
static int fail(char *file, int line)
{
fprintf(stderr, "%s: failed at line %d\n", file, line);
exit(EXIT_FAILURE);
return 0;
}
#define MAX_ARGS 256
static size_t my_strlen(char *s) { return strlen(s); }
static int promotion(signed char sc, signed short ss, unsigned char uc, unsigned short us)
{
int r= (int)sc + (int)ss + (int)uc + (int)us;
return r;
}
static signed char return_sc(signed char sc) { return sc; }
static unsigned char return_uc(unsigned char uc) { return uc; }
static long long return_ll(long long ll) { return ll; }
static int floating(int a, float b, double c, long_double d, int e)
{
int i;
dprintf(("%d %f %f %"Lf" %d\n", a, (double)b, c, d, e));
i= (int)((float)a/b + ((float)c/(float)d));
return i;
}
static float many(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9, float f10, float f11, float f12, float f13, float f14, float f15)
{
dprintf(("%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
(double)f1, (double)f2, (double)f3, (double)f4, (double)f5,
(double)f6, (double)f7, (double)f8, (double)f9, (double)f10,
(double)f11, (double)f12, (double)f13, (double)f14, (double)f15));
return ((f1/f2+f3/f4+f5/f6+f7/f8+f9/f10+f11/f12+f13/f14) * f15);
}
static double dblit(float f) { return f/3.0; }
static long_double ldblit(float f) { return (long_double)(((long_double)f)/ (long_double)3.0); }
#define TYPE(T,S) ((FFIType##T << FFIAtomicTypeShift) | (S) | FFIFlagAtomic)
typedef struct { unsigned char uc; double d; unsigned int ui; } test_structure_1;
static int spec_structure_1[]= {
FFIFlagStructure | sizeof(test_structure_1),
TYPE(UnsignedChar,4), TYPE(DoubleFloat,8), TYPE(UnsignedInt,4)
};
static test_structure_1 struct1(test_structure_1 ts)
{
dprintf(("%d %f %d\n", ts.uc, ts.d, ts.ui));
ts.uc++; ts.d--; ts.ui++; return ts;
}
typedef struct { double d1; double d2;} test_structure_2;
static int spec_structure_2[]= {
FFIFlagStructure | sizeof(test_structure_2),
TYPE(DoubleFloat,8), TYPE(DoubleFloat,8)
};
static test_structure_2 struct2(test_structure_2 ts)
{
ts.d1--; ts.d2--; return ts;
}
typedef struct { int si; } test_structure_3;
static int spec_structure_3[]= {
FFIFlagStructure | sizeof(test_structure_3),
TYPE(SignedInt,4)
};
static test_structure_3 struct3(test_structure_3 ts)
{
ts.si= -(ts.si*2); return ts;
}
typedef struct { unsigned ui1; unsigned ui2; unsigned ui3; } test_structure_4;
static int spec_structure_4[]= {
FFIFlagStructure | sizeof(test_structure_4),
TYPE(UnsignedInt,4), TYPE(UnsignedInt,4), TYPE(UnsignedInt,4)
};
static test_structure_4 struct4(test_structure_4 ts)
{
ts.ui3= ts.ui1 * ts.ui2 * ts.ui3; return ts;
}
typedef struct { char c1; char c2; } test_structure_5;
static int spec_structure_5[]= {
FFIFlagStructure | sizeof(test_structure_5),
TYPE(SignedChar,1), TYPE(SignedChar,1)
};
static test_structure_5 struct5(test_structure_5 ts1, test_structure_5 ts2)
{
dprintf(("%d %d %d %d\n", ts1.c1, ts1.c2, ts2.c1, ts2.c2));
ts1.c1 += ts2.c1; ts1.c2 -= ts2.c2; return ts1;
}
typedef struct { float f; double d; } test_structure_6;
static int spec_structure_6[]= {
FFIFlagStructure | sizeof(test_structure_6),
TYPE(SingleFloat,4), TYPE(DoubleFloat,8)
};
static test_structure_6 struct6 (test_structure_6 ts)
{
ts.f += 1; ts.d += 1; return ts;
}
typedef struct { float f1; float f2; double d; } test_structure_7;
static int spec_structure_7[]= {
FFIFlagStructure | sizeof(test_structure_7),
TYPE(SingleFloat,4), TYPE(SingleFloat,4), TYPE(DoubleFloat,8)
};
static test_structure_7 struct7 (test_structure_7 ts)
{
ts.f1 += 1; ts.f2 += 1; ts.d += 1; return ts;
}
typedef struct { float f1; float f2; float f3; float f4; } test_structure_8;
static int spec_structure_8[]= {
FFIFlagStructure | sizeof(test_structure_8),
TYPE(SingleFloat,4), TYPE(SingleFloat,4), TYPE(SingleFloat,4), TYPE(SingleFloat,4)
};
static test_structure_8 struct8 (test_structure_8 ts)
{
ts.f1 += 1; ts.f2 += 1; ts.f3 += 1; ts.f4 += 1; return ts;
}
typedef struct { float f; int i; } test_structure_9;
static int spec_structure_9[]= {
FFIFlagStructure | sizeof(test_structure_9),
TYPE(SingleFloat,4), TYPE(SignedInt,4)
};
static test_structure_9 struct9 (test_structure_9 ts)
{
ts.f += 1; ts.i += 1; return ts;
}
#define SPEC(S) spec_##S, (sizeof(spec_##S) / sizeof(int))
#define GO(T,F) ffiCallAddressOfWithReturnType((int)(F), FFICallTypeCDecl, \
(T) << FFIAtomicTypeShift)
#define GOS(S,F) ffiCallAddressOfWithStructReturn((int)(F), FFICallTypeCDecl, SPEC(S))
void ctests(void)
{
CHECK(sizeof(char) == 1);
CHECK(sizeof(short) == 2);
CHECK(sizeof(int) == 4);
CHECK(sizeof(long) == 4);
CHECK(sizeof(long long) == 8);
CHECK(sizeof(float) == 4);
CHECK(sizeof(double) == 8);
CHECK(sizeof(long_double) == 8); //xxx BOGUS BOGUS BOGUS BOGUS BOGUS
puts("long long tests...");
{
long long ll, rll;
for (ll= 0LL; ll < 100LL; ++ll)
{
ffiInitialize();
ffiPushSignedLongLong(ll % 0x100000000, ll / 0x100000000);
GO(FFITypeSignedLongLong, return_ll);
rll= ffiLongLongResultHigh() * 0x100000000LL + ffiLongLongResultLow();
ffiCleanup();
dprintf(("%lld %lld\n", ll, rll));
CHECK(rll == ll);
}
for (ll= 55555555555000LL; ll < 55555555555100LL; ll++)
{
ffiInitialize();
ffiPushSignedLongLong(ll % 0x100000000, ll / 0x100000000);
GO(FFITypeSignedLongLong, return_ll);
rll= ffiLongLongResultHigh() * 0x100000000LL + ffiLongLongResultLow();
ffiCleanup();
CHECK(rll == ll);
}
}
puts("char tests...");
{
signed char sc;
unsigned char uc;
int rint;
for (sc= (signed char)-127; sc < (signed char)127; ++sc)
{
ffiInitialize();
ffiPushSignedChar(sc);
rint= GO(FFITypeSignedInt, return_sc);
ffiCleanup();
CHECK(rint == (int)sc);
}
for (uc= (unsigned char)'\x00'; uc < (unsigned char)'\xff'; ++uc)
{
ffiInitialize();
ffiPushUnsignedChar(uc);
rint= GO(FFITypeSignedInt, return_uc);
ffiCleanup();
CHECK(rint == (int)uc);
}
}
puts("long double tests...");
{
float f= 3.14159;
long_double ld;
dprintf(("%"Lf"\n", ldblit(f)));
ld= 666;
ffiInitialize();
ffiPushSingleFloat(f);
GO(FFITypeDoubleFloat, ldblit);
ld= ffiReturnFloatValue();
ffiCleanup();
dprintf(("%"Lf", %"Lf", %"Lf", %"Lf"\n", ld, ldblit(f), ld - ldblit(f), (long_double)LDBL_EPSILON));
/* These are not always the same!! Check for a reasonable delta */
CHECK(ld - ldblit(f) < LDBL_EPSILON);
}
puts("float arg tests...");
{
int si1= 6;
float f= 3.14159;
double d= (double)1.0/(double)3.0;
long_double ld= 2.71828182846L;
int si2= 10;
int rint;
floating(si1, f, d, ld, si2);
ffiInitialize();
ffiPushSignedInt(si1);
ffiPushSingleFloat(f);
ffiPushDoubleFloat(d);
ffiPushDoubleFloat(ld);
ffiPushSignedInt(si2);
rint= GO(FFITypeSignedInt, floating);
ffiCleanup();
dprintf(("%d vs %d\n", (int)rint, floating(si1, f, d, ld, si2)));
CHECK(rint == floating(si1, f, d, ld, si2));
}
puts("double return tests...");
{
float f= 3.14159;
double d;
ffiInitialize();
ffiPushSingleFloat(f);
GO(FFITypeDoubleFloat, dblit);
d= ffiReturnFloatValue();
ffiCleanup();
CHECK(d - dblit(f) < DBL_EPSILON);
}
puts("strlen tests...");
{
char *s= "a";
int rint;
ffiInitialize();
ffiPushPointer((int)s);
rint= GO(FFITypeSignedInt, my_strlen);
ffiCleanup();
CHECK(rint == 1);
s= "1234567";
ffiInitialize();
ffiPushPointer((int)s);
rint= GO(FFITypeSignedInt, my_strlen);
ffiCleanup();
CHECK(rint == 7);
s= "1234567890123456789012345";
ffiInitialize();
ffiPushPointer((int)s);
rint= GO(FFITypeSignedInt, my_strlen);
ffiCleanup();
CHECK(rint == 25);
}
puts("many arg tests...");
{
unsigned long ul;
float f, ff;
float fa[15];
for (ul= 0; ul < 15; ++ul)
fa[ul]= (float)ul;
ff= many(fa[0], fa[1], fa[2], fa[3], fa[4], fa[5], fa[6], fa[7], fa[8], fa[9], fa[10], fa[11], fa[12], fa[13], fa[14]);
ffiInitialize();
for (ul= 0; ul < 15; ++ul)
ffiPushSingleFloat(fa[ul]);
GO(FFITypeSingleFloat, many);
f= ffiReturnFloatValue();
ffiCleanup();
CHECK(f - ff < FLT_EPSILON);
}
puts("promotion tests...");
{
signed char sc;
unsigned char uc;
signed short ss;
unsigned short us;
int rint;
for (sc= (signed char)-127; sc <= (signed char)120; sc += 1)
for (ss= -30000; ss <= 30000; ss += 10000)
for (uc= (unsigned char)0; uc <= (unsigned char)200; uc += 20)
for (us= 0; us <= 60000; us += 10000)
{
ffiInitialize();
ffiPushSignedChar(sc);
ffiPushSignedShort(ss);
ffiPushUnsignedChar(uc);
ffiPushUnsignedShort(us);
rint= GO(FFITypeSignedInt, promotion);
ffiCleanup();
CHECK((int)rint == (signed char)sc + (signed short)ss
+ (unsigned char)uc + (unsigned short)us);
}
}
puts("struct tests...");
{
test_structure_1 ts1_arg, ts1_result;
ts1_arg.uc= '\x01';
ts1_arg.d= 3.14159;
ts1_arg.ui= 555;
ffiInitialize();
CHECK(ffiCanReturn(SPEC(structure_1)));
ffiPushStructureOfLength((int)&ts1_arg, SPEC(structure_1));
GOS(structure_1, struct1);
ffiStoreStructure((int)&ts1_result, sizeof(ts1_result));
ffiCleanup();
dprintf(("%d %g\n", ts1_result.ui, ts1_result.d));
CHECK(ts1_result.ui == 556);
CHECK(ts1_result.d == 3.14159 - 1);
}
{
test_structure_2 ts2_arg, ts2_result;
ts2_arg.d1= 5.55;
ts2_arg.d2= 6.66;
dprintf(("%g\n", ts2_result.d1)); /*xxx this is junk!*/
dprintf(("%g\n", ts2_result.d2));
ffiInitialize();
CHECK(ffiCanReturn(SPEC(structure_2)));
ffiPushStructureOfLength((int)&ts2_arg, SPEC(structure_2));
GOS(structure_2, struct2);
ffiStoreStructure((int)&ts2_result, sizeof(ts2_result));
ffiCleanup();
dprintf(("%g\n", ts2_result.d1));
dprintf(("%g\n", ts2_result.d2));
CHECK(ts2_result.d1 == 5.55 - 1);
CHECK(ts2_result.d2 == 6.66 - 1);
}
{
int compare_value;
test_structure_3 ts3_arg, ts3_result;
ts3_arg.si= -123;
compare_value= ts3_arg.si;
ffiInitialize();
CHECK(ffiCanReturn(SPEC(structure_3)));
ffiPushStructureOfLength((int)&ts3_arg, SPEC(structure_3));
GOS(structure_3, struct3);
ffiStoreStructure((int)&ts3_result, sizeof(ts3_result));
ffiCleanup();
dprintf(("%d %d\n", ts3_result.si, -(compare_value*2)));
CHECK(ts3_result.si == -(ts3_arg.si*2));
}
{
test_structure_4 ts4_arg, ts4_result;
ts4_arg.ui1= 2;
ts4_arg.ui2= 3;
ts4_arg.ui3= 4;
ffiInitialize();
CHECK(ffiCanReturn(SPEC(structure_4)));
ffiPushStructureOfLength((int)&ts4_arg, SPEC(structure_4));
GOS(structure_4, struct4);
ffiStoreStructure((int)&ts4_result, sizeof(ts4_result));
ffiCleanup();
CHECK(ts4_result.ui3 == 2U * 3U * 4U);
}
{
test_structure_5 ts5_arg1, ts5_arg2, ts5_result;
ts5_arg1.c1= 2;
ts5_arg1.c2= 6;
ts5_arg2.c1= 5;
ts5_arg2.c2= 3;
struct5(ts5_arg1, ts5_arg2);
ts5_arg1.c1= 2;
ts5_arg1.c2= 6;
ts5_arg2.c1= 5;
ts5_arg2.c2= 3;
ffiInitialize();
CHECK(ffiCanReturn(SPEC(structure_5)));
ffiPushStructureOfLength((int)&ts5_arg1, SPEC(structure_5));
ffiPushStructureOfLength((int)&ts5_arg2, SPEC(structure_5));
GOS(structure_5, struct5);
ffiStoreStructure((int)&ts5_result, sizeof(ts5_result));
ffiCleanup();
dprintf(("%d %d\n", ts5_result.c1, ts5_result.c2));
CHECK(ts5_result.c1 == 7 && ts5_result.c2 == 3);
}
{
test_structure_6 ts6_arg, ts6_result;
ts6_arg.f= 5.55f;
ts6_arg.d= 6.66;
dprintf(("%g\n", ts6_arg.f));
dprintf(("%g\n", ts6_arg.d));
ffiInitialize();
CHECK(ffiCanReturn(SPEC(structure_6)));
ffiPushStructureOfLength((int)&ts6_arg, SPEC(structure_6));
GOS(structure_6, struct6);
ffiStoreStructure((int)&ts6_result, sizeof(ts6_result));
ffiCleanup();
dprintf(("%g\n", ts6_result.f));
dprintf(("%g\n", ts6_result.d));
CHECK(ts6_result.f == 5.55f + 1);
CHECK(ts6_result.d == 6.66 + 1);
}
{
test_structure_7 ts7_arg, ts7_result;
ts7_arg.f1= 5.55f;
ts7_arg.f2= 55.5f;
ts7_arg.d= 6.66;
dprintf(("%g\n", ts7_arg.f1));
dprintf(("%g\n", ts7_arg.f2));
dprintf(("%g\n", ts7_arg.d));
ffiInitialize();
CHECK(ffiCanReturn(SPEC(structure_7)));
ffiPushStructureOfLength((int)&ts7_arg, SPEC(structure_7));
GOS(structure_7, struct7);
ffiStoreStructure((int)&ts7_result, sizeof(ts7_result));
ffiCleanup();
dprintf(("%g\n", ts7_result.f1));
dprintf(("%g\n", ts7_result.f2));
dprintf(("%g\n", ts7_result.d));
CHECK(ts7_result.f1 == 5.55f + 1);
CHECK(ts7_result.f2 == 55.5f + 1);
CHECK(ts7_result.d == 6.66 + 1);
}
{
test_structure_8 ts8_arg, ts8_result;
ts8_arg.f1= 5.55f;
ts8_arg.f2= 55.5f;
ts8_arg.f3= -5.55f;
ts8_arg.f4= -55.5f;
dprintf(("%g\n", ts8_arg.f1));
dprintf(("%g\n", ts8_arg.f2));
dprintf(("%g\n", ts8_arg.f3));
dprintf(("%g\n", ts8_arg.f4));
ffiInitialize();
CHECK(ffiCanReturn(SPEC(structure_8)));
ffiPushStructureOfLength((int)&ts8_arg, SPEC(structure_8));
GOS(structure_8, struct8);
ffiStoreStructure((int)&ts8_result, sizeof(ts8_result));
ffiCleanup();
dprintf(("%g\n", ts8_result.f1));
dprintf(("%g\n", ts8_result.f2));
dprintf(("%g\n", ts8_result.f3));
dprintf(("%g\n", ts8_result.f4));
CHECK(ts8_result.f1 == 5.55f + 1);
CHECK(ts8_result.f2 == 55.5f + 1);
CHECK(ts8_result.f3 == -5.55f + 1);
CHECK(ts8_result.f4 == -55.5f + 1);
}
{
test_structure_9 ts9_arg, ts9_result;
ts9_arg.f= 5.55f;
ts9_arg.i= 5;
dprintf(("%g\n", ts9_arg.f));
dprintf(("%d\n", ts9_arg.i));
ffiInitialize();
CHECK(ffiCanReturn(SPEC(structure_9)));
ffiPushStructureOfLength((int)&ts9_arg, SPEC(structure_9));
GOS(structure_9, struct9);
ffiStoreStructure((int)&ts9_result, sizeof(ts9_result));
ffiCleanup();
dprintf(("%g\n", ts9_result.f));
dprintf(("%d\n", ts9_result.i));
CHECK(ts9_result.f == 5.55f + 1);
CHECK(ts9_result.i == 5 + 1);
}
}
#define C(C) ffiPushSignedChar(C)
#define S(S) ffiPushSignedShort(S)
#define I(I) ffiPushSignedInt(I)
#define F(F) ffiPushSingleFloat(F)
#define D(D) ffiPushDoubleFloat(D)
#define P(P) ffiPushPointer(P)
#define GO(T,F) ffiCallAddressOfWithReturnType((int)(F), FFICallTypeCDecl, \
(T) << FFIAtomicTypeShift)
static void assert(int pred, const char *gripe)
{
if (pred) return;
fprintf(stderr, "%s\n", gripe);
exit(1);
}
#include "ffi-test.h"
void stests(void)
{
double d;
char *s;
ffiInitialize(); C('A'); C(65); C(65); C(1);
GO(FFITypeSignedInt, ffiTestChars);
ffiCleanup();
ffiInitialize(); S('A'); S(65); S(65); S(1);
GO(FFITypeSignedInt, ffiTestShorts);
ffiCleanup();
ffiInitialize(); I('A'); I(65); I(65); I(1);
GO(FFITypeSignedInt, ffiTestInts);
ffiCleanup();
ffiInitialize(); F(65); F(65.0);
GO(FFITypeSingleFloat, ffiTestFloats);
d= ffiReturnFloatValue();
ffiCleanup();
dprintf(("%f\n", d));
assert(d == 130.0, "single floats don't work");
ffiInitialize(); D(41.0L); D(1);
GO(FFITypeDoubleFloat, ffiTestDoubles);
d= ffiReturnFloatValue();
ffiCleanup();
assert(d == 42.0, "problem with doubles");
/*xxx this does not really test strings, but the corresponding call
in the image's FFITester does */
ffiInitialize();
P((int)"Hello World!");
s= (char *)ffiCallAddressOfWithPointerReturn((int)ffiPrintString, FFICallTypeCDecl);
ffiCleanup();
assert(!strcmp(s, "Hello World!"), "Problem with strings");
{
int spec[]= { FFIFlagStructure | 8,
TYPE(SignedInt,4), TYPE(SignedInt,4) };
ffiTestPoint2 pt1= { 1, 2 }, pt2= { 3, 4 }, pt3;
ffiInitialize();
assert(ffiCanReturn((int *)&spec, 3), "cannot return struct");
ffiPushStructureOfLength((int)&pt1, (int *)&spec, 3);
ffiPushStructureOfLength((int)&pt2, (int *)&spec, 3);
ffiCallAddressOfWithStructReturn((int)ffiTestStruct64, FFICallTypeCDecl, spec, 3);
ffiStoreStructure((int)&pt3, sizeof(pt3));
ffiCleanup();
assert((pt3.x == 4) && (pt3.y == 6), "Problem passing 64bit structures");
}
{
int spec[]= { FFIFlagStructure | 16,
TYPE(SignedInt,4), TYPE(SignedInt,4),
TYPE(SignedInt,4), TYPE(SignedInt,4) };
ffiTestPoint4 pt1= { 1, 2, 3, 4 }, pt2= { 5, 6, 7, 8 }, pt3= { 9, 10, 11, 12 };
ffiInitialize();
assert(ffiCanReturn((int *)&spec, 3), "cannot return struct");
ffiPushStructureOfLength((int)&pt1, (int *)&spec, 5);
ffiPushStructureOfLength((int)&pt2, (int *)&spec, 5);
ffiPushStructureOfLength((int)&pt3, (int *)&spec, 5);
ffiCallAddressOfWithStructReturn((int)ffiTestStructBig, FFICallTypeCDecl, spec, 5);
ffiStoreStructure((int)&pt3, sizeof(pt3));
ffiCleanup();
assert((pt3.x == 6) && (pt3.y == 8) && (pt3.z == 10) && (pt3.w == 12),
"Problem passing large structures");
}
{
ffiTestPoint4 pt1= { 1, 2, 3, 4 }, pt2= { 5, 6, 7, 8 }, *pt3;
ffiInitialize();
ffiPushPointer((int)&pt1);
ffiPushPointer((int)&pt2);
pt3= (ffiTestPoint4 *)
ffiCallAddressOfWithPointerReturn((int)ffiTestPointers, 0);
ffiCleanup();
assert((pt3->x == 6) && (pt3->y == 8) && (pt3->z == 10) && (pt3->w == 12),
"Problem passing pointers");
free((void *)pt3);
}
}
extern void ffiDoAssertions(void);
int main()
{
ffiDoAssertions(); printf("passed ffi assertions\n");
stests(); printf("passed FFITester support check\n");
ctests(); printf("passed C test suite\n");
return 0;
}
--- NEW FILE: ffi-test-sq.h ---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define EXPORT(T) T
--- NEW FILE: ffi-test.c ---
/* last edited: 2003-01-29 21:48:36 by piumarta on emilia.inria.fr
*/
#if !defined(NO_FFI_TEST)
#include <stdio.h>
#include <stdlib.h>
#if !defined(LONGLONG)
# define LONGLONG long long
#endif
#if 0
# define dprintf(ARGS) printf ARGS
#else
# define dprintf(ARGS)
#endif
#include "ffi-test.h"
char ffiTestChars(char c1, char c2, char c3, char c4)
{
dprintf(("4 characters came in as\nc1 = %c (%x)\nc2 = %c (%x)\nc3 = %c (%x)\nc4 = %c (%x)\n", c1, c1, c2, c2, c3, c3, c4, c4));
return 'C';
}
short ffiTestShorts(short c1, short c2, short c3, short c4)
{
dprintf(("4 shorts came in as\ns1 = %d (%x)\ns2 = %d (%x)\ns3 = %d (%x)\ns4 = %d (%x)\n", c1, c1, c2, c2, c3, c3, c4, c4));
return -42;
}
int ffiTestInts(int c1, int c2, int c3, int c4)
{
dprintf(("4 ints came in as\ni1 = %d (%x)\ni2 = %d (%x)\ni3 = %d (%x)\ni4 = %d (%x)\n", c1, c1, c2, c2, c3, c3, c4, c4));
return 42;
}
int ffiTestInts8(int c1, int c2, int c3, int c4, int c5, int c6, int c7, int c8)
{
dprintf(("4 ints came in as\ni1 = %d (%x)\ni2 = %d (%x)\ni3 = %d (%x)\ni4 = %d (%x)\ni5 = %d (%x)\ni6 = %d (%x)\ni7 = %d (%x)\ni8 = %d (%x)\n", c1, c1, c2, c2, c3, c3, c4, c4, c5, c5, c6, c6, c7, c7, c8, c8));
return 42;
}
int ffiTestInts9(int c1, int c2, int c3, int c4, int c5, int c6, int c7, int c8, int c9)
{
dprintf(("4 ints came in as\ni1 = %d (%x)\ni2 = %d (%x)\ni3 = %d (%x)\ni4 = %d (%x)\ni5 = %d (%x)\ni6 = %d (%x)\ni7 = %d (%x)\ni8 = %d (%x)\ni9 = %d (%x)\n", c1, c1, c2, c2, c3, c3, c4, c4, c5, c5, c6, c6, c7, c7, c8, c8, c9, c9));
return 42;
}
float ffiTestFloats(float f1, float f2)
{
dprintf(("The two floats are %f and %f\n", (double)f1, (double)f2));
return (float) (f1 + f2);
}
float ffiTestFloats7(float f1, float f2, float f3, float f4, float f5, float f6, float f7)
{
dprintf(("The 7 floats are %f %f %f %f %f %f %f\n", (double)f1, (double)f2, (double)f3, (double)f4, (double)f5, (double)f6, (double)f7));
return (float) (f1 + f2 + f3 + f4 + f5 + f6 + f7);
}
float ffiTestFloats13(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9, float f10, float f11, float f12, float f13)
{
dprintf(("The 13 floats are %f %f %f %f %f %f %f %f %f %f %f %f %f\n", (double)f1, (double)f2, (double)f3, (double)f4, (double)f5, (double)f6, (double)f7, (double)f8, (double)f9, (double)f10, (double)f11, (double)f12, (double)f13));
return (float) (f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + f13);
}
float ffiTestFloats15(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9, float f10, float f11, float f12, float f13, float f14, float f15)
{
dprintf(("The 15 floats are %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n", (double)f1, (double)f2, (double)f3, (double)f4, (double)f5, (double)f6, (double)f7, (double)f8, (double)f9, (double)f10, (double)f11, (double)f12, (double)f13, (double)f14, (double)f15));
return (float) (f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + f13 + f14 + f15);
}
double ffiTestDoubles(double d1, double d2)
{
dprintf(("The two doubles are %f and %f\n", d1, d2));
return d1+d2;
}
double ffiTestDoubles15(double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10, double f11, double f12, double f13, double f14, double f15)
{
dprintf(("The 15 doubles are %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n", f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15));
return (double) (f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + f13 + f14 + f15);
}
char *ffiPrintString(char *string)
{
dprintf(("%s\n", string));
return string;
}
ffiTestPoint2 ffiTestStruct64(ffiTestPoint2 pt1, ffiTestPoint2 pt2)
{
ffiTestPoint2 result;
dprintf(("pt1.x = %d\npt1.y = %d\npt2.x = %d\npt2.y = %d\n",
pt1.x, pt1.y, pt2.x, pt2.y));
result.x = pt1.x + pt2.x;
result.y = pt1.y + pt2.y;
return result;
}
ffiTestPoint4 ffiTestStructBig(ffiTestPoint4 pt1, ffiTestPoint4 pt2)
{
ffiTestPoint4 result;
dprintf(("pt1.x = %d\npt1.y = %d\npt1.z = %d\npt1.w = %d\n",
pt1.x, pt1.y, pt1.z, pt1.w));
dprintf(("pt2.x = %d\npt2.y = %d\npt2.z = %d\npt2.w = %d\n",
pt2.x, pt2.y, pt2.z, pt2.w));
result.x = pt1.x + pt2.x;
result.y = pt1.y + pt2.y;
result.z = pt1.z + pt2.z;
result.w = pt1.w + pt2.w;
return result;
}
ffiTestPoint4 *ffiTestPointers(ffiTestPoint4 *pt1, ffiTestPoint4 *pt2)
{
ffiTestPoint4 *result;
dprintf(("pt1.x = %d\npt1.y = %d\npt1.z = %d\npt1.w = %d\n",
pt1->x, pt1->y, pt1->z, pt1->w));
dprintf(("pt2.x = %d\npt2.y = %d\npt2.z = %d\npt2.w = %d\n",
pt2->x, pt2->y, pt2->z, pt2->w));
result = (ffiTestPoint4*) malloc(sizeof(ffiTestPoint4));
result->x = pt1->x + pt2->x;
result->y = pt1->y + pt2->y;
result->z = pt1->z + pt2->z;
result->w = pt1->w + pt2->w;
return result;
}
LONGLONG ffiTestLongLong(LONGLONG i1, LONGLONG i2)
{
dprintf(("longlong %lld %lld\n", i1, i2));
return i1 + i2;
}
#endif /* !NO_FFI_TEST */
--- NEW FILE: ffi-test.h ---
typedef struct ffiTestPoint2
{
int x;
int y;
} ffiTestPoint2;
typedef struct ffiTestPoint4
{
int x;
int y;
int z;
int w;
} ffiTestPoint4;
extern char ffiTestChars(char c1, char c2, char c3, char c4);
extern short ffiTestShorts(short c1, short c2, short c3, short c4);
extern int ffiTestInts(int c1, int c2, int c3, int c4);
extern int ffiTestInts8(int c1, int c2, int c3, int c4, int c5, int c6, int c7, int c8);
extern int ffiTestInts9(int c1, int c2, int c3, int c4, int c5, int c6, int c7, int c8, int c9);
extern float ffiTestFloats(float f1, float f2);
extern float ffiTestFloats7(float f1, float f2, float f3, float f4, float f5, float f6, float f7);
extern float ffiTestFloats13(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9, float f10, float f11, float f12, float f13);
extern float ffiTestFloats15(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9, float f10, float f11, float f12, float f13, float f14, float f15);
extern double ffiTestDoubles(double d1, double d2);
extern double ffiTestDoubles15(double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10, double f11, double f12, double f13, double f14, double f15);
extern char *ffiPrintString(char *string);
extern ffiTestPoint2 ffiTestStruct64(ffiTestPoint2 pt1, ffiTestPoint2 pt2);
extern ffiTestPoint4 ffiTestStructBig(ffiTestPoint4 pt1, ffiTestPoint4 pt2);
extern ffiTestPoint4 *ffiTestPointers(ffiTestPoint4 *pt1, ffiTestPoint4 *pt2);
extern long long ffiTestLongLong(long long i1, long long i2);
--- NEW FILE: ppc-darwin-asm.S ---
/* ppc-sysv-asm.S -- PowerPC FFI trampoline for SVr4-like ABIs -*- asm -*-
*
* Author: Ian...@IN...
*
* Last edited: 2003-01-28 22:43:45 by piumarta on calvin.local.
*
* Copyright (C) 1996-2002 Ian Piumarta and other authors/contributors
* as listed elsewhere in this file.
* All rights reserved.
*
* This file is part of Unix Squeak.
*
* This file is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You may use and/or distribute this file ONLY as part of Squeak, under
* the terms of the Squeak License as described in `LICENSE' in the base of
* this distribution, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment to the original author(s) (and any
* other contributors mentioned herein) in the product documentation
* would be appreciated but is not required.
*
* 2. This notice must not be removed or altered in any source distribution.
*
* Using (or modifying this file for use) in any context other than Squeak
* changes these copyright conditions. Read the file `COPYING' in the
* directory `platforms/unix/doc' before proceeding with any such use.
*
* You are not allowed to distribute a modified version of this file
* under its original name without explicit permission to do so. If
* you change it, rename it.
*/
/* Mach-O PPC stack frames look like this (higher addresses first):
*
* | caller's lr |
* | caller's cr |
* caller's sp->| caller's caller's sp |
* | fpr save area |
* | gpr save area |
* | [alignment pad] |
* | local variables |
* sp + 24 -> | param save area |
* sp + 20 -> | caller's toc |
* sp + 16 -> | reserved |
* sp + 12 -> | reserved |
* sp + 8 -> | (callee-save) lr |
* sp + 4 -> | (callee-save) cr |
* sp + 0 -> | caller's sp |
*/
#define GPR_MAX 8
#define FPR_MAX 13
#define ARG_MAX 512
#include "ppc-global.h"
#define sp r1
.text
.globl _ffiCallAddressOf
_ffiCallAddressOf:
stwu sp, -32(sp) // push trampoline frame
mflr r0
stw r0, 40(sp)
mfcr r0
stw r0, 36(sp) // saved ccr
mtlr r3 // destination fn address
stw r4, 28(sp) // globals
lwz r5, stackIndex(r4)
slwi r10, r5, 2 // param save area size
addi r10, r10, 32+15 // round to quad word
rlwinm r10, r10, 0,0,27
neg r10, r10
stwux sp, sp, r10 // push ffi caller frame
cmpwi r5, 0 // have params?
beq+ 2f
mtctr r5 // words to move
la r10, (stack-4)(r4) // ffi param stack - 4
addi r11, sp, 24-4 // param save area - 4
1: lwzu r0, 4(r10) // copy param save area
stwu r0, 4(r11)
bdnz 1b
2: lwz r5, fprCount(r4)
cmpwi r5, 0
beq+ 4f // no fp args
la r11, fprs(r4)
cmpwi r5, 4
ble+ 3f
lfd f5, 32(r11)
lfd f6, 40(r11)
lfd f7, 48(r11)
lfd f8, 56(r11)
# if (FPR_MAX > 8)
lfd f9, 64(r11)
lfd f10, 72(r11)
lfd f11, 80(r11)
lfd f12, 88(r11)
lfd f13, 96(r11)
# endif
3: lfd f1, 0(r11)
lfd f2, 8(r11)
lfd f3, 16(r11)
lfd f4, 24(r11)
4: lwz r5, gprCount(r4)
cmpwi r5, 0
beq- 6f // no int args
la r11, gprs(r4)
cmpwi r5, 4
ble+ 5f
lwz r7, 16(r11)
lwz r8, 20(r11)
lwz r9, 24(r11)
lwz r10, 28(r11)
5: lwz r3, 0(r11)
lwz r4, 4(r11)
lwz r5, 8(r11)
lwz r6, 12(r11)
6: blrl // callout
lwz sp, 0(sp) // pop ffi caller frame
lwz r5, 28(sp) // globals
stw r3, longReturnValue+0(r5)
stw r4, longReturnValue+4(r5)
stfd f1, floatReturnValue(r5)
lwz r0, 40(sp)
mtlr r0
lwz r0, 36(sp) // saved ccr
mtcr r0
addi sp, sp, 32 // pop trampoline frame
blr
--- NEW FILE: ppc-darwin.c ---
/* ppc-darwin.c -- FFI support for PowerPC on Mach-O (Darwin)
*
* Author: Ian...@IN...
*
* Last edited: 2003-01-29 00:02:29 by piumarta on calvin.local.
*
* Copyright (C) 1996-2002 Ian Piumarta and other authors/contributors
* as listed elsewhere in this file.
* All rights reserved.
*
* This file is part of Unix Squeak.
*
* This file is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You may use and/or distribute this file ONLY as part of Squeak, under
* the terms of the Squeak License as described in `LICENSE' in the base of
* this distribution, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment to the original author(s) (and any
* other contributors mentioned herein) in the product documentation
* would be appreciated but is not required.
*
* 2. This notice must not be removed or altered in any source distribution.
*
* Using (or modifying this file for use) in any context other than Squeak
* changes these copyright conditions. Read the file `COPYING' in the
* directory `platforms/unix/doc' before proceeding with any such use.
*
* You are not allowed to distribute a modified version of this file
* under its original name without explicit permission to do so. If
* you change it, rename it.
*
* Notes:
*
* This is a complete rewrite of the version for MacPPC. (The latter
* is hopelessly broken when passing long longs or structs containing
* an element of alignment less strict than int.)
*
* Bugs:
*
* Because of the way strings are handled, this implementation is
* neither reentrant nor thread safe.
*
* References:
*
* Mach-O Runtime Architecture, Apple Computer Inc., July 2002.
*/
#include "sq.h"
#include "sqFFI.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef LONGLONG
# define LONGLONG long long
#endif
#if 0
# define dprintf(ARGS) printf ARGS
#else
# define dprintf(ARGS)
#endif
extern struct VirtualMachine *interpreterProxy;
#if defined(FFI_TEST)
static int primitiveFail(void) { puts("primitive fail"); exit(1); return 0; }
#else
# define primitiveFail() interpreterProxy->primitiveFail();
#endif
#define GPR_MAX 8
#define FPR_MAX 13
#define ARG_MAX 512
static char *strings[ARG_MAX];
static int stringCount= 0;
#if 0
static char structs[ARG_MAX * sizeof(int)];
static int structCount= 0;
#endif
/* the following avoids an awful lot of _very_ inefficient junk in the asm */
static struct
{
int _gprCount; // 0
int _fprCount; // 4
int _stackIndex; // 8
int *_structReturnValue; // 12 (everything below is 8-byte aligned)
LONGLONG _longReturnValue; // 16
double _floatReturnValue; // 24
int _gprs[GPR_MAX]; // 32
double _fprs[FPR_MAX]; // 32 + 4*GPR_MAX
int _stack[ARG_MAX]; // 32 + 4*GPR_MAX + 8*FPR_MAX
} global;
#define gprCount global._gprCount
#define fprCount global._fprCount
#define stackIndex global._stackIndex
#define structReturnValue global._structReturnValue
#define longReturnValue global._longReturnValue
#define floatReturnValue global._floatReturnValue
#define gprs global._gprs
#define fprs global._fprs
#define stack global._stack
extern int ffiCallAddressOf(void *addr, void *globals);
int ffiInitialize(void)
{
stackIndex= gprCount= fprCount= 0;
#if 0
structCount= 0;
#endif
floatReturnValue= 0.0;
return 1;
}
int ffiSupportsCallingConvention(int callType)
{
return (callType == FFICallTypeCDecl)
|| (callType == FFICallTypeApi);
}
int ffiAlloc(int byteSize)
{
return (int)malloc(byteSize);
}
int ffiFree(int ptr)
{
if (ptr) free((void *)ptr);
return 1;
}
#define checkStack() \
if (stackIndex >= ARG_MAX) \
return primitiveFail()
#define checkGPR() \
if ((gprCount >= GPR_MAX) && (stackIndex >= ARG_MAX)) \
return primitiveFail()
#define qalignStack() stackIndex += (stackIndex & 1)
#define pushGPR(value) \
checkGPR(); \
if (gprCount < GPR_MAX) \
gprs[gprCount++]= value; \
stack[stackIndex++]= value
#define qalignGPR() gprCount += (gprCount & 1)
int ffiPushSignedChar(int value)
{
dprintf(("ffiPushSignedChar %d\n", value));
pushGPR(value);
return 1;
}
int ffiPushUnsignedChar(int value)
{
dprintf(("ffiPushUnsignedChar %d\n", value));
pushGPR(value);
return 1;
}
int ffiPushSignedByte(int value)
{
dprintf(("ffiPushSignedByte %d\n", value));
pushGPR(value);
return 1;
}
int ffiPushUnsignedByte(int value)
{
dprintf(("ffiPushUnsignedByte %d\n", value));
pushGPR(value);
return 1;
}
int ffiPushSignedShort(int value)
{
dprintf(("ffiPushSignedShort %d\n", value));
pushGPR(value);
return 1;
}
int ffiPushUnsignedShort(int value)
{
dprintf(("ffiPushUnsignedShort %d\n", value));
pushGPR(value);
return 1;
}
int ffiPushSignedInt(int value)
{
dprintf(("ffiPushSignedInt %d\n", value));
pushGPR(value);
return 1;
}
int ffiPushUnsignedInt(int value)
{
dprintf(("ffiPushUnsignedInt %d\n", value));
pushGPR(value);
return 1;
}
int ffiPushSignedLongLong(int low, int high)
{
dprintf(("ffiPushSignedLongLong %d %d\n", low, high));
qalignGPR();
qalignStack();
pushGPR(high);
pushGPR(low);
return 1;
}
int ffiPushUnsignedLongLong(int low, int high)
{
dprintf(("ffiPushUnsignedLongLong %d %d\n", low, high));
qalignGPR();
qalignStack();
pushGPR(high);
pushGPR(low);
return 1;
}
int ffiPushPointer(int pointer)
{
dprintf(("ffiPushPointer %d\n", pointer));
pushGPR(pointer);
return 1;
}
int ffiPushSingleFloat(double value)
{
dprintf(("ffiPushSingleFloat %f\n", (float)value));
if (fprCount < FPR_MAX)
fprs[fprCount++]= value;
{
float floatValue= (float)value;
pushGPR(*(int *)&floatValue);
}
return 1;
}
int ffiPushDoubleFloat(double value)
{
dprintf(("ffiPushDoubleFloat %f\n", (float)value));
if (fprCount < FPR_MAX)
fprs[fprCount++]= value;
pushGPR(((int *)&value)[0]);
pushGPR(((int *)&value)[1]);
return 1;
}
int ffiPushStringOfLength(int srcIndex, int length)
{
char *ptr;
dprintf(("ffiPushStringOfLength %d\n", length));
checkGPR();
ptr= (char *)malloc(length + 1);
if (!ptr)
return primitiveFail();
memcpy(ptr, (void *)srcIndex, length);
ptr[length]= '\0';
strings[stringCount++]= ptr;
pushGPR((int)ptr);
return 1;
}
static inline int min(int x, int y) { return (x < y) ? x : y; }
int ffiPushStructureOfLength(int pointer, int *structSpec, int specSize)
{
int i;
char *data = (char *)pointer;
char *argp = (char *)&stack[stackIndex];
#define argl (char *)&stack[ARG_MAX]
int argSize = *structSpec & FFIStructSizeMask;
char *gprp = (char *)&gprs[gprCount];
#define gprl (char *)&gprs[GPR_MAX]
int gprSize = min(argSize, gprl - gprp);
if (gprSize < 4) gprp += (4 - gprSize);
if (argSize < 4) argp += (4 - gprSize);
if (argp + argSize > argl)
return primitiveFail();
memcpy((void *)gprp, (void *)data, gprSize);
memcpy((void *)argp, (void *)data, argSize);
gprCount += (gprSize + sizeof(int) - 1) / sizeof(int);
stackIndex += (argSize + sizeof(int) - 1) / sizeof(int);
#undef argl
#undef gprl
for (i= 0; i < specSize; ++i)
{
int typeSpec= structSpec[i];
if (typeSpec & FFIFlagPointer)
continue;
else if (typeSpec & FFIFlagStructure)
continue;
else
{
int atomicType= (typeSpec & FFIAtomicTypeMask) >> FFIAtomicTypeShift;
switch (atomicType)
{
case FFITypeSingleFloat:
if (fprCount < FPR_MAX)
fprs[fprCount++]= *(float *)data;
break;
case FFITypeDoubleFloat:
if (fprCount < FPR_MAX)
fprs[fprCount++]= *(double *)data;
break;
default:
break;
}
data += typeSpec & FFIStructSizeMask;
}
}
return 1;
}
int ffiCanReturn(int *structSpec, int specSize)
{
int header= *structSpec;
if (header & FFIFlagPointer)
return 1;
if (header & FFIFlagStructure)
{
/* structs are always returned as pointers to hidden structures */
int structSize= header & FFIStructSizeMask;
structReturnValue= malloc(structSize);
if (!structReturnValue)
return 0;
pushGPR((int)structReturnValue);
}
return 1;
}
double ffiReturnFloatValue(void) { return floatReturnValue; }
int ffiLongLongResultLow(void) { return ((int *)&longReturnValue)[1]; }
int ffiLongLongResultHigh(void) { return ((int *)&longReturnValue)[0]; }
int ffiStoreStructure(int address, int structSize)
{
memcpy((void *)address,
structReturnValue ? (void *)structReturnValue : (void *)&longReturnValue,
structSize);
return 1;
}
int ffiCleanup(void)
{
int i;
for (i= 0; i < stringCount; ++i)
free(strings[i]);
stringCount= 0;
if (structReturnValue)
{
free(structReturnValue);
structReturnValue= 0;
}
return 1;
}
int ffiCallAddress...
[truncated message content] |