Newbie questions about Pliant

Newbie questions about Pliant

Callback

Calling Pliant function without knowing its name
Message posted by maybe Boris Reitman on 2003/12/21 12:20:35
I am passing a pliant function address X to perl which will in turn call
a particular pliant function with address A and pass address X to it.  So now A must
call function X by address.  How do I do that ?  Also, given address X can I find
out the prototype of the function it references, at runtime ?  Also, instead 
of A being an address of function, as in,

  A := (the_function callback_bridge Address):execute

can it be an address of a particular instruction ?

Thanks, 
Boris



Message posted by hubert.tonneau on 2003/12/21 15:30:06
What you do is correct, provided your 'callback_bridge' function has
'external_calling_convention' attribute.
Message posted by reitman on 2003/12/22 18:21:41
Does Pliant relocate the location of a function ?  My callback works 
in the beginning but then stops working.

I have this pliant function,

  function callback_wrapper interpreter cv
    arg Address interpreter
    arg Address cv
    external_calling_convention
    console "zzzzzzzzzzzzzzzz in callback_wrapper" eol

I call this C function,

  init_callback_xs "pliant_call_function_" (the_function callback_wrapper Address Address):executable ""

And this is C code,

  XSUBADDR_t pliant_callback = NULL;

  void set_pliant_callback_address(void *ptr)
  { 
    pliant_callback = ptr;
  }

  void wrapper_callback(void *ptr1, void *ptr2)
  { 
    printf("Got pliant_callback = %d\n", pliant_callback);
    if ( pliant_callback != NULL )
      (*pliant_callback)(NULL,NULL);
  }

  void init_callback_xs(char *name, XSUBADDR_t pliant_callback_address, char *filename) {
    set_pliant_callback_address(pliant_callback_address);

    printf("Got pliant_callback %d\n", pliant_callback);
    (*pliant_callback)(NULL,NULL);

    newXS(name, (XSUBADDR_t) wrapper_callback, filename);
  }

----------------------
Here is the output
------------------------

Got pliant_callback 1080044344
zzzzzzzzzzzzzzzz in callback_wrapper
SV = RV(0x809a73c) at 0x809b2f0
  REFCNT = 1
  FLAGS = (ROK)
  RV = 0x809b1c4
in run_callback CODE(0x809b1c4)
in anonymous sub
Got pliant_callback = 1080044344
exception 11

------------------------------

It seems that the address 1080044344 was correct when I called the
callback right away in init_callback_xs,   but then, when I called 
it inside the C-implementation wrapper_callback, it was no longer the 
correct address.


Also, could you please show an example of how to pass a Pliant callback 
to a *Pliant* subroutine ?

Thanks, 
Boris
Message posted by hubert.tonneau on 2003/12/22 18:37:03
Your problem is probably that your callback function was freed in the mean time.
One way to lock it to memory is to export it.

Now, if you want to pass callback functions to Pliant, you have to use 'indirect'
See module /pliant/graphic/os/x11.pli for example:
in function 'XDestroyImage', we define the 'destroy_prototype' function which
defines the prototype for the callback.
Then, we set the 'executable' field of an empty 'Function' local variable to
get access to the function we received the address form the C part.

Here is a very simple example:

module "/pliant/language/compiler.pli"

function foo i f # this is defining the prototype of the callback function
  arg Int i ; arg Function f
  indirect

function twice f # here is a sample function that will use a callback
  arg Function f
  foo 3 f
  foo 5 f

function test i # here is the sample callback function
  arg Int i
  console "i = " i eol

twice (the_function test Int) # let's run
Message posted by maybe Boris Reitman on 2003/12/24 05:26:54

Thanks, things seem to be working for the most part.  
I'm having a problem with automatically initializing 
temporary variables.  I think it happens due to some optimization.
Statement,

  var PerlScalar scalar

is compiled to use an existing type instance instead of creating a new one.
As a result, the 'build' function doesn't initialize the 'scalar'
object, and things break from then on.

The problem occurs between 'console' statements 'Before' and 'After'
The presence of call 'perl_dump_scalar' makes the build
function run on the variable scalar.  This is OK.  But if
I remove perl_dump_scalar statement the 'build' instruction is never
executed.

=============================================================

function hello array -> retval
  arg_rw PerlArray array
  arg PerlArray retval
  console "Inside hello" eol
  for (var Int index) 0 array:size-1
    console "Got arg = " (cast array:index Str) eol

  # set return value

  console "Before xxxxxxxxx" eol

  var PerlScalar scalar
  perl_dump_scalar scalar

  #scalar reset
  console "After xxxxxxxxx" eol

  set_scalar_value scalar 1
  retval:0 := scalar


gvar PerlScalar callback :=  perl_callback_helper addressof:(the_function hello PerlArray -> PerlArray)
perl "run_callback" callback


==============================================================
Here is the output, in the case when 'build' is executed. 
This is shown by the last line 'DEBUG5: in build'.

(I would expect that since perl_dump_scalar causing 
the build to execute, I should see the 'DEBUG5: in build'
statement print out before I see 'After xxxxx'.  I'm guessing
that this must be some kind of optimization issue.  I think
that build runs before perl_dump_scalar is executed because
the dump correctly shows that 'SV = 0'.  Really all that build
does is set 'scalar:sv = 0'.)
==============================================================

DEBUG5: in build
DEBUG5: in build
DEBUG5: in build
DEBUG5: in build
in run_callback CODE(0x809b17c)
DEBUG5: in build
DEBUG5: in build
DEBUG5: in build
DEBUG5: in build
DEBUG5: in build
Inside hello
Got arg = a
Got arg = b
Got arg = c
Before xxxxxxxxx
SV = 0
After xxxxxxxxx
DEBUG5: in build
retval = 1

============================================================
Now, if I comment out the line

  perl_dump_scalar scalar

The build routine doesn't run.
=============================================================

DEBUG5: in build
DEBUG5: in build
DEBUG5: in build
DEBUG5: in build
in run_callback CODE(0x809b17c)
DEBUG5: in build
DEBUG5: in build
DEBUG5: in build
DEBUG5: in build
Inside hello
Got arg = a
Got arg = b
Got arg = c
Before xxxxxxxxx
After xxxxxxxxx
Modification of a read-only value attempted at (eval 1) line 1.

===============================================================

I have renamed 'hello' into 'sample function' to see the generated binary code.
I posted the output on the web at, 

http://boris.reitman.name/bug_yesbuild.txt
http://boris.reitman.name/bug_nobuild.txt

These are the 'build' and 'perl_dump_scalar' functions,

function build s
  arg_w PerlScalar s
  console "DEBUG5: in build" eol
  s:sv := null

public
  function perl_dump_scalar scalar
    arg PerlScalar scalar
    lperl_sv_dump scalar:sv

The lperl_sv_dump call is a call into an external C function.

Do you know what could be the problem ? 
Thanks,
Boris

Message posted by hubert.tonneau on 2003/12/24 09:58:32
What is the definition of 'PerlScalar' and prototype for 'set_scalar_value'

If 'PerlScalar' has a single field, what you could try just as a test is to add
it a second unused field.
Message posted by maybe Boris Reitman on 2003/12/24 18:21:09
I tried adding another field to PerlScalar (without any other code change)
but this didn't make any difference.

Here are the prototypes and code,

type PerlScalar
  field SV sv <- null
  #field Int dummy

function set_scalar_value s nn
  arg_w PerlScalar s
  arg uInt nn
  var Int n := (cast nn Int)
  #console "IN set_scalar_value" eol
  if s:sv = null 
    var SV sv
    sv := lperl_newSViv n 
    s set sv
  else
    lperl_sv_setiv s:sv n 

If you need to look at more code, its in CVS,

http://cvs.sourceforge.net/viewcvs.py/pliant-perl/pliant-perl/pliantx/language/perl/

Thanks,
Boris
Message posted by hubert.tonneau on 2003/12/24 18:27:36
Changing

function set_scalar_value s nn
  arg_w PerlScalar s

to

function set_scalar_value s nn
  arg_rw PerlScalar s

might solve the problem.





Message posted by maybe Boris Reitman on 2003/12/24 20:03:07
Great, that did it :)  Now I understand the difference 
between arg_rw and arg_w :)

Thanks!
Boris
Message posted by hubert.tonneau on 2003/12/24 23:45:18
I'm not sure your prototype was wrong.

In order to raise the proble ('scalar' local variable shared with another one)
we should have two properties:
. the 'PerlScalar' data type is atomic, which means
  . it has 'Int' size
  . it has no build or destroy method
. the 'set_scalar_value' has 'arg_w' prototype, which means it does not care
  of the previous content

What's puzzling is that I don't undertand why the 'PerlScalar' data type was
assumed to be atomic or scalar, and if it wasn't, how local variable sharing
could take place.
Message posted by maybe Boris Reitman on 2003/12/25 01:09:01
I have put a hole through my firewall into the dev box, so that 
it is possible to view the files. The SourceForge CVS viewer 
actually only updates nightly, so this URL is more recent.  

  http://lougheed.boris.reitman.info:8165/pliant-perl/pliantx/language/perl/

The PerlScalar is implemented in file 'types/scalar.pli'.

Note: I've started to move the project into Literate Programming
style.  It would be cool in the future to implement a literate programming
pliant module.  For now, I'm using the 'noweb' tool. The files with extension
.nw are source files from which the .pli and .html is generated.