On Fri, Nov 20, 2009 at 3:26 AM, Gary Dunn <osp@aloha.com> wrote:

I can report progress but no solution.

1. Since ffi-test-main failed to build with a simple "make" I had
assumed I needed to use libffi. I added a print statement to show the
values at the point of failure at line 361, the CHECK statement:

   ffiInitialize();
   for (ul= 0;  ul < 15;  ++ul)
     ffiPushSingleFloat(fa[ul]);
   GO(FFITypeSingleFloat, many);
   f= ffiReturnFloatValue();
   ffiCleanup();
   printf("%g %g %g %g\n", f, ff, f - ff, FLT_EPSILON);
   CHECK(f - ff < FLT_EPSILON);

It gave f and ff to be identical, f - ff zero, and FLT_EPSILON a very
small value. The strange thing was that the test did not fail. I
commented out my print statement and it failed. Weird.

I noticed I was not seeing the output from puts statements. Recalling
that this is typically a macro I looked to see if it had been defined,
and found this near the top of the file:

#if 0
# define dprintf(ARGS)  printf ARGS
# define puts(ARG)      puts(ARG)
#else
# define dprintf(ARGS)
# define puts(ARG)
#endif

I changed the zero to one and the output was verbose. No failure, even
with my print statement commented out.

I suspect there is some tricky coding here that works on some versions
of C and not others. The preprocessor, especially.

So I got to wondering why make without args failed. I traced the problem
to these lines from the Makefile

CPU=    $(shell ./ffi-config -cpu)
ABI=    $(shell ./ffi-config -abi)
LIB=    $(shell ./ffi-config -lib)

Running them manually gave x86, sysv and blank, but

OBJ=    ffi-test-main.o ffi-test.o $(CPU)-$(ABI).o $(CPU)-$(ABI)-asm.o

resolved to ffi-test-main.o ffi-test.o -.o --asm.o

which caused make to complain that it did not know how to make -.o.

I substituted like this

#OBJ=    ffi-test-main.o ffi-test.o $(CPU)-$(ABI).o $(CPU)-$(ABI)-asm.o
OBJ=   ffi-test-main.o ffi-test.o x86-sysv.o x86-sysv-asm.o

and the build completed.

Eventually I figured out that the shell construct works in gnu make.
FreeBSD does not use gnu make. It is available as gmake. I put back the
Makefile and used gmake and got a good build.

The results are inconclusive. The output is

slate01# ./main
passed ffi assertions (0 failed)
Problem passing 64bit structures

Is that because I am not using a 64bit CPU? Is that a show stopper?
Apparently not.

The thing is, this does not fix the real problem. If I load my 3.9 image
and install the FFI package from SqueakMap, then run the FFI-Tests in
SUnit runner I get 21 run, 0 passes, 0 expected failures, 0 failures, 21
errors, 0 unexpected passes. When I click on a result and open a
debugger I find

Error: Unable to find function address

invokeWithArguments: argArray
       "Manually invoke the receiver, representing an external function."
       <primitive: 'primitiveCalloutWithArgs' module:'SqueakFFIPrims'>
       ^self externalCallFailed



externalCallFailed
       "Raise an error after a failed call to an external function"
       | errCode |
       errCode := ExternalFunction getLastError. "this allows us to look at
the actual error code"
       ^self error: (ExternalFunction errorMessageFor: errCode).



error: aString
       "Throw a generic Error exception."

       ^Error new signal: aString


If the  ffi-test-main.c tests are passing, why are the SUnit tests all
failing? Is that 64bit thing a big deal?

twice as big a deal as 32-bits...  But seriously folks...

Have you built a SqueakFFIPrims shared object?  Have you installed it in the right directory with other plugins?  Is the export table in SqueakFFIPrims.c correct (calls itself SqueakFFIPrims, includes both primitiveCallout and primitiveCalloutWithArgs as exports).

First try and understand 



invokeWithArguments: argArray
       "Manually invoke the receiver, representing an external function."
       <primitive: 'primitiveCalloutWithArgs' module:'SqueakFFIPrims'>
       ^self externalCallFailed

