Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

GSoC: The majority of my NCI changes in 1 commit.

git-svn-id: https://svn.parrot.org/parrot/branches/gsoc_nci@48554 d31e2699-5ff4-0310-a27c-f18f2fbe73fe
  • Loading branch information...
commit 0c5f9c3fa3eb53bcd3677c3b993c304e6d371696 1 parent 41c9096
John Harrison authored
View
121 config/auto/libffi.pm
@@ -0,0 +1,121 @@
+# Copyright (C) 2005-2010, Parrot Foundation.
+# $Id$
+
+=head1 NAME
+
+config/auto/libffi - Check whether libffi
+
+=head1 DESCRIPTION
+
+=cut
+
+package auto::libffi;
+
+use strict;
+use warnings;
+
+use base qw(Parrot::Configure::Step);
+
+use Parrot::Configure::Utils ':auto';
+
+sub _init {
+ my $self = shift;
+ my %data;
+ $data{description} = q{Is libffi installed};
+ $data{result} = q{};
+ return \%data;
+}
+
+my @pkgconfig_variations =
+ defined( $ENV{TEST_PKGCONFIG} )
+ ? @{ $ENV{TEST_PKGCONFIG} }
+ : qw( pkg-config );
+
+sub runstep {
+ my ( $self, $conf ) = @_;
+
+ my ( $verbose, $without ) = $conf->options->get(
+ qw|
+ verbose
+ without-libffi
+ |
+ );
+
+ if ($without) {
+ $conf->data->set( HAS_LIBFFI => 0 );
+ $self->set_result('no');
+ return 1;
+ }
+
+ my $osname = $conf->data->get('osname');
+ print "\n" if $verbose;
+ my $pkgconfig_exec = check_progs([ @pkgconfig_variations ], $verbose);
+
+ my $libffi_options_cflags = '';
+ my $libffi_options_libs = '';
+ my $libffi_options_linkflags = '';
+
+ if ($pkgconfig_exec) {
+ $libffi_options_linkflags = capture_output($pkgconfig_exec, 'libffi --libs-only-L');
+ chomp $libffi_options_linkflags;
+ $libffi_options_libs = capture_output($pkgconfig_exec, 'libffi --libs-only-l');
+ chomp $libffi_options_libs;
+ $libffi_options_cflags = capture_output($pkgconfig_exec, 'libffi --cflags');
+ chomp $libffi_options_cflags;
+ }
+
+ my $extra_libs = $self->_select_lib( {
+ conf => $conf,
+ osname => $osname,
+ cc => $conf->data->get('cc'),
+ default => $libffi_options_libs . ' ' . $libffi_options_cflags,
+ } );
+
+ $conf->cc_gen('config/auto/libffi/test_c.in');
+ eval { $conf->cc_build( $libffi_options_cflags, $libffi_options_libs ) };
+ my $has_libffi = 0;
+ if ( !$@ ) {
+ my $test = $conf->cc_run();
+ $has_libffi = _evaluate_cc_run($test, $verbose);
+ }
+ $conf->cc_clean();
+
+ if ($has_libffi) {
+ $conf->data->set( HAS_LIBFFI => $has_libffi);
+ $conf->data->add( ' ', ccflags => $libffi_options_cflags );
+ $conf->data->add( ' ', libs => $libffi_options_libs );
+ $conf->data->add( ' ', linkflags => $libffi_options_linkflags );
+ $self->set_result('yes');
+ if ($verbose) {
+ print 'libffi cflags: ', $libffi_options_cflags, "libffi libs: ", $libffi_options_libs, "\n";
+ }
+ }
+ else {
+ $conf->data->set( HAS_LIBFFI => 0 );
+ $self->set_result('no');
+ print "No libffi found." if ($verbose);
+ }
+
+ return 1;
+}
+
+sub _evaluate_cc_run {
+ my ($output, $verbose) = @_;
+ my $has_libffi = ( $output =~ m/libffi worked/ ) ? 1 : 0;
+ return $has_libffi;
+}
+
+1;
+
+=head1 AUTHOR
+
+John Harrison <ash.gti at gmail dot com>
+
+=cut
+
+# Local Variables:
+# mode: cperl
+# cperl-indent-level: 4
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:
View
37 config/auto/libffi/test_c.in
@@ -0,0 +1,37 @@
+/*
+Copyright (C) 2008-2010, Parrot Foundation.
+$Id$
+
+seeing if libffi is installed
+*/
+
+#include <stdio.h>
+#include <ffi.h>
+
+int main() {
+ ffi_cif cif;
+ ffi_type *args[1];
+ void *values[1];
+ char *s;
+ int rc;
+
+ /* Initialize the argument info vectors */
+ args[0] = &ffi_type_pointer;
+ values[0] = &s;
+
+ /* Initialize the cif */
+ if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1,
+ &ffi_type_uint, args) == FFI_OK) {
+ s = "libffi worked";
+ ffi_call(&cif, FFI_FN(puts), &rc, values);
+ }
+
+ return 0;
+}
+
+/*
+ * Local variables:
+ * c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */
View
55 config/gen/libffi.pm
@@ -0,0 +1,55 @@
+# Copyright (C) 2001-2010, Parrot Foundation.
+# $Id$
+
+=head1 NAME
+
+config/gen/libffi.pm - Libffi Files
+
+=head1 DESCRIPTION
+
+Moves the appropriate nci files into place.
+
+=cut
+
+package gen::libffi;
+
+use strict;
+use warnings;
+
+use base qw(Parrot::Configure::Step);
+
+use Parrot::Configure::Utils ':gen';
+
+sub _init {
+ my $self = shift;
+ my %data;
+
+ $data{description} = q{Moving approriate NCI files into place};
+
+ return \%data;
+}
+
+sub runstep {
+ my ( $self, $conf ) = @_;
+
+ my $nci_file = 'config/gen/libffi/nci.pmc.in';
+ if ( $conf->data->get("HAS_LIBFFI") ) {
+ $nci_file = 'config/gen/libffi/nci-ffi.pmc.in';
+ }
+ else {
+ }
+
+ copy_if_diff( $nci_file, "src/pmc/nci.pmc" );
+
+ return 1;
+}
+
+1;
+
+# Local Variables:
+# mode: cperl
+# cperl-indent-level: 4
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4:
+
View
1,503 config/gen/libffi/nci-ffi.pmc.in
@@ -0,0 +1,1503 @@
+/*
+Copyright (C) 2001-2010, Parrot 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
+
+*/
+
+/* Cheat with this include, for whatever reason the space is required */
+# include "ffi.h"
+
+/* 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,
+ ARGMOD(Parrot_NCI_attributes *nci_info))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ FUNC_MODIFIES(*nci_info);
+
+static void pcc_params(PARROT_INTERP,
+ ARGIN(STRING *sig),
+ ARGMOD(Parrot_NCI_attributes *nci_info),
+ size_t sig_length)
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ __attribute__nonnull__(3)
+ FUNC_MODIFIES(*nci_info);
+
+#define ASSERT_ARGS_build_func __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(nci_info))
+#define ASSERT_ARGS_pcc_params __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(sig) \
+ , PARROT_ASSERT_ARG(nci_info))
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
+/* HEADERIZER END: static */
+
+static
+INTVAL
+parse_sig(PARROT_INTERP, STRING *sig, size_t sig_length, Parrot_NCI_attributes *nci_info);
+
+static
+size_t
+parse_return(PARROT_INTERP, STRING* sig, size_t sig_length,
+ Parrot_NCI_attributes * nci_info, ffi_type **return_type);
+
+static
+size_t
+parse_args(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length,
+ Parrot_NCI_attributes *nci_info, ffi_type ***arg_types);
+
+static
+size_t
+parse_identifier(PARROT_INTERP,
+ STRING* sig, size_t start, size_t end,
+ ffi_type** sig_obj,
+ char* pmc_type, size_t *pmc_count,
+ char* translation, size_t *translation_length);
+
+static
+size_t
+parse_structure(PARROT_INTERP, STRING* sig, size_t start, size_t end,
+ ffi_type** sig_obj, char* pmc_type);
+
+static
+INTVAL
+parse_prefix(INTVAL c);
+
+static
+size_t
+structure_length(PARROT_INTERP, STRING* sig, size_t start, size_t end);
+
+static
+size_t
+count_args(PARROT_INTERP, STRING* sig, size_t start, size_t end);
+
+static
+size_t
+find_matching(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length,
+ INTVAL start_character, INTVAL end_character);
+
+#define IS_DIGIT(x) (((x) == '0') || ((x) == '1') || ((x) == '2') || ((x) == '3') \
+ || ((x) == '4') || ((x) == '5') || ((x) == '6') || ((x) == '7') \
+ || ((x) == '8') || ((x) == '9'))
+
+#define IS_PREFIX(x) (((x) == '*') || ((x) == 'u'))
+
+#define IS_OLD_TYPE(x) (((x) == 'P') || ((x) == 'J') || ((x) == 'N') || ((x) == 'S') \
+ || ((x) == 'O') || ((x) == '@') || ((x) == 'B') || ((x) == 'p') \
+ || ((x) == '2') || ((x) == '3') || ((x) == '4') || ((x) == 'U') \
+ || ((x) == 'V'))
+
+#define IS_TYPE(x) (((x) == 'i') || ((x) == 'v') || ((x) == 'l') || ((x) == 't') \
+ || ((x) == 'c') || ((x) == 'b') || ((x) == 'f') || ((x) == 'd') \
+ || ((x) == 's') || IS_OLD_TYPE(x))
+
+#define IS_POSTFIX(x) ((x) == '{') /* || IS_DIGIT(x)) */
+#define IS_INFIX(x) ((x) == '|')
+#define IS_START_CIRCUMFIX(x) ((x) == '(')
+#define IS_END_CIRCUMFIX(x) ((x) == ')')
+#define IS_NOT_END_CIRCUMFIX(x) ((x) != ')')
+
+#define PREFIX_POINTER (1<<0)
+#define PREFIX_SIGNED ( 0)
+#define PREFIX_UNSIGNED (1<<1)
+#define PREFIX_NATIVE (1<<2)
+
+typedef struct pmc_holder_t {
+ PMC* p;
+ union {
+ INTVAL* ival;
+ void** pval;
+ };
+} pmc_holder_t;
+
+/*
+
+=item C<static INTVAL parse_sig(PARROT_INTERP, STRING *sig,
+ size_t sig_length, Parrot_NCI_attributes *nci_info)>
+
+Parse a full signature. All signatures should contain a return type and a list of
+arguments. "vv" Would be the shortest "void fn(void)" signature you can legally make.
+
+See C<parse_return> and C<parse_args> to see how the signature is broken down.
+
+=cut
+
+*/
+
+static INTVAL
+parse_sig(PARROT_INTERP, STRING *sig, size_t sig_length, Parrot_NCI_attributes *nci_info) {
+ ffi_cif cif;
+ ffi_type *return_type;
+ ffi_type **arg_types;
+
+ if (sig_length) {
+ size_t i = parse_return(interp, sig, sig_length, nci_info, &return_type);
+ if (i < sig_length)
+ parse_args(interp, sig, i, sig_length, nci_info, &arg_types);
+ else {
+ arg_types = mem_internal_allocate_n_zeroed_typed(1, ffi_type*);
+ arg_types[0] = &ffi_type_void;
+ nci_info->pcc_params_signature = string_make(interp, "", 1, NULL, 0);
+ nci_info->arg_translation = NULL;
+ nci_info->arity = 0;
+ }
+ }
+ else {
+ arg_types = mem_internal_allocate_n_zeroed_typed(1, ffi_type*);
+ arg_types[0] = &ffi_type_void;
+ return_type = &ffi_type_void;
+ nci_info->pcc_params_signature = string_make(interp, "", 1, NULL, 0);
+ nci_info->arg_translation = NULL;
+ nci_info->arity = 0;
+ }
+
+ if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI,
+ nci_info->arity, return_type, arg_types) == FFI_OK) {
+ nci_info->cif = (void*)mem_internal_allocate_typed(ffi_cif);
+ memcpy(nci_info->cif, &cif, sizeof (ffi_cif));
+ nci_info->arg_types = arg_types;
+
+ return 1;
+ }
+
+ if (arg_types) {
+ mem_sys_free(arg_types);
+ }
+
+ /* TODO: Throw Error here. */
+ printf("Bad signature\n");
+
+ return 0;
+}
+
+/*
+
+=item C<static size_t parse_return(PARROT_INTERP, STRING *sig, size_t sig_length,
+ Parrot_NCI_attributes* nci_info, ffi_type **return_type)>
+
+Parses the return type. This assumes the first identifier is the return type.
+
+See C<parse_identifier> to see how a single identifer is parsed.
+
+=cut
+
+*/
+
+static size_t
+parse_return(PARROT_INTERP, STRING *sig, size_t sig_length,
+ Parrot_NCI_attributes* nci_info, ffi_type **return_type) {
+ char *t = mem_allocate_n_zeroed_typed(2, char);
+ size_t j = 0, k = 0;
+ /* Should be 1 character plus a NULL" */
+ char * result_sig = mem_allocate_n_zeroed_typed(2, char);
+ size_t result_length = parse_identifier(interp,
+ sig, 0, sig_length,
+ return_type,
+ result_sig, &j,
+ t, &k);
+
+ nci_info->pcc_return_signature = string_make(interp, result_sig, 2, NULL, 0);
+ nci_info->return_translation = (void*)t;
+ mem_sys_free(result_sig);
+ return result_length;
+}
+
+/*
+
+=item C<static size_t parse_args(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length,
+ Parrot_NCI_attributes *nci_info, ffi_type ***arg_types)>
+
+Parses the signatures arguments. It takes an offset to know where to start looking.
+This should fill out a list of C<ffi_type*> args.
+
+See C<parse_identifier> to see how a single identifer is parsed.
+
+=cut
+
+*/
+
+static size_t
+parse_args(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length,
+ Parrot_NCI_attributes *nci_info, ffi_type ***arg_types) {
+ size_t i = start;
+ size_t arg_count = 0;
+ size_t argc = count_args(interp, sig, start, sig_length);
+ char* parrot_types = mem_allocate_n_zeroed_typed(argc + 1, char);
+ size_t parrot_types_length = 0;
+ char* translation_types = mem_allocate_n_zeroed_typed(argc + 1, char);
+ size_t translation_length = 0;
+
+ *arg_types = mem_internal_allocate_n_zeroed_typed(argc + 1, ffi_type*);
+
+ while (i < sig_length) {
+ ffi_type *ident;
+ i = parse_identifier(interp,
+ sig, i, sig_length,
+ &ident,
+ parrot_types, &parrot_types_length,
+ translation_types, &translation_length);
+ (*arg_types)[arg_count] = ident;
+ arg_count++;
+ }
+
+ nci_info->pcc_params_signature = string_make(interp, parrot_types,
+ strlen(parrot_types), NULL, 0);
+ nci_info->arg_translation = translation_types;
+ nci_info->arity = arg_count;
+
+ mem_sys_free(parrot_types);
+
+ return i;
+}
+
+/*
+
+=item C<static size_t parse_identifier(PARROT_INTERP, STRING *sig, size_t start,
+ size_t sig_length, ffi_type **type_obj,
+ char **type, size_t *pmc_count,
+ char **translation, size_t *translation_count)>
+
+Parse an identifier and build its representation used for PCC and any translations
+that are needed.
+
+An example of a transation is "t", it will take a STRING* and convert it to a
+char* for the function call.
+
+=cut
+
+*/
+
+static size_t
+parse_identifier(PARROT_INTERP,
+ STRING *sig, size_t start, size_t sig_length,
+ ffi_type **type_obj,
+ char *type, size_t *pmc_count,
+ char *translation, size_t *translation_count) {
+ size_t i = start;
+ INTVAL done = 0;
+
+ while (!done && i < sig_length) {
+ INTVAL c = Parrot_str_indexed(interp, sig, i);
+ int prefix = 0;
+ while (IS_PREFIX(c)) {
+ prefix |= parse_prefix(c);
+ i++;
+
+ if (i < sig_length)
+ c = Parrot_str_indexed(interp, sig, i);
+ else
+ return i;
+ }
+
+ if (IS_START_CIRCUMFIX(c)) {
+ i = parse_structure(interp, sig, i + 1, sig_length, type_obj, type);
+ i++;
+
+ if (i < sig_length)
+ c = Parrot_str_indexed(interp, sig, i);
+ else
+ return i;
+ }
+ else if (IS_TYPE(c)) {
+ if (prefix & PREFIX_POINTER) {
+ *type_obj = &ffi_type_pointer;
+ continue;
+ }
+ translation[(*translation_count)++] = ' ';
+ switch (c) {
+ case (INTVAL)' ':
+ case (INTVAL)'0': /* null ptr or such - doesn't consume a reg */
+ break;
+ case (INTVAL)'c':
+ translation[(*translation_count) - 1] = 'c';
+ type[(*pmc_count)++] = 'I';
+ if (prefix & PREFIX_UNSIGNED) {
+ *type_obj = &ffi_type_uchar;
+ }
+ else {
+ *type_obj = &ffi_type_schar;
+ }
+ break;
+ case (INTVAL)'B':
+ translation[(*translation_count) - 1] = 'B';
+ type[(*pmc_count)++] = 'S';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'b':
+ translation[(*translation_count) - 1] = 'b';
+ type[(*pmc_count)++] = 'S';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'s':
+ translation[(*translation_count) - 1] = 's';
+ type[(*pmc_count)++] = 'I';
+ if (prefix & PREFIX_UNSIGNED) {
+ *type_obj = &ffi_type_ushort;
+ }
+ else {
+ *type_obj = &ffi_type_sshort;
+ }
+ break;
+ case (INTVAL)'I': /* INTVAL */
+ case (INTVAL)'i':
+ translation[(*translation_count) - 1] = 'i';
+ type[(*pmc_count)++] = 'I';
+ if (prefix & PREFIX_UNSIGNED) {
+ *type_obj = &ffi_type_uint;
+ }
+ else {
+ *type_obj = &ffi_type_sint;
+ }
+ break;
+ case (INTVAL)'l':
+ translation[(*translation_count) - 1] = 'l';
+ type[(*pmc_count)++] = 'I';
+ if (prefix & PREFIX_UNSIGNED) {
+ *type_obj = &ffi_type_ulong;
+ }
+ else {
+ *type_obj = &ffi_type_slong;
+ }
+ break;
+ case (INTVAL)'q':
+ translation[(*translation_count) - 1] = 'q';
+ type[(*pmc_count)++] = 'I';
+ if (prefix & PREFIX_UNSIGNED) {
+ *type_obj = &ffi_type_uint64;
+ }
+ else {
+ *type_obj = &ffi_type_sint64;
+ }
+ break;
+ case (INTVAL)'J': /* interpreter */
+ translation[(*translation_count) - 1] = 'J';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'p': /* push pmc->data */
+ translation[(*translation_count) - 1] = 'p';
+ type[(*pmc_count)++] = 'P';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'2':
+ translation[(*translation_count) - 1] = '2';
+ type[(*pmc_count)++] = 'P';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'3':
+ translation[(*translation_count) - 1] = '3';
+ type[(*pmc_count)++] = 'P';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'4':
+ translation[(*translation_count) - 1] = '4';
+ type[(*pmc_count)++] = 'P';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'P': /* push PMC * */
+ translation[(*translation_count) - 1] = 'P';
+ type[(*pmc_count)++] = 'P';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'V': /* push PMC * */
+ translation[(*translation_count) - 1] = 'V';
+ type[(*pmc_count)++] = 'P';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'S':
+ type[(*pmc_count)++] = 'S';
+ *type_obj = &ffi_type_pointer;
+ case (INTVAL)'t':
+ translation[(*translation_count) - 1] = 't';
+ type[(*pmc_count)++] = 'S';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'v':
+ type[(*pmc_count)++] = 'v';
+ *type_obj = &ffi_type_void;
+ break;
+#if (DOUBLE_SIZE == 4) /* FLOATVAL is a float */
+ case (INTVAL)'N':
+#endif
+ case (INTVAL)'f':
+ translation[(*translation_count) - 1] = 'f';
+ type[(*pmc_count)++] = 'N';
+ *type_obj = &ffi_type_float;
+ break;
+#if (DOUBLE_SIZE == 8) /* FLOATVAL is a double */
+ case (INTVAL)'N':
+#endif
+ case (INTVAL)'d':
+ translation[(*translation_count) - 1] = 'd';
+ type[(*pmc_count)++] = 'N';
+ *type_obj = &ffi_type_double;
+ break;
+#if (DOUBLE_SIZE > 8) /* FLOATVAL is a long double */
+ case (INTVAL)'N':
+#endif
+ case (INTVAL)'D':
+ translation[(*translation_count) - 1] = 'D';
+ type[(*pmc_count)++] = 'N';
+ *type_obj = &ffi_type_longdouble;
+ break;
+ case (INTVAL)'O': /* push PMC * invocant */
+ *type_obj = &ffi_type_pointer;
+ type[(*pmc_count)++] = 'P';
+ type[(*pmc_count)++] = 'i';
+ break;
+ case (INTVAL)'@': /* push PMC * slurpy */
+ *type_obj = &ffi_type_pointer;
+ type[(*pmc_count)++] = 'P';
+ type[(*pmc_count)++] = 's';
+ break;
+ default:
+ Parrot_ex_throw_from_c_args(interp, NULL,
+ EXCEPTION_JIT_ERROR,
+ "Unknown param Signature %c\n", (char)c);
+ break;
+ }
+ i++;
+
+ if (i < sig_length)
+ c = Parrot_str_indexed(interp, sig, i);
+ else
+ return i;
+ }
+ else {
+ Parrot_ex_throw_from_c_args(interp, NULL,
+ EXCEPTION_JIT_ERROR,
+ "Unknown param Signature %c\n", (char)c);
+ }
+
+ /*
+ * Parse postfix ops
+ * TODO: Parse postfix ops, currently I skip them.
+ */
+ while (IS_POSTFIX(c)) {
+ i++;
+ if (i < sig_length)
+ c = Parrot_str_indexed(interp, sig, i);
+ else
+ return i;
+ }
+
+ if ((i < sig_length) && (c == (INTVAL)'|')) {
+ /* Its a union, parse it special. */
+ }
+ else {
+ done = 1;
+ }
+ }
+
+ return i;
+}
+
+/*
+
+=item C<static INTVAL parse_prefix(INTVAL c)>
+
+Parse a prefix character.
+
+=cut
+
+*/
+
+static INTVAL
+parse_prefix(INTVAL c) {
+ switch (c) {
+ case '*':
+ return PREFIX_POINTER;
+ break;
+ case 'u':
+ return PREFIX_UNSIGNED;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return 0;
+}
+
+/*
+
+=item C<static size_t parse_structure(PARROT_INTERP, STRING* sig, size_t start,
+ size_t sig_length, ffi_type **type_obj, char* pmc_type)>
+
+Parses a stucture.
+TODO: This should auto inflate to an UnmanagedStruct or a ManagedStruct in the future.
+
+=cut
+
+*/
+
+static size_t
+parse_structure(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length,
+ ffi_type **type_obj, char* pmc_type) {
+ size_t i = start;
+ size_t struct_len = structure_length(interp, sig, start, sig_length);
+ size_t element_counter = 0;
+ INTVAL c;
+
+ *type_obj = (ffi_type*)mem_internal_allocate_typed(ffi_type*);
+ (*type_obj)->elements = mem_internal_allocate_n_zeroed_typed(struct_len + 1, ffi_type*);
+
+ (*type_obj)->size = (*type_obj)->alignment = 0;
+ (*type_obj)->type = FFI_TYPE_STRUCT;
+
+ c = Parrot_str_indexed(interp, sig, i);
+ while (i < sig_length && IS_NOT_END_CIRCUMFIX(c)) {
+ i = parse_identifier(interp, sig, i, sig_length,
+ &(*type_obj)->elements[element_counter],
+ NULL, 0, NULL, 0);
+ element_counter++;
+ c = Parrot_str_indexed(interp, sig, i);
+ }
+
+ (*type_obj)->elements[struct_len] = NULL;
+
+ return i;
+}
+
+/*
+
+=item C<static size_t structure_length(PARROT_INTERP, STRING* sig,
+ size_t start, size_t sig_length)>
+
+Calculates the number of items in a stucture for size purposes.
+
+=cut
+
+*/
+
+static size_t
+structure_length(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length) {
+ size_t len = 0;
+ size_t i = start;
+ INTVAL depth = 0;
+ INTVAL c = Parrot_str_indexed(interp, sig, i);
+ while (i < sig_length && depth != -1) {
+ if (IS_START_CIRCUMFIX(c)) depth++;
+ else if (IS_END_CIRCUMFIX(c)) depth--;
+ else if (depth == 0 && (IS_TYPE(c))) len++;
+ i++;
+ c = Parrot_str_indexed(interp, sig, i);
+ }
+
+ return len;
+}
+
+/*
+
+=item C<static size_t find_matching(PARROT_INTERP, STRING* sig, size_t start,
+ size_t sig_length, INTVAL start_character, INTVAL end_character)>
+
+Find matching symbols, used for finding the start and stop of a stucture, it is
+also recursive to handle structures inside of structures.
+
+=cut
+
+*/
+
+static size_t
+find_matching(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length,
+ INTVAL start_character, INTVAL end_character) {
+ size_t i = start;
+ INTVAL c = Parrot_str_indexed(interp, sig, i);
+ while (i < sig_length && c != end_character) {
+ if (c == start_character)
+ i = find_matching(interp, sig, i, sig_length, start_character, end_character);
+ i++;
+ c = Parrot_str_indexed(interp, sig, i);
+ }
+
+ return i;
+}
+
+/*
+
+=item C<size_t count_args(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length)>
+
+Counts the number of arguments from a given starting point. It only counts
+identiers, not prefix, infix or postfix modifiers. Structures are considered as
+1 item in most cases.
+
+=cut
+
+*/
+
+static size_t
+count_args(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length) {
+ size_t length = 0;
+ size_t i = start;
+
+ while (i < sig_length) {
+ const INTVAL c = Parrot_str_indexed(interp, sig, i);
+ if (IS_START_CIRCUMFIX(c)) {
+ i = find_matching(interp, sig, i + 1, sig_length, '(', ')');
+ length++;
+ }
+ else if (IS_TYPE(c)) {
+ length++;
+ }
+ i++;
+ }
+
+ return length;
+}
+
+static void
+pcc_params(PARROT_INTERP, ARGIN(STRING *sig), ARGMOD(Parrot_NCI_attributes *nci_info),
+ size_t sig_length)
+{
+ ASSERT_ARGS(pcc_params)
+
+ /* NCI and PCC have a 1 to 1 mapping except an
+ extra char in PCC for invocant and slurpy */
+ size_t buf_length = sig_length + 2 + 1;
+
+ /* avoid malloc churn on common signatures */
+ char static_buf[16];
+ char * const sig_buf = sig_length <= sizeof static_buf ?
+ static_buf :
+ (char *)mem_sys_allocate(buf_length);
+
+ size_t j = 0;
+ size_t i;
+
+ for (i = 0; i < sig_length; ++i) {
+ const INTVAL c = Parrot_str_indexed(interp, sig, i);
+
+ PARROT_ASSERT(j < buf_length - 1);
+
+ switch (c) {
+ case (INTVAL)'0': /* null ptr or such - doesn't consume a reg */
+ break;
+ case (INTVAL)'f':
+ case (INTVAL)'N':
+ case (INTVAL)'d':
+ sig_buf[j++] = 'N';
+ break;
+ case (INTVAL)'I': /* INTVAL */
+ case (INTVAL)'l': /* long */
+ case (INTVAL)'i': /* int */
+ case (INTVAL)'s': /* short */
+ case (INTVAL)'c': /* char */
+ sig_buf[j++] = 'I';
+ break;
+ case (INTVAL)'S':
+ case (INTVAL)'t': /* string, pass a cstring */
+ sig_buf[j++] = 'S';
+ break;
+ case (INTVAL)'J': /* interpreter */
+ break;
+ case (INTVAL)'p': /* push pmc->data */
+ case (INTVAL)'P': /* push PMC * */
+ case (INTVAL)'V': /* push PMC * */
+ case (INTVAL)'2':
+ case (INTVAL)'3':
+ case (INTVAL)'4':
+ sig_buf[j++] = 'P';
+ break;
+ case (INTVAL)'v':
+ /* null return */
+ if (j == 0)
+ sig_buf[j++] = '\0';
+ break;
+ case (INTVAL)'O': /* push PMC * invocant */
+ sig_buf[j++] = 'P';
+ sig_buf[j++] = 'i';
+ break;
+ case (INTVAL)'@': /* push PMC * slurpy */
+ sig_buf[j++] = 'P';
+ sig_buf[j++] = 's';
+ break;
+ case (INTVAL)'b': /* buffer (void*) pass Buffer_bufstart(SReg) */
+ case (INTVAL)'B': /* buffer (void**) pass &Buffer_bufstart(SReg) */
+ sig_buf[j++] = 'S';
+ break;
+ default:
+ Parrot_ex_throw_from_c_args(interp, NULL,
+ EXCEPTION_JIT_ERROR,
+ "Unknown param Signature %c\n", (char)c);
+ break;
+ }
+ }
+
+ PARROT_ASSERT(j < buf_length);
+ sig_buf[j++] = '\0';
+
+
+ nci_info->pcc_return_signature =
+ Parrot_str_new(interp, sig_buf, 1);
+
+ nci_info->pcc_params_signature = j ?
+ Parrot_str_new(interp, sig_buf + 1, j - 1) :
+ CONST_STRING(interp, "");
+
+ if (sig_buf != static_buf)
+ mem_sys_free(sig_buf);
+}
+
+PARROT_IGNORABLE_RESULT
+static ffi_cif*
+build_libffi_func(PARROT_INTERP, ARGMOD(Parrot_NCI_attributes *nci_info))
+{
+ ASSERT_ARGS(build_func)
+
+ STRING * const key = nci_info->signature;
+ const size_t key_length = Parrot_str_byte_length(interp, key);
+
+ INTVAL r = parse_sig(interp, nci_info->signature, key_length, nci_info);
+
+ return (ffi_cif*)nci_info->cif;
+}
+
+/* actually build the NCI thunk */
+
+PARROT_IGNORABLE_RESULT
+static nci_thunk_t
+build_func(PARROT_INTERP, ARGMOD(Parrot_NCI_attributes *nci_info))
+{
+ ASSERT_ARGS(build_func)
+
+ STRING * const key = nci_info->signature;
+ const size_t key_length = Parrot_str_byte_length(interp, key);
+
+ pcc_params(interp, key, nci_info, key_length);
+
+ /* Arity is length of that string minus one (the return type). */
+ nci_info->arity = key_length - 1;
+
+ /* Build call function. */
+ nci_info->fb_info = build_call_func(interp, key);
+ nci_info->func = F2DPTR(VTABLE_get_pointer(interp, nci_info->fb_info));
+
+ return (nci_thunk_t)nci_info->func;
+}
+
+
+pmclass NCI auto_attrs provides invokable {
+ /* NCI thunk handling attributes */
+ /* NCI thunk handling attributes */
+ ATTR STRING *signature; /* The signature. */
+ ATTR void *func; /* Function pointer to call. */
+ ATTR void *orig_func;
+ ATTR PMC *fb_info; /* Frame-builder info */
+ ATTR void *cif; /* Function interface */
+ ATTR void *arg_types; /* Used for building the libffi call interface */
+
+ /* Parrot Sub-ish attributes */
+ ATTR STRING *pcc_params_signature;
+ ATTR STRING *pcc_return_signature;
+ ATTR void *arg_translation;
+ ATTR void *return_translation;
+ ATTR INTVAL arity; /* Cached arity of the NCI. */
+
+ /* MMD fields */
+ ATTR STRING *long_signature; /* The full signature. */
+ ATTR PMC *multi_sig; /* type tuple array (?) */
+
+/*
+
+=item C<METHOD get_multisig()>
+
+Return the MMD signature PMC, if any or a Null PMC.
+
+=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<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() {
+ /* Mark that we're not a raw NCI. */
+ PObj_flag_CLEAR(private2, SELF);
+ PObj_custom_mark_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) {
+ SET_ATTR_orig_func(INTERP, SELF, ptr);
+ PObj_flag_SET(private2, SELF);
+ }
+
+ VTABLE void *get_pointer() {
+ return PARROT_NCI(SELF)->orig_func;
+ }
+
+ VTABLE void set_pointer_keyed_str(STRING *key, void *func) {
+ Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
+
+ /* Store the original function and signature. */
+ SET_ATTR_func(INTERP, SELF, func);
+
+ /* ensure that the STRING signature is constant */
+ if (!PObj_constant_TEST(key)) {
+ char * const key_c = Parrot_str_to_cstring(INTERP, key);
+ const size_t key_length = Parrot_str_byte_length(interp, key);
+ key = string_make(interp, key_c, key_length, NULL, 0);
+ Parrot_str_free_cstring(key_c);
+ }
+
+ nci_info->signature = key;
+ }
+
+/*
+
+=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->fb_info);
+ Parrot_gc_mark_STRING_alive(interp, nci_info->signature);
+ Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_params_signature);
+ Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_return_signature);
+ Parrot_gc_mark_STRING_alive(interp, nci_info->long_signature);
+ Parrot_gc_mark_PMC_alive(interp, nci_info->multi_sig);
+ }
+ }
+
+/*
+
+=item C<void destroy()>
+
+Free all of the memory used internally to store various things, like libffi call signatures.
+
+=cut
+
+*/
+
+ VTABLE void destroy() {
+ if (PARROT_NCI(SELF)) {
+ Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
+ mem_sys_free(nci_info->cif);
+ mem_sys_free(nci_info->arg_translation);
+ mem_sys_free(nci_info->arg_types);
+ mem_sys_free(nci_info->return_translation);
+ }
+ }
+
+
+/*
+
+=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);
+ Parrot_NCI_attributes *nci_info_ret;
+ void *cif;
+
+ PMC * const ret = Parrot_pmc_new(INTERP, SELF->vtable->base_type);
+ 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->cif = nci_info_self->cif;
+ 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) & 0x7);
+
+ return ret;
+ }
+
+/*
+
+=item C<INTVAL defined()>
+
+Returns whether the NCI is defined.
+
+=cut
+
+*/
+
+ VTABLE INTVAL defined() {
+ 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);
+ char *sig_str;
+ PMC *cont;
+ INTVAL return_size = sizeof (void*);
+ PMC *ctx = CURRENT_CONTEXT(interp);
+ PMC *call_object = Parrot_pcc_get_signature(interp, ctx);
+ void (*func)(void*,void*,void*); /* a function pointer for our function to call */
+
+ if (PObj_flag_TEST(private2, SELF)) {
+ void *orig_func;
+ PMC *fb_info;
+ GET_ATTR_orig_func(INTERP, SELF, orig_func);
+ GET_ATTR_fb_info(INTERP, SELF, fb_info);
+
+ func = (void (*)(void*, void*, void*))orig_func;
+
+ if (!func) {
+ /* build the thunk only when necessary */
+ func = (void (*)(void*, void*, void*))build_func(interp, nci_info);
+
+ if (!func)
+ Parrot_ex_throw_from_c_args(INTERP, NULL,
+ EXCEPTION_INVALID_OPERATION,
+ "attempt to call NULL function");
+ }
+
+ func = (void (*)(void*, void*, void*))(orig_func);
+ func(INTERP, SELF, fb_info);
+ }
+ else {
+ PMC *positional, *arg_iter;
+ STRING *void_return;
+ void **values, **middle_man = NULL, **pcc_ptr, **translation_pointers = NULL, **pcc_val = NULL;
+ void *return_data;
+ size_t count, i, j_offset;
+ char *tmp_sig;
+ ffi_cif *cif, pcc_cif;
+ ffi_type **pcc_args;
+
+ cif = (ffi_cif*)nci_info->cif;
+ func = (void (*)(void*, void*, void*))nci_info->func;
+
+ if (!cif) {
+ /* build the thunk only when necessary */
+ cif = build_libffi_func(interp, nci_info);
+
+ if (!cif && !func)
+ Parrot_ex_throw_from_c_args(INTERP, NULL,
+ EXCEPTION_INVALID_OPERATION,
+
+ "attempt to call NULL function");
+ }
+
+ if (nci_info->arity > 0) {
+ size_t pcc_argc, pcc_values_offset, pcc_values_size, values_size;
+ /* Function has arguments */
+ pcc_args = mem_internal_allocate_n_zeroed_typed(nci_info->arity + 4, ffi_type*);
+ tmp_sig = Parrot_str_to_cstring(interp, nci_info->pcc_params_signature);
+
+ pcc_args[0] = &ffi_type_pointer;
+ pcc_args[1] = &ffi_type_pointer;
+ pcc_args[2] = &ffi_type_pointer;
+ pcc_values_size = 0;
+ values_size = 0;
+ pcc_argc = Parrot_str_length(interp, nci_info->pcc_params_signature);
+
+ /* Add up the size of memory needed for the actual call */
+ for (i = 0; i < (size_t)nci_info->arity; i++) {
+ values_size += cif->arg_types[i]->size;
+ }
+
+ pcc_ptr = (void**)mem_internal_allocate_n_zeroed_typed(pcc_argc + 4, void*);
+
+ /* Setup Parrot_pcc_fill_params_from_c_args required arguments */
+ pcc_ptr[0] = &interp;
+ pcc_ptr[1] = &call_object;
+ pcc_ptr[2] = &tmp_sig;
+
+ pcc_val = (void**)mem_internal_allocate_n_zeroed_typed(pcc_argc, void*);
+ values = (void**)mem_internal_allocate_zeroed(values_size + sizeof(void*));
+ /* Middle man is used to contain */
+ middle_man = mem_internal_allocate_n_zeroed_typed(nci_info->arity, void*);
+
+ /* Add up the size of the pcc arguments */
+ for (i = 0; i < pcc_argc; i++) {
+ pcc_args[i + 3] = &ffi_type_pointer;
+ if (tmp_sig[i] == 'N') {
+ pcc_val[i] = malloc(sizeof(FLOATVAL));
+ pcc_ptr[i+3] = &pcc_val[i];
+ }
+ else if (tmp_sig[i] == 'I') {
+ pcc_val[i] = malloc(sizeof(INTVAL));
+ pcc_ptr[i+3] = &pcc_val[i];
+ }
+ else if (tmp_sig[i] == 'P' || tmp_sig[i] == 'S') {
+ pcc_val[i] = malloc(sizeof(void*));
+ pcc_ptr[i+3] = &pcc_val[i];
+ }
+ }
+
+ if (ffi_prep_cif(&pcc_cif, FFI_DEFAULT_ABI, 3 + pcc_argc,
+ &ffi_type_void, pcc_args) != FFI_OK) {
+ Parrot_ex_throw_from_c_args(INTERP, NULL,
+ EXCEPTION_INVALID_OPERATION,
+ "Bad signature generated for Parrot_pcc_fill_params_from_c_args in NCI");
+ }
+
+ ffi_call(&pcc_cif, FFI_FN(Parrot_pcc_fill_params_from_c_args), NULL, pcc_ptr);
+
+ Parrot_str_free_cstring(tmp_sig);
+
+ /*
+ * Apply Argument Transformations
+ * this is mostly to transform STRING* into char*
+ * and add the parrot interp argument if it needs it
+ * but other transformations might apply later, like packing an
+ * object into a ManagedStruct
+ */
+ j_offset = 0;
+ translation_pointers = mem_internal_allocate_n_zeroed_typed(nci_info->arity, void*);
+ for (i = 0; i < (size_t)nci_info->arity; i++) {
+ switch ((INTVAL)((char*)nci_info->arg_translation)[i]) {
+ case 'J':
+ values[i] = &interp;
+ j_offset++;
+ break;
+ case 't':
+ if (STRING_IS_NULL(*(STRING**)pcc_val[i - j_offset])) {
+ translation_pointers[i] = (char*) NULL;
+ }
+ else {
+ translation_pointers[i] = Parrot_str_to_cstring(interp, *(STRING**)pcc_val[i - j_offset]);
+ }
+ values[i] = &translation_pointers[i];
+ break;
+ case 'B':
+ if (STRING_IS_NULL(*(STRING**)pcc_val[i - j_offset])) {
+ translation_pointers[i] = (char*) NULL;
+ }
+ else {
+ translation_pointers[i] = Parrot_str_to_cstring(interp, *(STRING**)pcc_val[i - j_offset]);
+ }
+ middle_man[i] = &translation_pointers[i];
+ values[i] = &middle_man[i];
+ break;
+ case 'b':
+ values[i] = &Buffer_bufstart(*(STRING**)pcc_val[i - j_offset]);
+ break;
+ case 'c':
+ translation_pointers[i] = mem_internal_allocate_zeroed_typed(char);
+ *((char**)translation_pointers)[i] = (char)*(INTVAL*)pcc_val[i - j_offset];
+ values[i] = translation_pointers[i];
+ break;
+ case '2':
+ translation_pointers[i] = mem_internal_allocate_zeroed_typed(pmc_holder_t);
+ ((pmc_holder_t*)translation_pointers[i])->p = *(PMC**)pcc_val[i - j_offset];
+ ((pmc_holder_t*)translation_pointers[i])->ival = (INTVAL*)mem_internal_allocate_zeroed_typed(short);
+ *((pmc_holder_t*)translation_pointers[i])->ival = (short)VTABLE_get_integer(interp, *(PMC**)pcc_ptr[i - j_offset]);
+ values[i] = &((pmc_holder_t*)translation_pointers[i])->ival;
+ break;
+ case 's':
+ translation_pointers[i] = mem_internal_allocate_zeroed_typed(short);
+ *((short**)translation_pointers)[i] = (short)*(INTVAL*)pcc_val[i - j_offset];
+ values[i] = translation_pointers[i];
+ break;
+ case '3':
+ translation_pointers[i] = mem_internal_allocate_zeroed_typed(pmc_holder_t);
+ ((pmc_holder_t*)translation_pointers[i])->p = *(PMC**)pcc_val[i - j_offset];
+ ((pmc_holder_t*)translation_pointers[i])->ival = (INTVAL*)mem_internal_allocate_zeroed_typed(int);
+ *((pmc_holder_t*)translation_pointers[i])->ival = (int)VTABLE_get_integer(interp, *(PMC**)pcc_val[i - j_offset]);
+ values[i] = &((pmc_holder_t*)translation_pointers[i])->ival;
+ break;
+ case 'i':
+ translation_pointers[i] = mem_internal_allocate_zeroed_typed(int);
+ *((int**)translation_pointers)[i] = (int)*(INTVAL*)pcc_val[i - j_offset];
+ values[i] = translation_pointers[i];
+ break;
+ case '4':
+ translation_pointers[i] = mem_internal_allocate_zeroed_typed(pmc_holder_t);
+ ((pmc_holder_t*)translation_pointers[i])->p = *(PMC**)pcc_val[i - j_offset];
+ ((pmc_holder_t*)translation_pointers[i])->ival = (INTVAL*)mem_internal_allocate_zeroed_typed(long);
+ *((pmc_holder_t*)translation_pointers[i])->ival = (long)VTABLE_get_integer(interp, *(PMC**)pcc_val[i - j_offset]);
+ values[i] = &((pmc_holder_t*)translation_pointers[i])->ival;
+ break;
+ case 'l':
+ translation_pointers[i] = mem_internal_allocate_zeroed_typed(long);
+ *((long**)translation_pointers)[i] = (long)*(INTVAL*)pcc_val[i - j_offset];
+ values[i] = translation_pointers[i];
+ break;
+ case 'q':
+ translation_pointers[i] = mem_internal_allocate_zeroed_typed(long long);
+ *((long long**)translation_pointers)[i] = (long long)*(INTVAL*)pcc_val[i - j_offset];
+ values[i] = translation_pointers[i];
+ break;
+ case 'V':
+ translation_pointers[i] = mem_internal_allocate_zeroed_typed(pmc_holder_t);
+ ((pmc_holder_t*)translation_pointers[i])->p = *(PMC**)pcc_val[i - j_offset];
+ ((pmc_holder_t*)translation_pointers[i])->pval = (void**)mem_internal_allocate_zeroed_typed(void*);
+ *((pmc_holder_t*)translation_pointers[i])->pval = PMC_IS_NULL(*(PMC**)pcc_ptr[i - j_offset]) ?
+ (void *)NULL : (void*)VTABLE_get_pointer(interp, *(PMC**)pcc_val[i - j_offset]);
+ values[i] = &((pmc_holder_t*)translation_pointers[i])->pval;
+ break;
+ case 'P':
+ translation_pointers[i] = *(PMC**)pcc_val[i - j_offset];
+ values[i] = &translation_pointers[i];
+ break;
+ case 'p':
+ translation_pointers[i] = PMC_IS_NULL(*(PMC**)pcc_ptr[i - j_offset]) ?
+ (void *)NULL : VTABLE_get_pointer(interp, *(PMC**)pcc_val[i - j_offset]);
+ values[i] = &translation_pointers[i];
+ break;
+ case 'f':
+ translation_pointers[i] = mem_internal_allocate_zeroed_typed(float);
+ *((float**)translation_pointers)[i] = (float)*(FLOATVAL*)pcc_val[i - j_offset];
+ values[i] = translation_pointers[i];
+ break;
+ case 'd':
+ translation_pointers[i] = mem_internal_allocate_zeroed_typed(double);
+ *((double**)translation_pointers)[i] = *(FLOATVAL*)pcc_val[i - j_offset];
+ values[i] = translation_pointers[i];
+ break;
+ case ' ':
+ default:
+ break;
+ }
+ }
+
+ if (pcc_args) {
+ mem_sys_free(pcc_args);
+ }
+ if (pcc_ptr) {
+ mem_sys_free(pcc_ptr);
+ }
+ if (pcc_val) {
+ for (i = 0; i < pcc_argc; i++) {
+ mem_sys_free(pcc_val[i]);
+ }
+ mem_sys_free(pcc_val);
+ }
+ }
+ else {
+ /* No arguments */
+ values = NULL;
+ }
+
+ /*
+ * This will allow for any type of datat to be returned.
+ * Including one day Structures
+ */
+ return_data = mem_internal_allocate_zeroed(cif->rtype->size);
+
+ ffi_call(cif, FFI_FN(func), return_data, values);
+
+ if (cif->rtype != &ffi_type_void) {
+ char *s;
+ PMC *ret_object;
+ s = Parrot_str_to_cstring(interp, nci_info->pcc_return_signature);
+ switch (*(char*)nci_info->return_translation) {
+ case 'p':
+ {
+ PMC *final_destination = PMCNULL;
+
+ if (*(void**)return_data != NULL) {
+ final_destination = Parrot_pmc_new(interp, enum_class_UnManagedStruct);
+ VTABLE_set_pointer(interp, final_destination, *(void**)return_data);
+ }
+ ret_object = Parrot_pcc_build_call_from_c_args(interp,
+ call_object,
+ s, final_destination);
+
+ }
+ break;
+ case 't':
+ {
+ STRING *final_destination = Parrot_str_new(interp, *(char**)return_data, 0);
+ ret_object = Parrot_pcc_build_call_from_c_args(interp,
+ call_object,
+ s, final_destination);
+ }
+ break;
+ case 'f':
+ {
+ FLOATVAL final_destination = *(float*)return_data;
+
+ ret_object = Parrot_pcc_build_call_from_c_args(interp,
+ call_object,
+ s, final_destination);
+ }
+ break;
+ default:
+ switch (s[0]) {
+ case 'N':
+ ret_object = Parrot_pcc_build_call_from_c_args(interp,
+ call_object,
+ s, *(FLOATVAL*)return_data);
+ case 'I':
+ ret_object = Parrot_pcc_build_call_from_c_args(interp,
+ call_object,
+ s, *(INTVAL*)return_data);
+ case 'P':
+ case 'S':
+ default:
+ ret_object = Parrot_pcc_build_call_from_c_args(interp,
+ call_object,
+ s, *(void**)return_data);
+ }
+ break;
+ }
+ Parrot_str_free_cstring(s);
+ }
+
+ /*
+ * Free memory used for cstrings,
+ * and any other translations that use temporary memory
+ */
+ for (i = 0; i < (size_t)nci_info->arity; i++) {
+ switch ((INTVAL)((char*)nci_info->arg_translation)[i]) {
+ case (INTVAL)'B':
+ if (translation_pointers[i]) {
+ Parrot_str_free_cstring((char*)translation_pointers[i]);
+ }
+ break;
+ case (INTVAL)'t':
+ if (translation_pointers[i]) {
+ Parrot_str_free_cstring((char*)translation_pointers[i]);
+ }
+ break;
+ case (INTVAL)'2':
+ VTABLE_set_integer_native(interp,
+ ((pmc_holder_t*)translation_pointers[i])->p,
+ (INTVAL)*(short*)((pmc_holder_t*)translation_pointers[i])->ival);
+ if (translation_pointers[i]) {
+ mem_sys_free(translation_pointers[i]);
+ }
+ break;
+ case (INTVAL)'3':
+ VTABLE_set_integer_native(interp,
+ ((pmc_holder_t*)translation_pointers[i])->p,
+ (INTVAL)*(int*)((pmc_holder_t*)translation_pointers[i])->ival);
+ if (translation_pointers[i]) {
+ mem_sys_free(translation_pointers[i]);
+ }
+ break;
+ case (INTVAL)'4':
+ VTABLE_set_integer_native(interp,
+ ((pmc_holder_t*)translation_pointers[i])->p,
+ (INTVAL)*(long*)((pmc_holder_t*)translation_pointers[i])->ival);
+ if (translation_pointers[i]) {
+ mem_sys_free(translation_pointers[i]);
+ }
+ break;
+ case (INTVAL)'V':
+ VTABLE_set_pointer(interp,
+ ((pmc_holder_t*)translation_pointers[i])->p,
+ (PMC*)*((pmc_holder_t*)translation_pointers[i])->pval);
+ if (translation_pointers[i]) {
+ mem_sys_free(translation_pointers[i]);
+ }
+ break;
+ case (INTVAL)'d':
+ case (INTVAL)'c':
+ case (INTVAL)'s':
+ case (INTVAL)'i':
+ case (INTVAL)'l':
+ case (INTVAL)'q':
+ if (translation_pointers[i]) {
+ mem_sys_free(translation_pointers[i]);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (nci_info->arity > 0 && middle_man) {
+ mem_sys_free(middle_man);
+ }
+ if (return_data) {
+ mem_sys_free(return_data);
+ }
+ if (values) {
+ mem_sys_free(values);
+ }
+ }
+
+ 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 = 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, nci_info);
+ return (INTVAL)nci_info->func;
+ }
+
+/*
+
+=item C<INTVAL get_bool()>
+
+Returns the boolean value of the pointer.
+
+=cut
+
+*/
+
+ VTABLE INTVAL get_bool() {
+ Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
+ return (0 != (INTVAL)nci_info->cif);
+ }
+
+/*
+
+=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);
+ INTVAL arity = 0;
+
+ if (nci_info) {
+ if (PObj_flag_TEST(private2, SELF)) {
+ }
+ else {
+ if (!nci_info->cif) {
+ nci_info->cif = build_libffi_func(interp, nci_info);
+ }
+ if (nci_info->cif) {
+ 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>.
+
+=head1 HISTORY
+
+Initial revision by sean 2002/08/04.
+
+Updates by John Harrison, Summer 2010, GSoC.
+
+=cut
+
+*/
+
+/*
+ * Local variables:
+ * c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */
+
+
+
View
478 config/gen/libffi/nci.pmc.in
@@ -0,0 +1,478 @@
+/*
+Copyright (C) 2001-2010, Parrot 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
+
+*/
+
+/* 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,
+ ARGMOD(Parrot_NCI_attributes *nci_info))
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ FUNC_MODIFIES(*nci_info);
+
+static void pcc_params(PARROT_INTERP,
+ ARGIN(STRING *sig),
+ ARGMOD(Parrot_NCI_attributes *nci_info),
+ size_t sig_length)
+ __attribute__nonnull__(1)
+ __attribute__nonnull__(2)
+ __attribute__nonnull__(3)
+ FUNC_MODIFIES(*nci_info);
+
+#define ASSERT_ARGS_build_func __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(nci_info))
+#define ASSERT_ARGS_pcc_params __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+ PARROT_ASSERT_ARG(interp) \
+ , PARROT_ASSERT_ARG(sig) \
+ , PARROT_ASSERT_ARG(nci_info))
+/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
+/* HEADERIZER END: static */
+
+
+static void
+pcc_params(PARROT_INTERP, ARGIN(STRING *sig), ARGMOD(Parrot_NCI_attributes *nci_info),
+ size_t sig_length)
+{
+ ASSERT_ARGS(pcc_params)
+
+ /* NCI and PCC have a 1 to 1 mapping except an
+ extra char in PCC for invocant and slurpy */
+ size_t buf_length = sig_length + 2 + 1;
+
+ /* avoid malloc churn on common signatures */
+ char static_buf[16];
+ char * const sig_buf = sig_length <= sizeof static_buf ?
+ static_buf :
+ (char *)mem_sys_allocate(buf_length);
+
+ size_t j = 0;
+ size_t i;
+
+ for (i = 0; i < sig_length; ++i) {
+ const INTVAL c = Parrot_str_indexed(interp, sig, i);
+
+ PARROT_ASSERT(j < buf_length - 1);
+
+ switch (c) {
+ case (INTVAL)'0': /* null ptr or such - doesn't consume a reg */
+ break;
+ case (INTVAL)'f':
+ case (INTVAL)'N':
+ case (INTVAL)'d':
+ sig_buf[j++] = 'N';
+ break;
+ case (INTVAL)'I': /* INTVAL */
+ case (INTVAL)'l': /* long */
+ case (INTVAL)'i': /* int */
+ case (INTVAL)'s': /* short */
+ case (INTVAL)'c': /* char */
+ sig_buf[j++] = 'I';
+ break;
+ case (INTVAL)'S':
+ case (INTVAL)'t': /* string, pass a cstring */
+ sig_buf[j++] = 'S';
+ break;
+ case (INTVAL)'J': /* interpreter */
+ break;
+ case (INTVAL)'p': /* push pmc->data */
+ case (INTVAL)'P': /* push PMC * */
+ case (INTVAL)'V': /* push PMC * */
+ case (INTVAL)'2':
+ case (INTVAL)'3':
+ case (INTVAL)'4':
+ sig_buf[j++] = 'P';
+ break;
+ case (INTVAL)'v':
+ /* null return */
+ if (j == 0)
+ sig_buf[j++] = '\0';
+ break;
+ case (INTVAL)'O': /* push PMC * invocant */
+ sig_buf[j++] = 'P';
+ sig_buf[j++] = 'i';
+ break;
+ case (INTVAL)'@': /* push PMC * slurpy */
+ sig_buf[j++] = 'P';
+ sig_buf[j++] = 's';
+ break;
+ case (INTVAL)'b': /* buffer (void*) pass Buffer_bufstart(SReg) */
+ case (INTVAL)'B': /* buffer (void**) pass &Buffer_bufstart(SReg) */
+ sig_buf[j++] = 'S';
+ break;
+ default:
+ Parrot_ex_throw_from_c_args(interp, NULL,
+ EXCEPTION_JIT_ERROR,
+ "Unknown param Signature %c\n", (char)c);
+ break;
+ }
+ }
+
+ PARROT_ASSERT(j < buf_length);
+ sig_buf[j++] = '\0';
+
+
+ nci_info->pcc_return_signature =
+ Parrot_str_new(interp, sig_buf, 1);
+
+ nci_info->pcc_params_signature = j ?
+ Parrot_str_new(interp, sig_buf + 1, j - 1) :
+ CONST_STRING(interp, "");
+
+ if (sig_buf != static_buf)
+ mem_sys_free(sig_buf);
+}
+
+/* actually build the NCI thunk */
+
+PARROT_IGNORABLE_RESULT
+static nci_thunk_t
+build_func(PARROT_INTERP, ARGMOD(Parrot_NCI_attributes *nci_info))
+{
+ ASSERT_ARGS(build_func)
+
+ STRING * const key = nci_info->signature;
+ const size_t key_length = Parrot_str_byte_length(interp, key);
+
+ pcc_params(interp, key, nci_info, key_length);
+
+ /* Arity is length of that string minus one (the return type). */
+ nci_info->arity = key_length - 1;
+
+ /* Build call function. */
+ nci_info->fb_info = build_call_func(interp, key);
+ nci_info->func = F2DPTR(VTABLE_get_pointer(interp, nci_info->fb_info));
+
+ return (nci_thunk_t)nci_info->func;
+}
+
+
+pmclass NCI auto_attrs provides invokable {
+ /* NCI thunk handling attributes */
+ ATTR STRING *signature; /* The signature. */
+ ATTR void *func; /* Function pointer to call. */
+ ATTR PMC *fb_info; /* Frame-builder info */
+ ATTR void *orig_func; /* Function pointer
+ * used to create func */
+ /* Parrot Sub-ish attributes */
+ ATTR STRING *pcc_params_signature;
+ ATTR STRING *pcc_return_signature;
+ ATTR INTVAL arity; /* Cached arity of the NCI. */
+
+ /* MMD fields */
+ ATTR STRING *long_signature; /* The full signature. */
+ ATTR PMC *multi_sig; /* type tuple array (?) */
+
+/*
+
+=item C<METHOD get_multisig()>
+
+Return the MMD signature PMC, if any or a Null PMC.
+
+=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<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() {
+ /* Mark that we're not a raw NCI. */
+ PObj_flag_CLEAR(private2, SELF);
+ PObj_custom_mark_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) {
+ SET_ATTR_orig_func(INTERP, SELF, ptr);
+ PObj_flag_SET(private2, SELF);
+ }
+
+ VTABLE void *get_pointer() {
+ return PARROT_NCI(SELF)->orig_func;
+ }
+
+ VTABLE void set_pointer_keyed_str(STRING *key, void *func) {
+ Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
+
+ /* Store the original function and signature. */
+ SET_ATTR_orig_func(INTERP, SELF, func);
+
+ /* ensure that the STRING signature is constant */
+ if (!PObj_constant_TEST(key)) {
+ char * const key_c = Parrot_str_to_cstring(INTERP, key);
+ const size_t key_length = Parrot_str_byte_length(interp, key);
+ key = string_make(interp, key_c, key_length,
+ NULL, PObj_constant_FLAG);
+ Parrot_str_free_cstring(key_c);
+ }
+
+ nci_info->signature = key;
+ }
+
+/*
+
+=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->fb_info);
+ Parrot_gc_mark_STRING_alive(interp, nci_info->signature);
+ Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_params_signature);
+ Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_params_signature);
+ Parrot_gc_mark_STRING_alive(interp, nci_info->long_signature);
+ Parrot_gc_mark_PMC_alive(interp, nci_info->multi_sig);
+ }
+ }
+
+/*
+
+=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);
+ Parrot_NCI_attributes *nci_info_ret;
+ void *orig_func;
+
+ PMC * const ret = Parrot_pmc_new(INTERP, SELF->vtable->base_type);
+ 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) & 0x7);
+
+ return ret;
+ }
+
+/*
+
+=item C<INTVAL defined()>
+
+Returns whether the NCI is defined.
+
+=cut
+
+*/
+
+ VTABLE INTVAL defined() {
+ 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;
+ char *sig_str;
+ void *orig_func;
+ PMC *cont;
+
+ GET_ATTR_orig_func(INTERP, SELF, orig_func);
+ func = PObj_flag_TEST(private2, SELF)
+ ? (nci_thunk_t) D2FPTR(orig_func)
+ : (nci_thunk_t) D2FPTR(nci_info->func);
+
+ GET_ATTR_fb_info(INTERP, SELF, fb_info);
+
+ if (!func) {
+ /* build the thunk only when necessary */
+ func = build_func(interp, nci_info);
+
+ if (!func)
+ Parrot_ex_throw_from_c_args(INTERP, NULL,
+ EXCEPTION_INVALID_OPERATION,
+ "attempt to call NULL function");
+ }
+
+ func(INTERP, SELF, fb_info);
+ 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 = 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, nci_info);
+ return (INTVAL)nci_info->func;
+ }
+
+/*
+
+=item C<INTVAL get_bool()>
+
+Returns the boolean value of the pointer.
+
+=cut
+
+*/
+
+ VTABLE INTVAL get_bool() {
+ 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);
+ INTVAL arity = 0;
+
+ if (nci_info) {
+ if (!nci_info->func)
+ build_func(INTERP, nci_info);
+ if (nci_info->func) {
+ 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>.
+
+=head1 HISTORY
+
+Initial revision by sean 2002/08/04.
+
+=cut
+
+*/
+
+/*
+ * Local variables:
+ * c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */
View
1  lib/Parrot/Configure/Options/Conf.pm
@@ -101,6 +101,7 @@ External Library Options:
--without-gettext Build parrot without gettext support
--without-gmp Build parrot without GMP support
+ --without-libffi Build parrot without libffi support
--without-opengl Build parrot without OpenGL support (GL/GLU/GLUT)
--without-pcre Build parrot without pcre support
--without-zlib Build parrot without zlib support
View
2  lib/Parrot/Configure/Step/List.pm
@@ -61,11 +61,13 @@ my @steps = qw(
auto::ctags
auto::revision
auto::icu
+ auto::libffi
gen::config_h
gen::core_pmcs
gen::opengl
gen::makefiles
gen::platform
+ gen::libffi
gen::config_pm
);
View
1,084 src/pmc/nci.pmc
@@ -18,6 +18,9 @@ The vtable functions for the native C call functions.
*/
+/* Cheat with this include, for whatever reason the space is required */
+# include "ffi.h"
+
/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
@@ -49,6 +52,618 @@ static void pcc_params(PARROT_INTERP,
/* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
/* HEADERIZER END: static */
+static
+INTVAL
+parse_sig(PARROT_INTERP, STRING *sig, size_t sig_length, Parrot_NCI_attributes *nci_info);
+
+static
+size_t
+parse_return(PARROT_INTERP, STRING* sig, size_t sig_length,
+ Parrot_NCI_attributes * nci_info, ffi_type **return_type);
+
+static
+size_t
+parse_args(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length,
+ Parrot_NCI_attributes *nci_info, ffi_type ***arg_types);
+
+static
+size_t
+parse_identifier(PARROT_INTERP,
+ STRING* sig, size_t start, size_t end,
+ ffi_type** sig_obj,
+ char* pmc_type, size_t *pmc_count,
+ char* translation, size_t *translation_length);
+
+static
+size_t
+parse_structure(PARROT_INTERP, STRING* sig, size_t start, size_t end,
+ ffi_type** sig_obj, char* pmc_type);
+
+static
+INTVAL
+parse_prefix(INTVAL c);
+
+static
+size_t
+structure_length(PARROT_INTERP, STRING* sig, size_t start, size_t end);
+
+static
+size_t
+count_args(PARROT_INTERP, STRING* sig, size_t start, size_t end);
+
+static
+size_t
+find_matching(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length,
+ INTVAL start_character, INTVAL end_character);
+
+#define IS_DIGIT(x) (((x) == '0') || ((x) == '1') || ((x) == '2') || ((x) == '3') \
+ || ((x) == '4') || ((x) == '5') || ((x) == '6') || ((x) == '7') \
+ || ((x) == '8') || ((x) == '9'))
+
+#define IS_PREFIX(x) (((x) == '*') || ((x) == 'u'))
+
+#define IS_OLD_TYPE(x) (((x) == 'P') || ((x) == 'J') || ((x) == 'N') || ((x) == 'S') \
+ || ((x) == 'O') || ((x) == '@') || ((x) == 'B') || ((x) == 'p') \
+ || ((x) == '2') || ((x) == '3') || ((x) == '4') || ((x) == 'U') \
+ || ((x) == 'V'))
+
+#define IS_TYPE(x) (((x) == 'i') || ((x) == 'v') || ((x) == 'l') || ((x) == 't') \
+ || ((x) == 'c') || ((x) == 'b') || ((x) == 'f') || ((x) == 'd') \
+ || ((x) == 's') || IS_OLD_TYPE(x))
+
+#define IS_POSTFIX(x) ((x) == '{') /* || IS_DIGIT(x)) */
+#define IS_INFIX(x) ((x) == '|')
+#define IS_START_CIRCUMFIX(x) ((x) == '(')
+#define IS_END_CIRCUMFIX(x) ((x) == ')')
+#define IS_NOT_END_CIRCUMFIX(x) ((x) != ')')
+
+#define PREFIX_POINTER (1<<0)
+#define PREFIX_SIGNED ( 0)
+#define PREFIX_UNSIGNED (1<<1)
+#define PREFIX_NATIVE (1<<2)
+
+typedef struct pmc_holder_t {
+ PMC* p;
+ union {
+ INTVAL* ival;
+ void** pval;
+ };
+} pmc_holder_t;
+
+/*
+
+=item C<static INTVAL parse_sig(PARROT_INTERP, STRING *sig,
+ size_t sig_length, Parrot_NCI_attributes *nci_info)>
+
+Parse a full signature. All signatures should contain a return type and a list of
+arguments. "vv" Would be the shortest "void fn(void)" signature you can legally make.
+
+See C<parse_return> and C<parse_args> to see how the signature is broken down.
+
+=cut
+
+*/
+
+static INTVAL
+parse_sig(PARROT_INTERP, STRING *sig, size_t sig_length, Parrot_NCI_attributes *nci_info) {
+ ffi_cif cif;
+ ffi_type *return_type;
+ ffi_type **arg_types;
+
+ if (sig_length) {
+ size_t i = parse_return(interp, sig, sig_length, nci_info, &return_type);
+ if (i < sig_length)
+ parse_args(interp, sig, i, sig_length, nci_info, &arg_types);
+ else {
+ arg_types = mem_internal_allocate_n_zeroed_typed(1, ffi_type*);
+ arg_types[0] = &ffi_type_void;
+ nci_info->pcc_params_signature = string_make(interp, "", 1, NULL, 0);
+ nci_info->arg_translation = NULL;
+ nci_info->arity = 0;
+ }
+ }
+ else {
+ arg_types = mem_internal_allocate_n_zeroed_typed(1, ffi_type*);
+ arg_types[0] = &ffi_type_void;
+ return_type = &ffi_type_void;
+ nci_info->pcc_params_signature = string_make(interp, "", 1, NULL, 0);
+ nci_info->arg_translation = NULL;
+ nci_info->arity = 0;
+ }
+
+ if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI,
+ nci_info->arity, return_type, arg_types) == FFI_OK) {
+ nci_info->cif = (void*)mem_internal_allocate_typed(ffi_cif);
+ memcpy(nci_info->cif, &cif, sizeof (ffi_cif));
+ nci_info->arg_types = arg_types;
+
+ return 1;
+ }
+
+ if (arg_types) {
+ mem_sys_free(arg_types);
+ }
+
+ /* TODO: Throw Error here. */
+ printf("Bad signature\n");
+
+ return 0;
+}
+
+/*
+
+=item C<static size_t parse_return(PARROT_INTERP, STRING *sig, size_t sig_length,
+ Parrot_NCI_attributes* nci_info, ffi_type **return_type)>
+
+Parses the return type. This assumes the first identifier is the return type.
+
+See C<parse_identifier> to see how a single identifer is parsed.
+
+=cut
+
+*/
+
+static size_t
+parse_return(PARROT_INTERP, STRING *sig, size_t sig_length,
+ Parrot_NCI_attributes* nci_info, ffi_type **return_type) {
+ char *t = mem_allocate_n_zeroed_typed(2, char);
+ size_t j = 0, k = 0;
+ /* Should be 1 character plus a NULL" */
+ char * result_sig = mem_allocate_n_zeroed_typed(2, char);
+ size_t result_length = parse_identifier(interp,
+ sig, 0, sig_length,
+ return_type,
+ result_sig, &j,
+ t, &k);
+
+ nci_info->pcc_return_signature = string_make(interp, result_sig, 2, NULL, 0);
+ nci_info->return_translation = (void*)t;
+ mem_sys_free(result_sig);
+ return result_length;
+}
+
+/*
+
+=item C<static size_t parse_args(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length,
+ Parrot_NCI_attributes *nci_info, ffi_type ***arg_types)>
+
+Parses the signatures arguments. It takes an offset to know where to start looking.
+This should fill out a list of C<ffi_type*> args.
+
+See C<parse_identifier> to see how a single identifer is parsed.
+
+=cut
+
+*/
+
+static size_t
+parse_args(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length,
+ Parrot_NCI_attributes *nci_info, ffi_type ***arg_types) {
+ size_t i = start;
+ size_t arg_count = 0;
+ size_t argc = count_args(interp, sig, start, sig_length);
+ char* parrot_types = mem_allocate_n_zeroed_typed(argc + 1, char);
+ size_t parrot_types_length = 0;
+ char* translation_types = mem_allocate_n_zeroed_typed(argc + 1, char);
+ size_t translation_length = 0;
+
+ *arg_types = mem_internal_allocate_n_zeroed_typed(argc + 1, ffi_type*);
+
+ while (i < sig_length) {
+ ffi_type *ident;
+ i = parse_identifier(interp,
+ sig, i, sig_length,
+ &ident,
+ parrot_types, &parrot_types_length,
+ translation_types, &translation_length);
+ (*arg_types)[arg_count] = ident;
+ arg_count++;
+ }
+
+ nci_info->pcc_params_signature = string_make(interp, parrot_types,
+ strlen(parrot_types), NULL, 0);
+ nci_info->arg_translation = translation_types;
+ nci_info->arity = arg_count;
+
+ mem_sys_free(parrot_types);
+
+ return i;
+}
+
+/*
+
+=item C<static size_t parse_identifier(PARROT_INTERP, STRING *sig, size_t start,
+ size_t sig_length, ffi_type **type_obj,
+ char **type, size_t *pmc_count,
+ char **translation, size_t *translation_count)>
+
+Parse an identifier and build its representation used for PCC and any translations
+that are needed.
+
+An example of a transation is "t", it will take a STRING* and convert it to a
+char* for the function call.
+
+=cut
+
+*/
+
+static size_t
+parse_identifier(PARROT_INTERP,
+ STRING *sig, size_t start, size_t sig_length,
+ ffi_type **type_obj,
+ char *type, size_t *pmc_count,
+ char *translation, size_t *translation_count) {
+ size_t i = start;
+ INTVAL done = 0;
+
+ while (!done && i < sig_length) {
+ INTVAL c = Parrot_str_indexed(interp, sig, i);
+ int prefix = 0;
+ while (IS_PREFIX(c)) {
+ prefix |= parse_prefix(c);
+ i++;
+
+ if (i < sig_length)
+ c = Parrot_str_indexed(interp, sig, i);
+ else
+ return i;
+ }
+
+ if (IS_START_CIRCUMFIX(c)) {
+ i = parse_structure(interp, sig, i + 1, sig_length, type_obj, type);
+ i++;
+
+ if (i < sig_length)
+ c = Parrot_str_indexed(interp, sig, i);
+ else
+ return i;
+ }
+ else if (IS_TYPE(c)) {
+ if (prefix & PREFIX_POINTER) {
+ *type_obj = &ffi_type_pointer;
+ continue;
+ }
+ translation[(*translation_count)++] = ' ';
+ switch (c) {
+ case (INTVAL)' ':
+ case (INTVAL)'0': /* null ptr or such - doesn't consume a reg */
+ break;
+ case (INTVAL)'c':
+ translation[(*translation_count) - 1] = 'c';
+ type[(*pmc_count)++] = 'I';
+ if (prefix & PREFIX_UNSIGNED) {
+ *type_obj = &ffi_type_uchar;
+ }
+ else {
+ *type_obj = &ffi_type_schar;
+ }
+ break;
+ case (INTVAL)'B':
+ translation[(*translation_count) - 1] = 'B';
+ type[(*pmc_count)++] = 'S';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'b':
+ translation[(*translation_count) - 1] = 'b';
+ type[(*pmc_count)++] = 'S';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'s':
+ translation[(*translation_count) - 1] = 's';
+ type[(*pmc_count)++] = 'I';
+ if (prefix & PREFIX_UNSIGNED) {
+ *type_obj = &ffi_type_ushort;
+ }
+ else {
+ *type_obj = &ffi_type_sshort;
+ }
+ break;
+ case (INTVAL)'I': /* INTVAL */
+ case (INTVAL)'i':
+ translation[(*translation_count) - 1] = 'i';
+ type[(*pmc_count)++] = 'I';
+ if (prefix & PREFIX_UNSIGNED) {
+ *type_obj = &ffi_type_uint;
+ }
+ else {
+ *type_obj = &ffi_type_sint;
+ }
+ break;
+ case (INTVAL)'l':
+ translation[(*translation_count) - 1] = 'l';
+ type[(*pmc_count)++] = 'I';
+ if (prefix & PREFIX_UNSIGNED) {
+ *type_obj = &ffi_type_ulong;
+ }
+ else {
+ *type_obj = &ffi_type_slong;
+ }
+ break;
+ case (INTVAL)'q':
+ translation[(*translation_count) - 1] = 'q';
+ type[(*pmc_count)++] = 'I';
+ if (prefix & PREFIX_UNSIGNED) {
+ *type_obj = &ffi_type_uint64;
+ }
+ else {
+ *type_obj = &ffi_type_sint64;
+ }
+ break;
+ case (INTVAL)'J': /* interpreter */
+ translation[(*translation_count) - 1] = 'J';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'p': /* push pmc->data */
+ translation[(*translation_count) - 1] = 'p';
+ type[(*pmc_count)++] = 'P';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'2':
+ translation[(*translation_count) - 1] = '2';
+ type[(*pmc_count)++] = 'P';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'3':
+ translation[(*translation_count) - 1] = '3';
+ type[(*pmc_count)++] = 'P';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'4':
+ translation[(*translation_count) - 1] = '4';
+ type[(*pmc_count)++] = 'P';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'P': /* push PMC * */
+ translation[(*translation_count) - 1] = 'P';
+ type[(*pmc_count)++] = 'P';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'V': /* push PMC * */
+ translation[(*translation_count) - 1] = 'V';
+ type[(*pmc_count)++] = 'P';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'S':
+ type[(*pmc_count)++] = 'S';
+ *type_obj = &ffi_type_pointer;
+ case (INTVAL)'t':
+ translation[(*translation_count) - 1] = 't';
+ type[(*pmc_count)++] = 'S';
+ *type_obj = &ffi_type_pointer;
+ break;
+ case (INTVAL)'v':
+ type[(*pmc_count)++] = 'v';
+ *type_obj = &ffi_type_void;
+ break;
+#if (DOUBLE_SIZE == 4) /* FLOATVAL is a float */
+ case (INTVAL)'N':
+#endif
+ case (INTVAL)'f':
+ translation[(*translation_count) - 1] = 'f';
+ type[(*pmc_count)++] = 'N';
+ *type_obj = &ffi_type_float;
+ break;
+#if (DOUBLE_SIZE == 8) /* FLOATVAL is a double */
+ case (INTVAL)'N':
+#endif
+ case (INTVAL)'d':
+ translation[(*translation_count) - 1] = 'd';
+ type[(*pmc_count)++] = 'N';
+ *type_obj = &ffi_type_double;
+ break;
+#if (DOUBLE_SIZE > 8) /* FLOATVAL is a long double */
+ case (INTVAL)'N':
+#endif
+ case (INTVAL)'D':
+ translation[(*translation_count) - 1] = 'D';
+ type[(*pmc_count)++] = 'N';
+ *type_obj = &ffi_type_longdouble;
+ break;
+ case (INTVAL)'O': /* push PMC * invocant */
+ *type_obj = &ffi_type_pointer;
+ type[(*pmc_count)++] = 'P';
+ type[(*pmc_count)++] = 'i';
+ break;
+ case (INTVAL)'@': /* push PMC * slurpy */
+ *type_obj = &ffi_type_pointer;
+ type[(*pmc_count)++] = 'P';
+ type[(*pmc_count)++] = 's';
+ break;
+ default:
+ Parrot_ex_throw_from_c_args(interp, NULL,
+ EXCEPTION_JIT_ERROR,
+ "Unknown param Signature %c\n", (char)c);
+ break;
+ }
+ i++;
+
+ if (i < sig_length)
+ c = Parrot_str_indexed(interp, sig, i);
+ else
+ return i;
+ }
+ else {
+ Parrot_ex_throw_from_c_args(interp, NULL,
+ EXCEPTION_JIT_ERROR,
+ "Unknown param Signature %c\n", (char)c);
+ }
+
+ /*
+ * Parse postfix ops
+ * TODO: Parse postfix ops, currently I skip them.
+ */
+ while (IS_POSTFIX(c)) {
+ i++;
+ if (i < sig_length)
+ c = Parrot_str_indexed(interp, sig, i);
+ else
+ return i;
+ }
+
+ if ((i < sig_length) && (c == (INTVAL)'|')) {
+ /* Its a union, parse it special. */
+ }
+ else {
+ done = 1;
+ }
+ }
+
+ return i;
+}
+
+/*
+
+=item C<static INTVAL parse_prefix(INTVAL c)>
+
+Parse a prefix character.
+
+=cut
+
+*/
+
+static INTVAL
+parse_prefix(INTVAL c) {
+ switch (c) {
+ case '*':
+ return PREFIX_POINTER;
+ break;
+ case 'u':
+ return PREFIX_UNSIGNED;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return 0;
+}
+
+/*
+
+=item C<static size_t parse_structure(PARROT_INTERP, STRING* sig, size_t start,
+ size_t sig_length, ffi_type **type_obj, char* pmc_type)>
+
+Parses a stucture.
+TODO: This should auto inflate to an UnmanagedStruct or a ManagedStruct in the future.
+
+=cut
+
+*/
+
+static size_t
+parse_structure(PARROT_INTERP, STRING* sig, size_t start, size_t sig_length,
+ ffi_type **type_obj, char* pmc_type) {
+ size_t i = start;
+ size_t struct_len = structure_length(interp, sig, start, sig_length);
+ size_t element_counter = 0;