Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tree: 48d2796f3c
Fetching contributors…

Cannot retrieve contributors at this time

297 lines (194 sloc) 6.055 kB
/*
Copyright (C) 2001-2008, The Perl Foundation.
$Id$
=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
*/
#include "parrot/parrot.h"
pmclass NCI need_ext {
ATTR STRING *signature; /* The signature. */
ATTR void *func; /* Function pointer to what we'll call. */
ATTR INTVAL arity; /* Cached arity of the NCI. */
/*
=item C<METHOD get_multisig()>
Return the MMD signature PMC, if any or a Null PMC.
=cut
*/
METHOD get_multisig() {
PMC *sig = PMC_pmc_val(SELF) ? PMC_pmc_val(SELF) : PMCNULL;
RETURN(PMC *sig);
}
/*
=item C<METHOD set_raw_nci_ptr(void *func)>
Sets the specified function pointer and raw flag.
=cut
*/
METHOD make_raw_nci(PMC *func) {
VTABLE_set_pointer(interp, SELF, (void *)func);
}
/*
=item C<void init()>
Initializes the NCI with a C<NULL> function pointer.
=cut
*/
VTABLE void init() {
PMC_struct_val(SELF) = NULL;
PMC_pmc_val(SELF) = PMCNULL;
PMC_data(SELF) = mem_allocate_zeroed_typed(Parrot_NCI);
/* Mark that we're not a raw NCI. */
PObj_flag_CLEAR(private2, SELF);
PObj_active_destroy_SET(SELF);
}
/*
=item C<void set_pointer_keyed_str(STRING *key, void *func)>
Sets the specified function pointer and signature (C<*key>).
=cut
*/
VTABLE void set_pointer(void *ptr) {
PMC_struct_val(SELF) = ptr;
PObj_flag_SET(private2, SELF);
}
VTABLE void set_pointer_keyed_str(STRING *key, void *func) {
Parrot_NCI * const nci_info = PARROT_NCI(SELF);
/* Store the original function and signature. */
PMC_struct_val(SELF) = func;
nci_info->signature = key;
/* Arity is length of that string minus one (the return type). */
nci_info->arity = string_length(INTERP, key) - 1;
/* Build call function. */
nci_info->func = (PMC *)(build_call_func(INTERP, SELF, key));
}
/*
=item C<void destroy()>
Destroys the NCI, freeing any allocated memory.
=cut
*/
VTABLE void destroy() {
if (PMC_data(SELF)) {
Parrot_NCI * const nci_info = PARROT_NCI(SELF);
#if defined(CAN_BUILD_CALL_FRAMES)
if (nci_info->func)
mem_free_executable(nci_info->func);
#endif
mem_sys_free(nci_info);
PMC_data(SELF) = NULL;
}
}
/*
=item C<PMC *clone()>
Creates and returns a clone of the NCI.
=cut
*/
VTABLE PMC *clone() {
Parrot_NCI * const nci_info_self = PARROT_NCI(SELF);
Parrot_NCI *nci_info_ret;
PMC * const ret = pmc_new_noinit(INTERP, SELF->vtable->base_type);
PMC_struct_val(ret) = PMC_struct_val(SELF);
PMC_pmc_val(ret) = PMCNULL;
PMC_data(ret) = mem_allocate_zeroed_typed(Parrot_NCI);
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->signature = nci_info_self->signature;
nci_info_ret->arity = nci_info_self->arity;
PObj_get_FLAGS(ret) |= (PObj_get_FLAGS(SELF) & 0x7);
return ret;
}
/*
=item C<INTVAL defined()>
Returns whether the NCI is defined.
=cut
*/
VTABLE INTVAL defined() {
Parrot_NCI * const nci_info = PARROT_NCI(SELF);
return nci_info->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 * const nci_info = PARROT_NCI(SELF);
typedef INTVAL (*nci_sub_t)(PARROT_INTERP, PMC *);
nci_sub_t func = PObj_flag_TEST(private2, SELF)
? (nci_sub_t) D2FPTR(PMC_struct_val(SELF))
: (nci_sub_t) D2FPTR(nci_info->func);
PMC *cont;
if (!func)
real_exception(INTERP, NULL, INVALID_OPERATION,
"attempt to call NULL function");
func(INTERP, SELF);
cont = INTERP->current_cont;
/*
* 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 (cont && cont != NEED_CONTINUATION &&
(PObj_get_FLAGS(cont) & SUB_FLAG_TAILCALL)) {
cont = CONTEXT(interp)->current_cont;
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 * const nci_info = PARROT_NCI(SELF);
return (INTVAL)nci_info->func;
}
/*
=item C<INTVAL get_bool()>
Returns the boolean value of the pointer.
=cut
*/
VTABLE INTVAL get_bool() {
Parrot_NCI * const nci_info = PARROT_NCI(SELF);
return (0 != (INTVAL)nci_info->func);
}
/*
=item C<METHOD arity()>
Return the arity of the NCI (the number of arugments).
=cut
*/
METHOD arity() {
Parrot_NCI * const nci_info = PARROT_NCI(SELF);
INTVAL arity = 0;
if (nci_info && nci_info->func)
arity = nci_info->arity;
else
real_exception(INTERP, NULL, INVALID_OPERATION,
"You cannot get the arity of an undefined NCI.");
RETURN(INTVAL arity);
}
}
/*
=back
=head1 SEE ALSO
F<docs/pdds/pdd03_calling_conventions.pod>.
=head1 HISTORY
Initial revision by sean 2002/08/04.
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4:
*/
Jump to Line
Something went wrong with that request. Please try again.