and Error: Unable to find function address.

The first is a method that includes a spec for calling a plugin primitive, in the SqueakFFIPrims plugin, which could be in a shared object, a dll or a bundle depending on platform.  You're on linux so it should be in either SqueakFFIPrims or SqueakFFIPrims.so depending on which version of the VM you're working on.

The second tells you that, probably the VM is finding the SqueakFFIPrims module but its not finding primitiveCalloutWithArgs within it.  You can check by tracing execution through ioLoadExternalFunctionOfLengthFromModuleOfLength.  Assuming the module is being found you need to find out why the function isn't being found.

At the end of SqueakFFIPrims.c you should see a table that looks something like

#ifdef SQUEAK_BUILTIN_PLUGIN

void* SqueakFFIPrims_exports[][3] = {
    {"SqueakFFIPrims", "ffiLogCallsTo", (void*)ffiLogCallsTo},
    {"SqueakFFIPrims", "getModuleName", (void*)getModuleName},
    {"SqueakFFIPrims", "initialiseModule", (void*)initialiseModule},
    {"SqueakFFIPrims", "primitiveCallout", (void*)primitiveCallout},
    {"SqueakFFIPrims", "primitiveCalloutWithArgs", (void*)primitiveCalloutWithArgs},
    {"SqueakFFIPrims", "primitiveFFIAllocate", (void*)primitiveFFIAllocate},
    {"SqueakFFIPrims", "primitiveFFIDoubleAt", (void*)primitiveFFIDoubleAt},
    {"SqueakFFIPrims", "primitiveFFIDoubleAtPut", (void*)primitiveFFIDoubleAtPut},
    {"SqueakFFIPrims", "primitiveFFIFloatAt", (void*)primitiveFFIFloatAt},
    {"SqueakFFIPrims", "primitiveFFIFloatAtPut", (void*)primitiveFFIFloatAtPut},
    {"SqueakFFIPrims", "primitiveFFIFree", (void*)primitiveFFIFree},
    {"SqueakFFIPrims", "primitiveFFIGetLastError", (void*)primitiveFFIGetLastError},
    {"SqueakFFIPrims", "primitiveFFIIntegerAt", (void*)primitiveFFIIntegerAt},
    {"SqueakFFIPrims", "primitiveFFIIntegerAtPut", (void*)primitiveFFIIntegerAtPut},
    {"SqueakFFIPrims", "primitiveForceLoad", (void*)primitiveForceLoad},
    {"SqueakFFIPrims", "primitiveLogCallsTo", (void*)primitiveLogCallsTo},
    {"SqueakFFIPrims", "setInterpreter", (void*)setInterpreter},
    {NULL, NULL, NULL}
};

#endif /* ifdef SQ_BUILTIN_PLUGIN */

If primitiveCalloutWithArgs is missing then SqueakFFIPrims.c didn't get generated correctly.  Go back to VMMaker and the FFIPlugin source and try to figure out why.  Note that the table shouldn't be being used because the plugin is typically used as an external plugin.  If you're building it in then ignore what follows and reply saying "I want an internal plugin dammit!!"

If primitiveCalloutWithArgs isn't missing then is it being exported form the module?  Use nm on whatever SqueakFFIPrims is compiled to and make sure its exported.  It should have something like the following:

$ nm Fast.app/Contents/Resources/SqueakFFIPrims.bundle/Contents/MacOS/SqueakFFIPrims | grep primitiveC
00004200 T _primitiveCallout
00003750 T _primitiveCalloutWithArgs

If there's a lowercase t there' figure out why it isn't being exported.  e.g. EXPORT macro definition, linker commands, etc...

If it is being exported then you need to start debugging ioLoadSymbolOfLengthFromModule, because that's failing to extract the address of primitiveCalloutWithArgs from the loaded module.

HTH
Eliot



--
Gary Dunn, Honolulu
osp@aloha.com
http://openslate.net/
http://e9erust.blogspot.com/
Sent from Slate001