If you have a Sub PMC (or subclass), you can invoke that PMC from C code using 
Parrot_call_sub() or a similar function.  Of course, if you want to pass 
arguments to that PMC, something needs to translate those arguments from C's 
calling conventions to Parrot's calling conventions.

That something is a function something like runops_args() in src/inter_run.c.

Here's the fun part.

This function calls:

            dest = VTABLE_invoke(interp, sub, NULL);

That is, it invokes the PMC.  A Sub PMC returns the address of the next opcode 
to run -- the first opcode of the sub.  runops_args() can check that opcode 
to see if it fetches arguments.  A subroutine that takes arguments will start 
with an opcode to fetch the arguments.

The important thing is that this doesn't really execute the subroutine.  It 
just gets the address of the next opcode to run.  Parrot can run that later, 
after it sets up the arguments appropriately.

Of course, an NCI PMC (a subclass of the Sub PMC) doesn't really have an 
opcodes to execute, as it's a function pointer to execute.  Its invoke() 
vtable override actually calls the function.

Note that this happens *before* Parrot translates the arguments from the C 
conventions into Parrot's conventions, so in the NCI thunk that translate 
arguments from Parrot's conventions back into C's conventions, the arguments 
Just Aren't There.

I'm not sure what the right solution is, but Liskov cries a little bit.  
Clearly, invoke() behaves very differently for Sub and NCI subs.

I haven't looked at how Multi behaves, but I have my guesses.

-- c

Reply via email to