2 Copyright (C) 2001-2010, Parrot Foundation.
7 src/pmc/nci.pmc - Native Call Interface
11 The vtable functions for the native C call functions.
21 /* HEADERIZER HFILE: none */
22 /* HEADERIZER BEGIN: static */
23 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
25 PARROT_IGNORABLE_RESULT
26 static nci_thunk_t /*@alt void@*/
27 build_func(PARROT_INTERP,
28 ARGMOD(Parrot_NCI_attributes *nci_info))
29 __attribute__nonnull__(1)
30 __attribute__nonnull__(2)
31 FUNC_MODIFIES(*nci_info);
33 static void pcc_params(PARROT_INTERP,
35 ARGMOD(Parrot_NCI_attributes *nci_info),
37 __attribute__nonnull__(1)
38 __attribute__nonnull__(2)
39 __attribute__nonnull__(3)
40 FUNC_MODIFIES(*nci_info);
42 #define ASSERT_ARGS_build_func __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
43 PARROT_ASSERT_ARG(interp) \
44 , PARROT_ASSERT_ARG(nci_info))
45 #define ASSERT_ARGS_pcc_params __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
46 PARROT_ASSERT_ARG(interp) \
47 , PARROT_ASSERT_ARG(sig) \
48 , PARROT_ASSERT_ARG(nci_info))
49 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
50 /* HEADERIZER END: static */
54 pcc_params(PARROT_INTERP, ARGIN(STRING *sig), ARGMOD(Parrot_NCI_attributes *nci_info),
57 ASSERT_ARGS(pcc_params)
59 /* NCI and PCC have a 1 to 1 mapping except an
60 extra char in PCC for invocant and slurpy */
61 size_t buf_length = sig_length + 2 + 1;
63 /* avoid malloc churn on common signatures */
65 char * const sig_buf = sig_length <= sizeof static_buf ?
67 (char *)mem_sys_allocate(buf_length);
72 for (i = 0; i < sig_length; ++i) {
73 const INTVAL c = Parrot_str_indexed(interp, sig, i);
75 PARROT_ASSERT(j < buf_length - 1);
78 case (INTVAL)'0': /* null ptr or such - doesn't consume a reg */
85 case (INTVAL)'I': /* INTVAL */
86 case (INTVAL)'l': /* long */
87 case (INTVAL)'i': /* int */
88 case (INTVAL)'s': /* short */
89 case (INTVAL)'c': /* char */
93 case (INTVAL)'t': /* string, pass a cstring */
96 case (INTVAL)'J': /* interpreter */
98 case (INTVAL)'p': /* push pmc->data */
99 case (INTVAL)'P': /* push PMC * */
100 case (INTVAL)'V': /* push PMC * */
111 case (INTVAL)'O': /* push PMC * invocant */
115 case (INTVAL)'@': /* push PMC * slurpy */
119 case (INTVAL)'b': /* buffer (void*) pass Buffer_bufstart(SReg) */
120 case (INTVAL)'B': /* buffer (void**) pass &Buffer_bufstart(SReg) */
124 Parrot_ex_throw_from_c_args(interp, NULL,
126 "Unknown param Signature %c\n", (char)c);
131 PARROT_ASSERT(j < buf_length);
135 nci_info->pcc_return_signature =
136 Parrot_str_new(interp, sig_buf, 1);
138 nci_info->pcc_params_signature = j ?
139 Parrot_str_new(interp, sig_buf + 1, j - 1) :
140 CONST_STRING(interp, "");
142 if (sig_buf != static_buf)
143 mem_sys_free(sig_buf);
146 /* actually build the NCI thunk */
148 PARROT_IGNORABLE_RESULT
150 build_func(PARROT_INTERP, ARGMOD(Parrot_NCI_attributes *nci_info))
152 ASSERT_ARGS(build_func)
154 STRING * const key = nci_info->signature;
155 const size_t key_length = Parrot_str_byte_length(interp, key);
157 pcc_params(interp, key, nci_info, key_length);
159 /* Arity is length of that string minus one (the return type). */
160 nci_info->arity = key_length - 1;
162 /* Build call function. */
163 nci_info->fb_info = build_call_func(interp, key);
164 nci_info->func = F2DPTR(VTABLE_get_pointer(interp, nci_info->fb_info));
166 return (nci_thunk_t)nci_info->func;
170 pmclass NCI auto_attrs provides invokable {
171 /* NCI thunk handling attributes */
172 /* NCI thunk handling attributes */
173 ATTR STRING *signature; /* The signature. */
174 ATTR void *func; /* Function pointer to call. */
175 ATTR PMC *fb_info; /* Frame-builder info */
176 ATTR void *orig_func; /* Function pointer
177 * used to create func */
178 /* Parrot Sub-ish attributes */
179 ATTR STRING *pcc_params_signature;
180 ATTR STRING *pcc_return_signature;
181 ATTR INTVAL arity; /* Cached arity of the NCI. */
184 ATTR STRING *long_signature; /* The full signature. */
185 ATTR PMC *multi_sig; /* type tuple array (?) */
189 =item C<METHOD get_multisig()>
191 Return the MMD signature PMC, if any or a Null PMC.
197 METHOD get_multisig() {
199 GET_ATTR_multi_sig(INTERP, SELF, sig);
200 if (PMC_IS_NULL(sig))
207 =item C<METHOD set_raw_nci_ptr(void *func)>
209 Sets the specified function pointer and raw flag.
215 METHOD make_raw_nci(PMC *func) {
216 VTABLE_set_pointer(interp, SELF, (void *)func);
223 Initializes the NCI with a C<NULL> function pointer.
230 /* Mark that we're not a raw NCI. */
231 PObj_flag_CLEAR(private2, SELF);
232 PObj_custom_mark_SET(SELF);
237 =item C<void set_pointer_keyed_str(STRING *key, void *func)>
239 Sets the specified function pointer and signature (C<*key>).
245 VTABLE void set_pointer(void *ptr) {
246 SET_ATTR_orig_func(INTERP, SELF, ptr);
247 PObj_flag_SET(private2, SELF);
250 VTABLE void *get_pointer() {
251 return PARROT_NCI(SELF)->orig_func;
254 VTABLE void set_pointer_keyed_str(STRING *key, void *func) {
255 Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
257 /* Store the original function and signature. */
258 SET_ATTR_orig_func(INTERP, SELF, func);
260 /* ensure that the STRING signature is constant */
261 if (!PObj_constant_TEST(key)) {
262 char * const key_c = Parrot_str_to_cstring(INTERP, key);
263 const size_t key_length = Parrot_str_byte_length(interp, key);
264 key = string_make(interp, key_c, key_length,
265 NULL, PObj_constant_FLAG);
266 Parrot_str_free_cstring(key_c);
269 nci_info->signature = key;
276 Mark any referenced strings and PMCs.
282 if (PARROT_NCI(SELF)) {
283 Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
285 Parrot_gc_mark_PMC_alive(interp, nci_info->fb_info);
286 Parrot_gc_mark_STRING_alive(interp, nci_info->signature);
287 Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_params_signature);
288 Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_params_signature);
289 Parrot_gc_mark_STRING_alive(interp, nci_info->long_signature);
290 Parrot_gc_mark_PMC_alive(interp, nci_info->multi_sig);
296 =item C<PMC *clone()>
298 Creates and returns a clone of the NCI.
304 VTABLE PMC *clone() {
305 Parrot_NCI_attributes * const nci_info_self = PARROT_NCI(SELF);
306 Parrot_NCI_attributes *nci_info_ret;
309 PMC * const ret = Parrot_pmc_new(INTERP, SELF->vtable->base_type);
310 nci_info_ret = PARROT_NCI(ret);
312 /* FIXME if data is malloced (JIT/i386!) then we need
313 * the length of data here, to memcpy it
314 * ManagedStruct or Buffer?
316 nci_info_ret->func = nci_info_self->func;
317 nci_info_ret->fb_info = nci_info_self->fb_info;
318 nci_info_ret->orig_func = nci_info_self->orig_func;
319 nci_info_ret->signature = nci_info_self->signature;
320 nci_info_ret->pcc_params_signature = nci_info_self->pcc_params_signature;
321 nci_info_ret->pcc_return_signature = nci_info_self->pcc_params_signature;
322 nci_info_ret->arity = nci_info_self->arity;
323 PObj_get_FLAGS(ret) |= (PObj_get_FLAGS(SELF) & 0x7);
330 =item C<INTVAL defined()>
332 Returns whether the NCI is defined.
338 VTABLE INTVAL defined() {
339 Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
340 return nci_info->orig_func != NULL;
345 =item C<opcode_t *invoke(void *next)>
347 Calls the associated C function, returning C<*next>. If the invocant is a
348 class, the PMC arguments are shifted down.
354 VTABLE opcode_t *invoke(void *next) {
355 Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
362 GET_ATTR_orig_func(INTERP, SELF, orig_func);
363 func = PObj_flag_TEST(private2, SELF)
364 ? (nci_thunk_t) D2FPTR(orig_func)
365 : (nci_thunk_t) D2FPTR(nci_info->func);
367 GET_ATTR_fb_info(INTERP, SELF, fb_info);
370 /* build the thunk only when necessary */
371 func = build_func(interp, nci_info);
374 Parrot_ex_throw_from_c_args(INTERP, NULL,
375 EXCEPTION_INVALID_OPERATION,
376 "attempt to call NULL function");
379 func(INTERP, SELF, fb_info);
380 cont = INTERP->current_cont;
383 * If the NCI function was tailcalled, the return result
384 * is already passed back to the caller of this frame
385 * - see Parrot_init_ret_nci(). We therefore invoke the
386 * return continuation here, which gets rid of this frame
387 * and returns the real return address
389 if (cont && cont != NEED_CONTINUATION
390 && (PObj_get_FLAGS(cont) & SUB_FLAG_TAILCALL)) {
391 cont = Parrot_pcc_get_continuation(interp, CURRENT_CONTEXT(interp));
392 next = VTABLE_invoke(INTERP, cont, next);
395 return (opcode_t *)next;
400 =item C<INTVAL get_integer()>
402 Returns the function pointer as an integer.
408 VTABLE INTVAL get_integer() {
409 Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
411 build_func(INTERP, nci_info);
412 return (INTVAL)nci_info->func;
417 =item C<INTVAL get_bool()>
419 Returns the boolean value of the pointer.
425 VTABLE INTVAL get_bool() {
426 Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
427 return (0 != (INTVAL)nci_info->orig_func);
432 =item C<METHOD arity()>
434 Return the arity of the NCI (the number of arguments).
440 Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
445 build_func(INTERP, nci_info);
446 if (nci_info->func) {
447 arity = nci_info->arity;
448 RETURN(INTVAL arity);
452 Parrot_ex_throw_from_c_args(INTERP, NULL,
453 EXCEPTION_INVALID_OPERATION,
454 "You cannot get the arity of an undefined NCI.");
464 F<docs/pdds/pdd03_calling_conventions.pod>.
468 Initial revision by sean 2002/08/04.
476 * c-file-style: "parrot"
478 * vim: expandtab shiftwidth=4: