Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 6586a2ca6f
Fetching contributors…

Cannot retrieve contributors at this time

296 lines (192 sloc) 5.866 kb
/*
Copyright (C) 2001-2007, The Perl Foundation.
$Id$
=head1 NAME
src/pmc/nci.pmc - Native Call Interface
=head1 DESCRIPTION
The vtable functions for the native C call functions.
Invoking an NCI function changes some registers according to PDD 3.
The caller has to preserve registers if needed.
=head2 Methods
=over 4
=cut
*/
#include "parrot/parrot.h"
/* NCI PMC's underlying struct. */
typedef struct Parrot_NCI {
STRING *signature; /* The signature. */
int arity; /* Cached arity of the NCI. */
funcptr_t *func; /* Function pointer to what we'll call. */
} Parrot_NCI;
/* Macro to access underlying structure of an NCI PMC. */
#define PARROT_NCI(o) ((Parrot_NCI *) PMC_data(o))
pmclass NCI need_ext {
/*
=item C<METHOD PMC *get_multisig()>
Return the MMD signature PMC, if any or a Null PMC.
=cut
*/
METHOD PMC *get_multisig() {
return PMC_pmc_val(SELF) ? PMC_pmc_val(SELF) : PMCNULL;
}
/*
=item C<METHOD PMC *set_raw_nci_ptr(void *func)>
Sets the specified function pointer and raw flag.
=cut
*/
METHOD void make_raw_nci(void *func) {
PMC_struct_val(SELF) = func;
PObj_flag_SET(private2, SELF);
}
/*
=item C<void init()>
Initializes the NCI with a C<NULL> function pointer.
=cut
*/
void init() {
PMC_struct_val(SELF) = NULL;
PMC_pmc_val(SELF) = PMCNULL;
PMC_data(SELF) = mem_sys_allocate_zeroed(sizeof(Parrot_NCI));
/* Mark that we're not a raw NCI. */
PObj_flag_CLEAR(private2, SELF);
}
/*
=item C<void set_pointer_keyed_str(STRING *key, void *func)>
Sets the specified function pointer and signature (C<*key>).
=cut
*/
void set_pointer_keyed_str(STRING *key, void *func) {
Parrot_NCI *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 = build_call_func(INTERP, SELF, key);
}
/*
=item C<void destroy()>
Destroys the NCI, freeing any allocated memory.
=cut
*/
void destroy() {
if (PMC_data(SELF)) {
Parrot_NCI *nci_info = PARROT_NCI(SELF);
if (nci_info->func)
mem_free_executable(nci_info->func);
mem_sys_free(nci_info);
}
}
/*
=item C<PMC *clone()>
Creates and returns a clone of the NCI.
=cut
*/
PMC *clone() {
Parrot_NCI *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_sys_allocate_zeroed(sizeof(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
*/
INTVAL defined() {
Parrot_NCI *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
*/
opcode_t *invoke(void *next) {
Parrot_NCI *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->ctx)->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
*/
INTVAL get_integer() {
Parrot_NCI *nci_info = PARROT_NCI(SELF);
return (INTVAL)nci_info->func;
}
/*
=item C<INTVAL get_bool()>
Returns the boolean value of the pointer.
=cut
*/
INTVAL get_bool() {
Parrot_NCI *nci_info = PARROT_NCI(SELF);
return (0 != (INTVAL)nci_info->func);
}
/*
=item C<METHOD INTVAL arity()>
Return the arity of the NCI (the number of arugments).
=cut
*/
METHOD INTVAL arity() {
Parrot_NCI *nci_info = PARROT_NCI(SELF);
if (nci_info != NULL && nci_info->func != NULL)
return nci_info->arity;
else
real_exception(INTERP, NULL, INVALID_OPERATION,
"You cannot get the arity of an undefined NCI.");
return 0; /* Unreachable; avoids warning. */
}
}
/*
=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.