As mentioned on the list yesterday I started evaluating ffcall as a way
of providing NCI functionality.
http://www.haible.de/bruno/packages-ffcall.html
I actually really like the current NCI implementation, although it
suffers from a large nci.c file and all the usable prototypes need to be
specified at compile time in call_list.txt. Over time as more libraries
become supported this list will quickly grow.
My main reason for visiting this is that I couldn't write the simple NCI
example that I had in mind because callbacks are too restrictive, and
unlikely to be fixable.
I've now got a working POC for function calls, and although callbacks
don't work yet, they're not far off. All but 11 of the 59 NCI tests
pass, and those that don't work exercise callbacks or reading back
values from types for which I haven't done yet.
For those that want to try it, you'll of course need ffcall installed
and rerun Configure. Being a Proof of Concept, I've hacked the '-l's for
the libraries into the Makefile in the wrong place which means some of
the other tests fail. For now, just try:
perl -Ilib t/pmc/nci.t
To recap the (mostly obvious) Pros & Cons.
Pros:
* Makes any prototype possible, not just those in call_list.txt
* Probably won't initially make code much smaller, but would over time
(stripped nci_ffcall.o & library is currently < 1/6 size of nci.o)
* Callbacks can have any prototype as well, not just a data/user data pair
* Callbacks no longer require user data to be managed by the 3rd party
library (this is a biggy)
* Callbacks will be able to support a return type
Cons:
* Reliance on a library, although NCI may be an optional feature
* Performance? There are a few additional loops and switches, but I
can't see this being a real issue
* NCI would only be available on platforms which support the library
we use; from what I've seen dynamic function calls is not easy to do
cross-platform
* Possibly incompatible 3rd party licensing
To address some of the points in the Cons section, it would be possible
to maintain multiple NCI backends, although more work.
As far as PIR/PASM code, the interface is unchanged, although I would
like to suggest that at some point the newclass signature include the
return type in common with other opcodes, as hopefully we can support this.
Cheers,
Nick
p.s. As you can see, I've been won over by ffcall, but I've only been
using it for a day so there may well be show stoppers to using it.
> Guys,
>
> As mentioned on the list yesterday I started evaluating ffcall as a
> way of providing NCI functionality.
>
> http://www.haible.de/bruno/packages-ffcall.html
I've downloaded it and had a short look into sources. The list of
supported platforms is quite impressive. OTOH it looks a bit under
documented to me.
> I've now got a working POC for function calls, and although callbacks
> don't work yet, they're not far off. All but 11 of the 59 NCI tests
> pass, and those that don't work exercise callbacks or reading back
> values from types for which I haven't done yet.
That's a lot for this early stage. Good work.
> Pros:
Makes ffcall very worthy to include.
> Cons:
>
> * Reliance on a library, although NCI may be an optional feature
A library per se isn't a problem. You mentioned licence issues
yesterday due to GPL. Keeping a fallback to NCI (with possibly reduced
functionality would be ok too probably).
> * Performance? There are a few additional loops and switches, but I
> can't see this being a real issue
Can be measured.
> * Possibly incompatible 3rd party licensing
Ah, yep - IANALL.
> As far as PIR/PASM code, the interface is unchanged, although I would
> like to suggest that at some point the newclass signature include the
> return type in common with other opcodes, as hopefully we can support
> this.
You are talking about new_callback ?
> Cheers,
>
> Nick
>
> p.s. As you can see, I've been won over by ffcall, but I've only been
> using it for a day so there may well be show stoppers to using it.
Great work for one day.
leo
> Guys,
>
> As mentioned on the list yesterday I started evaluating ffcall as a
> way of providing NCI functionality.
I seem to be seeing rather strange, and it's probably a misunderstanding
on my part.
I've pinched the GET_NCI_x(n) macros and accompanying get_nci_x
functions from nci.c, but they don't seem to be working consistently.
In particular, where I have a signature "pp" I often seem to be getting
the same pointer twice.
If the following line is added as line 267 in nci_ffcall.c after
applying the patch:
printf ("Pointer is %p\n", nci_args->args[i]._pointer);
and the following script run:
.sub test :main
.local pmc libnci_test
libnci_test = loadlib "libnci_test"
.local pmc nci_cb_C1
nci_cb_C1 = dlfunc libnci_test, "nci_cb_C1", "vpp"
.local pmc user_data
user_data = new .Integer
user_data = -99
.local pmc cb
cb = newsub _call_back
.local pmc cb_wrapped
cb_wrapped = new_callback cb, user_data, "iii"
nci_cb_C1 (user_data, cb_wrapped)
.end
.sub _call_back
print "Hello world!\n"
.end
then you get
Pointer is 0x84a33d0
Pointer is 0x84a33d0
[probably a segfault!]
while these are meant to be different addresses (corresponding to
user_data and cb_wrapped). From what I've seen you get the second
address twice.
I must be doing something wrong as it works in nci.c.
Any thoughts would be appreciated as I can't see the wood from the trees
anymore,
Cheers,
Nick
p.s. Since posting the patch, I've realised that I probably need another
Parrot_init_arg_nci(interpreter, &st, nci_args->signature_parrot);
before reading back the values, and probably a 'default' in the switch
which steps over skipped items. This only enables one extra test to
succeed though.
>
> On Oct 28, 2005, at 22:22, Nick Glencross wrote:
>
>> Guys,
>>
>> As mentioned on the list yesterday I started evaluating ffcall as a
>> way of providing NCI functionality.
>>
>> http://www.haible.de/bruno/packages-ffcall.html
>
>
> I've downloaded it and had a short look into sources. The list of
> supported platforms is quite impressive. OTOH it looks a bit under
> documented to me.
The page that I've linked to is a bit bland, but the manual pages for
the 4 routines are very thorough. It's being able to create the closures
which made this library stand out, as that would allow us to create
callbacks with any library. Still haven't looked under the hood to see
how on earth that's possible.
>
>> I've now got a working POC for function calls, and although callbacks
>> don't work yet, they're not far off. All but 11 of the 59 NCI tests
>> pass, and those that don't work exercise callbacks or reading back
>> values from types for which I haven't done yet.
>
>
> That's a lot for this early stage. Good work.
I was hoping to have shiny callbacks too, but something bad was
happening with the arguments being passed around, but I've got to the
bottom of that nasty.
>> As far as PIR/PASM code, the interface is unchanged, although I would
>> like to suggest that at some point the newclass signature include the
>> return type in common with other opcodes, as hopefully we can support
>> this.
>
>
> You are talking about new_callback ?
Yes, thought one thing, typed another,
Nick
> Nick Glencross wrote:
>
>> Guys,
>>
>> As mentioned on the list yesterday I started evaluating ffcall as a
>> way of providing NCI functionality.
>
>
> I seem to be seeing rather strange, and it's probably a
> misunderstanding on my part.
>
Ok, I see what the problem is. PMC_data(x) is a macro which can expand x
out twice and because GET_NCI_P has the side effect of advancing to the
next PMC, it starts by returning the second PMC.
That will hopefully fix the problems that I've been having with callbacks!
Nick
> Guys,
>
> As mentioned on the list yesterday I started evaluating ffcall as a
> way of providing NCI functionality.
Ok, here's an updated version with (hopefully) working callbacks -- at
least enough for a POC.
If you tried out my previous version, run 'rm */*ffcall*' before
applying this patch to avoid creating botched files.
I'll show an example of how you might use it...
I started by hacking nci_test.c to include:
typedef int (*cb_C1_func)(int, int, int);
void
nci_cb_C1(cb_C1_func cb, int a, int b, int c) {
int result = (cb)(a, b, c);
printf ("Result is %d\n", result);
}
This routine accepts a callback pointer and three arguments, and then
calls the callback with these arguments and prints the value received back.
The parrot harness might look like this:
.sub test :main
.local pmc libnci_test
libnci_test = loadlib "libnci_test"
.local pmc nci_cb_C1
nci_cb_C1 = dlfunc libnci_test, "nci_cb_C1", "ipiii"
.local pmc user_data
user_data = new .Integer
.local pmc cb
cb = newsub _call_back
.local pmc cb_wrapped
cb_wrapped = new_callback cb, user_data, "iiii"
nci_cb_C1 (cb_wrapped, 1,2,3)
print "Finish!\n"
.end
.sub _call_back
.param int a
.param int b
.param int c
print "Hello world!\n"
print a
print " "
print b
print " "
print c
print " "
print_newline
.return (b)
.end
The script looks similar to before, but certain limitations have been
lifted. A PMC must still be supplied to new_callback (although this
requirement could be lifted), but this does not need to be seen by the
callback (unless you want it to -- just pass it with a normal 'p'
signature) Moreover, the callback signature can be anything, and would
now include the return type which will be returned to C.
To clarify, 'ipiii' refers to the C nci_cb_C1 routine, and the 'iiii'
refers to the prototype for _call_back.
Running it gives
Hello world!
1 2 3
Result is 2
Finish!
'1 2 3' were passed from parrot into C and then back out into parrot to
be printed. parrot then returned the middle one which was printed back
in C-land.
Have fun!
Nick
I am a SWIG (www.swig.org) developer, and I recently started looking at
what it will take to add a parrot module to SWIG. I will post some of the
issues I ran into, but I was wondering if there would be any interest for
SWIG to become one of the official way to do NCI?
SWIG has a whole bunch of other benefits which I won't list here.
The main issue resolves around the problem that there isn't a standard way
to just register a function as callable from parrot (that I can see).
perl5 allowed XS() and then calling the newXS function. SWIG would prefer
to use the best representation/match to the internal interpreter...
SWIG can easily generate functions of the form
void* _wrap_foo(Interp* interpreter, PMC* pmc, void * next)
one for each function being wrapped. Can we inject that function directly
into the vtable somehow? Or just create a class that passes on the invoke
function?
One of the existing SWIG modules (CHICKEN) deals with a continuation
passing language, so SWIG can deal with continuation-aware languages.
> Pros:
>
> * Makes any prototype possible, not just those in call_list.txt
>
> * Probably won't initially make code much smaller, but would over time
> (stripped nci_ffcall.o & library is currently < 1/6 size of nci.o)
>
> * Callbacks can have any prototype as well, not just a data/user data
> pair
>
> * Callbacks no longer require user data to be managed by the 3rd party
> library (this is a biggy)
>
> * Callbacks will be able to support a return type
>
> Cons:
>
> * Reliance on a library, although NCI may be an optional feature
SWIG does not require any code besides what it generates... think lex or
yacc...
>
> * Performance? There are a few additional loops and switches, but I
> can't see this being a real issue
>
> * NCI would only be available on platforms which support the library
> we use; from what I've seen dynamic function calls is not easy to do
> cross-platform
SWIG works on pretty much every platform and every compiler...
>
> * Possibly incompatible 3rd party licensing
SWIG uses a BSD like license, so no problem at all... can even include
SWIG directly in the parrot code...
It is something to think about...
John
> On Fri, October 28, 2005 2:22 pm, Nick Glencross said:
>> Guys,
>>
>> As mentioned on the list yesterday I started evaluating ffcall as a
>> way
>> of providing NCI functionality.
>>
>> http://www.haible.de/bruno/packages-ffcall.html
>
> I am a SWIG (www.swig.org) developer, and I recently started looking at
> what it will take to add a parrot module to SWIG. I will post some of
> the
> issues I ran into, but I was wondering if there would be any interest
> for
> SWIG to become one of the official way to do NCI?
SWIG isn't a replacement for NCI. Parrot NCI is fully dynamic and
doesn't need any compiler, linker, interface definition file and what
not.
> SWIG has a whole bunch of other benefits which I won't list here.
I think, it would need good reasons to include another ffi-alike. But
that doesn't preclude SWIG of course.
> The main issue resolves around the problem that there isn't a standard
> way
> to just register a function as callable from parrot (that I can see).
Any PMC that provides the 'invoke' vtable is a callable.
> SWIG can easily generate functions of the form
> void* _wrap_foo(Interp* interpreter, PMC* pmc, void * next)
> one for each function being wrapped. Can we inject that function
> directly
> into the vtable somehow? Or just create a class that passes on the
> invoke
> function?
I presume that would be a NCI_SWIG PMC. If this callable is inserted
into the vtable or dynamically looked up is an implementation detail.
> One of the existing SWIG modules (CHICKEN) deals with a continuation
> passing language, so SWIG can deal with continuation-aware languages.
Sounds interesting
> SWIG does not require any code besides what it generates... think lex
> or
> yacc...
Well, it's fully static, while NCI is dynamic:
$ cat n.pir
.sub main :main
.local pmc l, f
.local string fn
.local float v
l = loadlib "libm"
loop:
(fn, v) = input_func_and_val()
f = dlfunc l, fn, "dd"
v = f(v)
print v
print "\n"
goto loop
.end
.sub input_func_and_val
.local pmc in, out
out = getstdout
print "> "
out."flush"()
.local string fn, v
in = getstdin
fn = readline in
chopn fn, 1
v = readline in
chopn v, 1
.return (fn, v)
.end
$ ./parrot n.pir
> sin
2
0.909297
> cos
2
-0.416147
> John
leo
Here's a reference to the last time this thread came up:
http://groups.google.com/group/perl.perl6.internals/browse_frm/thread/8b1b5e
7e343ce3c4/
and a shortened URL forwarded version:
http://ffcall-perl6-internals.notlong.com
Here's the tail end:
8. Dan Sugalski Jan 12 2004, 12:49 pm
At 10:13 AM -0600 1/12/04, Garrett Goebel wrote:
>
>Tim Bunce wrote:
>>
>> I see Dan says in his blog "Yeah, I know, we should use libffi, and
>> we may as a fallback, if we don't just give in and build up the
>> function headers everywhere."
>>
>> I'm not familiar with libffi so this may be a dumb question,
>> but why the apparent reluctance to use it?
>
>The reluctance probably doesn't have anything to do with its very liberal
>licensing terms...
Nope. The two issues were portability and the prospect of a library
which isn't ours that we'd need to maintain if we were distributing
it.
I'm fine with someone taking a stab at teaching Configure to probe
for it on platforms that don't have the JIT building up function
headers already, and teaching nci.c to use it in that case. (As long
as the order of preference is "JIT building functions", "libffi",
"current hackish NCI scheme" is maintained)
--
Dan
9. Garrett Goebel Jan 12 2004, 1:48 pm
Tim Bunce wrote:
> > Tim Bunce wrote:
> >
> > I see Dan says in his blog "Yeah, I know, we should use libffi,
> > and we may as a fallback, if we don't just give in and build up
> > the function headers everywhere."
> >
> > I'm not familiar with libffi so this may be a dumb question,
> > but why the apparent reluctance to use it?
> >
>
> In http://www.nntp.perl.org/group/perl.perl6.internals/253 I see
> Garrett Goebel quotes Bruno Haible saying "I could agree to the
> LGPL license. Perl could then use ffcall as a shared library
> (linked or via dlopen)"
>
> And I see http://www.parrotcode.org/docs/faq.pod.html says
> "Code accepted into the core interpreter must fall under the same
> terms as parrot. Library code (for example the ICU library we're
> using for Unicode) we link into the interpreter can be covered by
> other licenses so long as their terms don't prohibit this."
>
> So it seems there's no licensing issue preventing parrot using libffi.
>
> Is that right?
> Are there any others?
My bad. In my comments on Dan's blog, I confused libffi with ffcall. Both do
roughly the same thing...
The libffi was originally produced by Cygnus, but is now part of GCC.
http://sources.redhat.com/libffi/
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libffi/LICENSE
ffcall was produced by Bruno Haibel as part of his CLISP package.
http://www.haible.de/bruno/packages-ffcall.html
ffcall used to be considered more mature/stable, but since libffi was
included in GCC the general impression true or not is that libffi is more
actively maintained. From mailing lists and csv logs, it looks like both are
actively maintained...
10. Tim Bunce Jan 13 2004, 9:49 am
And since it seems both are usable for parrot from a licencing
perspective we're free to use whichever suits best on a given
platform - assuming someone implements the relevant interface code.
Tim.
--
Garrett Goebel
IS Development Specialist
ScriptPro Direct: 913.403.5261
5828 Reeds Road Main: 913.384.1008
Mission, KS 66202 Fax: 913.384.2180
www.scriptpro.com garrett at scriptpro dot com
>Nick Glencross wrote:
>
>
>>As mentioned on the list yesterday I started evaluating ffcall
>>as a way of providing NCI functionality.
>>
>> http://www.haible.de/bruno/packages-ffcall.html
>>
>>I actually really like the current NCI implementation, although
>>it suffers from a large nci.c file and all the usable prototypes
>>need to be specified at compile time in call_list.txt. Over time
>>as more libraries become supported this list will quickly grow.
>>
>>
>Here's a reference to the last time this thread came up:
>
>http://groups.google.com/group/perl.perl6.internals/browse_frm/thread/8b1b5e
>7e343ce3c4/
>
>and a shortened URL forwarded version:
> http://ffcall-perl6-internals.notlong.com
>
>
>
Thanks for that Garrett.
It's great that you've talked to Bruno in the past about this! Although
I had planned to look at both ffcall and libffi, ffcall has so far
looked more compelling to me.
I started looking for the latest version of libffi, couldn't be sure
which it was so I put it on the backburner. Then I looked at ffcall,
instantly thought 'perfect' because it provided a really usable API, and
then knocked up a quick POC.
I certainly agree about what was being said about supporting multiple
backends as it protects us against future nasty platforms. However, I'm
unclear what the benefits of the favoured option of using JIT code was;
that sounds like reinventing a ff library.
One thing that would be nice would be extend build_native.pl so that it
builds the other supported NCI layers; that way they would all support
the same types and not get out of sync with one another. I'd be
interested in trying this if no one objects...
My word of the week seems to be 'callbacks' because the current
implementation doesn't seem to cut it (in my opinion), which is really
the driving reason for looking at other alternatives.
Cheers,
Nick
> I certainly agree about what was being said about supporting multiple
> backends as it protects us against future nasty platforms. However, I'm
> unclear what the benefits of the favoured option of using JIT code was;
> that sounds like reinventing a ff library.
Having a JIT was a goal anyway. It avoids potential license conflicts.
It removes one dependency. It potentially reduces executable size and
memory use. It's something we can patch and test and customize as we
need, especially with regard to our calling conventions.
Those might not all be current benefits; I'm just going by memory and
not arguing for or against ffcall or libffi.
-- c