# Copyright (C) 2010, Parrot Foundation.

=pod

=head1 NAME

src/nci/framebuilder.pod - Parrot Native Call Frame Builder API

=head1 DESCRIPTION

Parrot's frame builder is fully pluggable at runtime. That is to say, a new implementation of the
frame builder can be installed at any time.

=head2 REGISTRATION

Parrot has 2 slots for the frame builder function - a callback PMC and a user data PMC. The
callback PMC is expected to return a valid C<nci_fb_func_t> native function from its C<get_pointer>
vtable.

The callback for a framebuilder should be registerd in parrot's C<iglobals> array under
C<NCI_FB_CB>. The user data is likewise registered in C<iglobals> under C<NCI_FB_UD>.

=head2 C<nci_fb_func_t>

C<nci_fb_func_t> functions receive an interpreter, the registered frame builder user data, and a
signature string. They are expected to produce a thunk PMC, and throw an exception or return C<NULL>
on failure. B<IMPORTANT:> frame builders should not parse the signature string themselves but
delegate to C<Parrot_nci_parse_signature> to ensure consistency between implementations.

=head2 Thunk PMCs

Thunk PMCs, produced by the frame builder callback, are expected to return a valid C<nci_thunk_t>
native function from their C<get_pointer> vtables.

C<nci_thunk_t> functions receive an interpreter, an NCI PMC, and a thunk PMC. They are expected to
unpack Parrot's PCC arguments and pass them to the native function pointer in the NCI PMC using the
appropriate native function calling conventions and to do the reverse with return values. The exact
details of what operations to perform are specified in the signature supplied to the frame builder
when the thunk is created.

=head2 The Thunk Cache

Thunks are generated lazily on demand and cached. Generally, only one thunk will exist for a given
NCI signature. The cache is held in C<iglobals> under C<NCI_FUNCS>. This cache can be operated on
directly, for example, clearing the cache is possible by running the following PIR code:

  .include 'iglobals.pasm'
  .sub 'clear-nci-cache'
    $P0 = getinterp
    $P0 = $P0[.IGLOBALS_NCI_FUNCS]
    $P1 = iter $P0
    loop:
	unless $P1 goto end_loop
	$S0 = shift $P1
	delete $P0[$S0]
	goto loop
    end_loop:
  .end

Note however, that this will B<not> remove thunks from NCI PMCs which have already been invoked
(these cache their Thunk PMC locally).

Another use of direct manipulation of the C<NCI_FUNCS> cache is nci thunk dynext libraries,
generated by C<nci_thunk_gen>, which add additional statically compiled thunks to parrot at runtime.

=head1 WARNING

The frame builder API is currently in a state of flux. Expected improvements are to isolate frame
builders further from the signature strings and also to reduce the C-bias in the API.

=cut

