/*
Copyright (C) 2001-2011, Parrot Foundation.
=head1 NAME
src/pmc/nci.pmc - Native Call Interface
=head1 DESCRIPTION
The vtable functions for the native C call functions.
=head2 Methods
=over 4
=cut
*/
/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
PARROT_IGNORABLE_RESULT
static nci_thunk_t /*@alt void@*/
build_func(PARROT_INTERP,
ARGIN(PMC *obj),
ARGMOD(Parrot_NCI_attributes *nci))
__attribute__nonnull__(1)
__attribute__nonnull__(2)
__attribute__nonnull__(3)
FUNC_MODIFIES(*nci);
#define ASSERT_ARGS_build_func __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
PARROT_ASSERT_ARG(interp) \
, PARROT_ASSERT_ARG(obj) \
, PARROT_ASSERT_ARG(nci))
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
/*
=item C<static nci_thunk_t build_func(PARROT_INTERP, PMC *obj,
Parrot_NCI_attributes *nci)>
Actually build the NCI thunk.
=cut
*/
PARROT_IGNORABLE_RESULT
static nci_thunk_t
build_func(PARROT_INTERP, ARGIN(PMC *obj), ARGMOD(Parrot_NCI_attributes *nci))
{
ASSERT_ARGS(build_func)
Parrot_nci_sig_to_pcc(interp, nci->signature,
&nci->pcc_params_signature,
&nci->pcc_return_signature);
/* Arity is length of the signature minus one (the return type). */
nci->arity = VTABLE_elements(interp, nci->signature) - 1;
/* Build call function. */
nci->fb_info = build_call_func(interp, nci->signature);
nci->func = F2DPTR(VTABLE_get_pointer(interp, nci->fb_info));
PARROT_GC_WRITE_BARRIER(interp, obj);
return (nci_thunk_t)nci->func;
}
pmclass NCI auto_attrs provides invokable {
/* NCI thunk handling attributes */
ATTR PMC *signature; /* parsed signature */
ATTR void *func; /* function pointer to call */
ATTR PMC *fb_info; /* frame-builder info */
ATTR void *orig_func; /* pointer to wrapped function */
/* Parrot Sub-ish attributes */
ATTR STRING *pcc_params_signature;
ATTR STRING *pcc_return_signature;
ATTR INTVAL arity;
/* MMD fields */
ATTR STRING *long_signature;
ATTR PMC *multi_sig;
/*
=item C<METHOD get_multisig()>
Return the MMD signature PMC, if any or C<PMCNULL>.
=cut
*/
METHOD get_multisig() {
PMC *sig;
GET_ATTR_multi_sig(INTERP, SELF, sig);
if (PMC_IS_NULL(sig))
sig = PMCNULL;
RETURN(PMC *sig);
}
/*
=item C<void init()>
Initializes the NCI with a C<NULL> function pointer.
=cut
*/
VTABLE void init() {
PObj_custom_mark_SET(SELF);
}
VTABLE void *get_pointer() {
return PARROT_NCI(SELF)->orig_func;
}
/*
=item C<void set_pmc_keyed(PMC *key, PMC *p)>
=item C<void set_pmc_keyed_str(STRING *key, PMC *p)>
Call the equivalent C<set_pointer*> function.
=cut
*/
VTABLE void set_pmc_keyed(PMC *key, PMC *p) {
STATICSELF.set_pointer_keyed(key, VTABLE_get_pointer(INTERP, p));
}
VTABLE void set_pmc_keyed_str(STRING *key, PMC *p) {
STATICSELF.set_pointer_keyed_str(key, VTABLE_get_pointer(INTERP, p));
}
/*
=item C<void set_pointer_keyed(PMC *key, void *func)>
Sets the specified function pointer and signature (C<*key>).
=item C<void set_pointer_keyed_str(STRING *key, void *func)>
Sets the specified function pointer and siganture as described in the string C<key>.
=cut
*/
VTABLE void set_pointer_keyed(PMC *key, void *func) {
/* Store the original function and signature. */
SET_ATTR_orig_func(INTERP, SELF, func);
SET_ATTR_signature(INTERP, SELF, key);
}
VTABLE void set_pointer_keyed_str(STRING *key, void *func) {
SELF.set_pointer_keyed(Parrot_nci_parse_signature(INTERP, key), func);
}
/*
=item C<void mark()>
Mark any referenced strings and PMCs.
=cut
*/
VTABLE void mark() {
if (PARROT_NCI(SELF)) {
Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
Parrot_gc_mark_PMC_alive(interp, nci_info->signature);
Parrot_gc_mark_PMC_alive(interp, nci_info->fb_info);
Parrot_gc_mark_PMC_alive(interp, nci_info->multi_sig);
Parrot_gc_mark_STRING_alive(interp, nci_info->long_signature);
Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_params_signature);
Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_return_signature);
}
}
/*
=item C<PMC *clone()>
Creates and returns a clone of the NCI.
=cut
*/
VTABLE PMC *clone() {
Parrot_NCI_attributes * const nci_info_self = PARROT_NCI(SELF);
PMC * const ret = Parrot_pmc_new(INTERP, SELF->vtable->base_type);
Parrot_NCI_attributes * const nci_info_ret = PARROT_NCI(ret);
/* FIXME if data is malloced (JIT/i386!) then we need
* the length of data here, to memcpy it
* ManagedStruct or Buffer?
*/
nci_info_ret->func = nci_info_self->func;
nci_info_ret->fb_info = nci_info_self->fb_info;
nci_info_ret->orig_func = nci_info_self->orig_func;
nci_info_ret->signature = nci_info_self->signature;
nci_info_ret->pcc_params_signature = nci_info_self->pcc_params_signature;
nci_info_ret->pcc_return_signature = nci_info_self->pcc_params_signature;
nci_info_ret->arity = nci_info_self->arity;
PObj_get_FLAGS(ret) = PObj_get_FLAGS(SELF);
return ret;
}
/*
=item C<INTVAL defined()>
Returns whether the NCI is defined.
=cut
*/
VTABLE INTVAL defined() {
const Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
return nci_info->orig_func != NULL;
}
/*
=item C<opcode_t *invoke(void *next)>
Calls the associated C function, returning C<*next>. If the invocant is a
class, the PMC arguments are shifted down.
=cut
*/
VTABLE opcode_t *invoke(void *next) {
Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
nci_thunk_t func;
PMC *fb_info;
PMC *cont;
func = (nci_thunk_t)D2FPTR(nci_info->func);
if (!func) {
/* build the thunk only when necessary */
func = build_func(interp, SELF, nci_info);
if (!func)
Parrot_ex_throw_from_c_args(INTERP, NULL,
EXCEPTION_INVALID_OPERATION,
"attempt to call NULL function");
}
GET_ATTR_fb_info(INTERP, SELF, fb_info);
cont = INTERP->current_cont;
func(INTERP, SELF, fb_info);
/*
* If the NCI function was tailcalled, the return result
* is already passed back to the caller of this frame
* - see Parrot_init_ret_nci(). We therefore invoke the
* return continuation here, which gets rid of this frame
* and returns the real return address
*/
if (!PMC_IS_NULL(cont)
&& (PObj_get_FLAGS(cont) & SUB_FLAG_TAILCALL)) {
cont = Parrot_pcc_get_continuation(interp, CURRENT_CONTEXT(interp));
next = VTABLE_invoke(INTERP, cont, next);
}
return (opcode_t *)next;
}
/*
=item C<INTVAL get_integer()>
Returns the function pointer as an integer.
=cut
*/
VTABLE INTVAL get_integer() {
Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
if (!nci_info->func)
build_func(INTERP, SELF, nci_info);
return (INTVAL)nci_info->func;
}
/*
=item C<INTVAL get_bool()>
Returns the boolean value of the pointer.
=cut
*/
VTABLE INTVAL get_bool() {
const Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
return (0 != (INTVAL)nci_info->orig_func);
}
/*
=item C<METHOD arity()>
Return the arity of the NCI (the number of arguments).
=cut
*/
METHOD arity() {
Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
if (nci_info) {
if (!nci_info->func)
build_func(INTERP, SELF, nci_info);
if (nci_info->func) {
const INTVAL arity = nci_info->arity;
RETURN(INTVAL arity);
}
}
Parrot_ex_throw_from_c_args(INTERP, NULL,
EXCEPTION_INVALID_OPERATION,
"You cannot get the arity of an undefined NCI.");
}
}
/*
=back
=head1 SEE ALSO
F<docs/pdds/pdd03_calling_conventions.pod>.
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/