Index: src/pmc/nci.pmc =================================================================== --- src/pmc/nci.pmc (revision 42133) +++ src/pmc/nci.pmc (working copy) @@ -18,86 +18,116 @@ */ +#include "parrot/nci.h" + typedef INTVAL (*nci_sub_t)(PARROT_INTERP, PMC *); -typedef INTVAL (*nci_jit_sub_t)(PARROT_INTERP, PMC *, char *); +typedef nci_sub_t nci_jit_sub_t; -void pcc_params(PARROT_INTERP, STRING *sig, Parrot_NCI_attributes * const nci_info, - size_t sig_length); -void pcc_params(PARROT_INTERP, STRING *sig, Parrot_NCI_attributes * const nci_info, - size_t sig_length) { - char param_buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - char *param_sig = sig_length <= 7 - ? param_buf - : mem_allocate_n_typed(sig_length, char); - size_t j = 0; - size_t i; +#define NCI_raw_FLAG PObj_private0_FLAG - for (i = 1; i < sig_length; i++) { +STRING *pcc_sig_params(PARROT_INTERP, STRING *sig); +STRING *pcc_sig_params(PARROT_INTERP, STRING *sig) { + size_t sig_len = Parrot_str_byte_length(interp, sig); + char param_buf[sig_len*2]; + + size_t i, j; + + for (i = 1, j = 0; i < sig_len; i++) { INTVAL c = Parrot_str_indexed(interp, sig, i); - - switch (c) { - case (INTVAL)'0': /* null ptr or such - doesn't consume a reg */ - break; - case (INTVAL)'f': - case (INTVAL)'N': - case (INTVAL)'d': - param_sig[j++] = 'N'; - break; - case (INTVAL)'I': /* INTVAL */ - case (INTVAL)'l': /* long */ - case (INTVAL)'i': /* int */ - case (INTVAL)'s': /* short */ - case (INTVAL)'c': /* char */ - param_sig[j++] = 'I'; - break; - case (INTVAL)'S': - case (INTVAL)'t': /* string, pass a cstring */ - param_sig[j++] = 'S'; - break; - case (INTVAL)'J': /* interpreter */ - break; - case (INTVAL)'p': /* push pmc->data */ - case (INTVAL)'O': /* push PMC * object in P2 */ - case (INTVAL)'P': /* push PMC * */ - case (INTVAL)'V': /* push PMC * */ - param_sig[j++] = 'P'; - case (INTVAL)'v': - break; - /* I have no idea how to handle these */ - case (INTVAL)'2': - case (INTVAL)'3': - case (INTVAL)'4': - param_sig[j++] = 'I'; - break; - case (INTVAL)'@': - param_sig[j++] = '@'; - break; - case (INTVAL)'b': /* buffer (void*) pass Buffer_bufstart(SReg) */ - case (INTVAL)'B': /* buffer (void**) pass &Buffer_bufstart(SReg) */ - param_sig[j++] = 'S'; - break; - default: - if (sig_length > 7) - mem_sys_free(param_sig); - Parrot_ex_throw_from_c_args(interp, NULL, + if (c > 127) { + Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "Unknown param Signature %c\n", (char)c); - break; + "Unknown param type at %d in signature '%S' (way too big)\n", i, sig); } + else { + switch ((char)c) { + case 'v': + case '0': + case 'J': + break; + case 'N': + case 'd': + case 'f': + param_buf[j++] = 'N'; + break; + case 'I': + case 'l': + case 'i': + case 's': + case 'c': + param_buf[j++] = 'I'; + break; + case 'S': + case 't': + case 'b': + case 'B': + param_buf[j++] = 'S'; + break; + case 'P': + case 'p': + case 'V': + case '2': + case '3': + case '4': + param_buf[j++] = 'P'; + break; + case 'O': + param_buf[j++] = 'P'; + param_buf[j++] = 'i'; + break; + case '@': + param_buf[j++] = 'P'; + param_buf[j++] = 's'; + break; + default: + Parrot_ex_throw_from_c_args(interp, NULL, + EXCEPTION_JIT_ERROR, + "Unknown param type at %d in signature '%S'\n", i, sig); + } + } } - PARROT_ASSERT(j <= sig_length); + return string_make(interp, param_buf, j, NULL, PObj_constant_FLAG); +} - /* use only the signature-significant part of the string buffer */ - if (j) { - nci_info->pcc_params_signature = string_make(interp, param_sig, j, - NULL, PObj_constant_FLAG); +STRING *pcc_sig_ret(PARROT_INTERP, STRING *sig); +STRING *pcc_sig_ret(PARROT_INTERP, STRING *sig) { + INTVAL c = Parrot_str_indexed(interp, sig, 0); + if (c > 127) { + Parrot_ex_throw_from_c_args(interp, NULL, + EXCEPTION_JIT_ERROR, + "Unknown return type at %d in signature '%S' (way too big)\n", 0, sig); } - else - nci_info->pcc_params_signature = CONST_STRING(interp, ""); - - if (sig_length > 7) - mem_sys_free(param_sig); + else { + switch ((char)c) { + case 'v': + return CONST_STRING(interp, "v"); + case 'N': + case 'f': + case 'd': + return CONST_STRING(interp, "N"); + case 'I': + case 'l': + case 'i': + case 's': + case 'c': + return CONST_STRING(interp, "I"); + case 'S': + case 't': + return CONST_STRING(interp, "S"); + case 'p': + case 'P': + return CONST_STRING(interp, "P"); + case '2': + case '3': + case '4': + return CONST_STRING(interp, "P"); + default: + Parrot_ex_throw_from_c_args(interp, NULL, + EXCEPTION_JIT_ERROR, + "Unknown return type at %d in signature '%S'\n", 0, sig); + } + } } /* actually build the NCI thunk */ @@ -106,34 +136,32 @@ static nci_sub_t build_func(PARROT_INTERP, PMC *pmc, Parrot_NCI_attributes *nci_info) { - STRING *key = nci_info->signature; - size_t key_length = Parrot_str_byte_length(interp, key); + STRING *key = nci_info->nci_signature; int jitted = 0; - 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->func = (PMC *)(build_call_func(interp, pmc, key, &jitted)); - nci_info->jitted = jitted; return (nci_sub_t)nci_info->func; } pmclass NCI auto_attrs { - ATTR STRING *signature; /* The signature. */ - ATTR void *func; /* Function pointer to call. */ - ATTR void *orig_func; /* Function pointer - * used to create func */ - ATTR STRING *pcc_params_signature; /* The signature. */ - ATTR STRING *long_signature; /* The full signature. */ - ATTR PMC *multi_sig; /* type tuple array (?) */ - ATTR INTVAL arity; /* Cached arity of the NCI. */ - ATTR INTVAL jitted; /* Is this a jitted NCI stub. */ + /* Signature Attributes */ + ATTR STRING *nci_signature; /* The NCI signature */ + ATTR STRING *pcc_signature_ret; /* The PCC return signature */ + ATTR STRING *pcc_signature_param; /* The PCC param signature */ + /* Function Pointers */ + ATTR void *func; /* Function pointer to call */ + ATTR void *orig_func; /* Function pointer being wrapped */ + + /* Sub PMC Attributes */ + ATTR INTVAL arity; /* Number of params taken */ + /* MMD Attributes */ + ATTR PMC *multi_sig; + ATTR STRING *long_signature; + /* =item C @@ -147,8 +175,9 @@ METHOD get_multisig() { PMC *sig; GET_ATTR_multi_sig(INTERP, SELF, sig); - if (PMC_IS_NULL(sig)) + if (sig == NULL) { sig = PMCNULL; + } RETURN(PMC *sig); } @@ -178,45 +207,77 @@ VTABLE void init() { /* Mark that we're not a raw NCI. */ - PObj_flag_CLEAR(private2, SELF); + PObj_get_FLAGS(SELF) &= ~NCI_raw_FLAG; + /* Mark that we have a custom gc marker */ PObj_custom_mark_SET(SELF); } /* -=item C +=item C -Sets the specified function pointer and signature (C<*key>). +=item C +Get/Set the pointer being wrapped. Setting through this interface sets +the raw flag. + =cut */ VTABLE void set_pointer(void *ptr) { SET_ATTR_orig_func(INTERP, SELF, ptr); - PObj_flag_SET(private2, SELF); + PObj_get_FLAGS(SELF) |= NCI_raw_FLAG; } VTABLE void *get_pointer() { return PARROT_NCI(SELF)->orig_func; } +/* + +=item C + +Roughly equivalent to C and C. +Setting through this interface clears the raw flag. + +=cut + +*/ + VTABLE void set_pointer_keyed_str(STRING *key, void *func) { - Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF); + SELF.set_string_native(key); + SELF.set_pointer(func); + PObj_get_FLAGS(SELF) &= ~NCI_raw_FLAG; + } - /* 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); - 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); +=item C + +=item C + +Get/Set the NCI signature. + +=cut + +*/ + + VTABLE STRING *get_string() { + return PARROT_NCI(SELF)->nci_signature; + } + + VTABLE void set_string_native(STRING *str) { + if (!PObj_constant_TEST(str)) { + str = Parrot_str_copy(INTERP, str); } + SET_ATTR_nci_signature(INTERP, SELF, str); - nci_info->signature = key; + /* set up derivative attributes */ + SET_ATTR_pcc_signature_param(INTERP, SELF, pcc_sig_params(INTERP, str)); + SET_ATTR_pcc_signature_ret(INTERP, SELF, pcc_sig_ret(INTERP, str)); + /* Arity is length of the NCI signature minus one (the return type). */ + SET_ATTR_arity(INTERP, SELF, Parrot_str_byte_length(INTERP, str) - 1); } /* @@ -232,8 +293,9 @@ if (PARROT_NCI(SELF)) { Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF); - 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->nci_signature); + Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_signature_param); + Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_signature_ret); Parrot_gc_mark_STRING_alive(interp, nci_info->long_signature); Parrot_gc_mark_PMC_alive(interp, nci_info->multi_sig); } @@ -262,11 +324,13 @@ * ManagedStruct or Buffer? */ nci_info_ret->func = nci_info_self->func; - 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->orig_func = nci_info_self->orig_func; + nci_info_ret->nci_signature = nci_info_self->nci_signature; + nci_info_ret->pcc_signature_param = nci_info_self->pcc_signature_param; + nci_info_ret->pcc_signature_ret = nci_info_self->pcc_signature_ret; + nci_info_ret->long_signature = nci_info_self->long_signature; + nci_info_ret->multi_sig = nci_info_self->multi_sig; nci_info_ret->arity = nci_info_self->arity; - nci_info_ret->jitted = nci_info_self->jitted; PObj_get_FLAGS(ret) |= (PObj_get_FLAGS(SELF) & 0x7); return ret; @@ -306,7 +370,7 @@ PMC *cont; GET_ATTR_orig_func(INTERP, SELF, orig_func); - func = PObj_flag_TEST(private2, SELF) + func = PObj_get_FLAGS(SELF) & NCI_raw_FLAG ? (nci_sub_t) D2FPTR(orig_func) : (nci_sub_t) D2FPTR(nci_info->func); @@ -320,23 +384,8 @@ "attempt to call NULL function"); } - if (nci_info->jitted) { - nci_jit_sub_t jit_func = (nci_jit_sub_t) D2FPTR(nci_info->func); + func(INTERP, SELF); - /* Parrot_eprintf(interp, "JITTED %S\n", nci_info->signature); */ - sig_str = Parrot_str_to_cstring(interp, nci_info->pcc_params_signature); - jit_func(INTERP, SELF, sig_str); - Parrot_str_free_cstring(sig_str); - } - else { - if (PObj_flag_TEST(private2, SELF)) { - /* Parrot_eprintf(interp, "RAW NCI CALL\n"); */ - } - else { - /* Parrot_eprintf(interp, "HACKED %S\n", nci_info->signature); */ - } - func(INTERP, SELF); - } cont = INTERP->current_cont; /* @@ -397,22 +446,85 @@ */ METHOD arity() { - Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF); - INTVAL arity = 0; + INTVAL arity; + GET_ATTR_arity(INTERP, SELF, arity); + RETURN(INTVAL arity); + } - if (nci_info) { - if (!nci_info->func) - build_func(INTERP, SELF, nci_info); - if (nci_info->func) { - arity = nci_info->arity; - RETURN(INTVAL arity); - } +/* + +=item C + +=item C + +=item C + +Accessors for all attributes of this class not otherwise accessible through VTABLES. +Integers are used for keys to make access easier for JIT. These are also available to +PIR from F + +=over + +=item INTVAL keys + +C + +=item STRING keys + +C, C, +C + +=item PMC keys + +C + +=back + +=cut + +*/ + + VTABLE INTVAL get_integer_keyed_int(INTVAL key) { + switch (key) { + case PARROT_NCI_ARITY: + return PARROT_NCI(SELF)->arity; + default: + Parrot_ex_throw_from_c_args(INTERP, NULL, + EXCEPTION_INVALID_OPERATION, + "Bad index for NCI.get_integer_keyed_int()"); } + } - Parrot_ex_throw_from_c_args(INTERP, NULL, - EXCEPTION_INVALID_OPERATION, - "You cannot get the arity of an undefined NCI."); + VTABLE STRING *get_string_keyed_int(INTVAL key) { + switch (key) { + case PARROT_NCI_PCC_SIGNATURE_PARAMS: + return PARROT_NCI(SELF)->pcc_signature_param; + case PARROT_NCI_PCC_SIGNATURE_RET: + return PARROT_NCI(SELF)->pcc_signature_ret; + case PARROT_NCI_LONG_SIGNATURE: + return PARROT_NCI(SELF)->long_signature; + default: + Parrot_ex_throw_from_c_args(INTERP, NULL, + EXCEPTION_INVALID_OPERATION, + "Bad index for NCI.get_string_keyed_int()"); + } } + + VTABLE PMC *get_pmc_keyed_int(INTVAL key) { + PMC *retval; + switch (key) { + case PARROT_NCI_MULTI_SIG: + GET_ATTR_multi_sig(INTERP, SELF, retval); + default: + Parrot_ex_throw_from_c_args(INTERP, NULL, + EXCEPTION_INVALID_OPERATION, + "Bad index for NCI.get_pmc_keyed_int()"); + } + if (retval == NULL) { + retval = PMCNULL; + } + return retval; + } } /* Index: include/parrot/nci.h =================================================================== --- include/parrot/nci.h (revision 42133) +++ include/parrot/nci.h (working copy) @@ -15,6 +15,17 @@ #include "parrot/parrot.h" +/* NCI PMC interface constants */ +/* &gen_from_enum(nci.pasm) */ +typedef enum { + PARROT_NCI_ARITY, + PARROT_NCI_PCC_SIGNATURE_PARAMS, + PARROT_NCI_PCC_SIGNATURE_RET, + PARROT_NCI_LONG_SIGNATURE, + PARROT_NCI_MULTI_SIG, +} parrot_nci_enum_t; +/* &end_gen */ + void *build_call_func(PARROT_INTERP, SHIM(PMC *pmc_nci), NOTNULL(STRING *signature), NOTNULL(int *jitted)); #endif /* PARROT_NCI_H_GUARD */ Index: config/gen/parrot_include.pm =================================================================== --- config/gen/parrot_include.pm (revision 42133) +++ config/gen/parrot_include.pm (working copy) @@ -39,13 +39,13 @@ include/parrot/library.h include/parrot/longopt.h include/parrot/multidispatch.h + include/parrot/nci.h include/parrot/packfile.h include/parrot/stat.h include/parrot/string.h include/parrot/pmc.h include/parrot/warnings.h include/parrot/gc_api.h - src/pmc/timer.pmc src/utils.c ) ]; $data{generated_files} = [ qw(