fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / pmc / nci.pmc
blob4746df0b92e4cdd3fa97cbd9175a0e9f4bc61d0b
1 /*
2 Copyright (C) 2001-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/pmc/nci.pmc - Native Call Interface
9 =head1 DESCRIPTION
11 The vtable functions for the native C call functions.
13 =head2 Methods
15 =over 4
17 =cut
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,
34     ARGIN(STRING *sig),
35     ARGMOD(Parrot_NCI_attributes *nci_info),
36     size_t sig_length)
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 =item C<static void pcc_params(PARROT_INTERP, STRING *sig, Parrot_NCI_attributes
55 *nci_info, size_t sig_length)>
57 =cut
61 static void
62 pcc_params(PARROT_INTERP, ARGIN(STRING *sig), ARGMOD(Parrot_NCI_attributes *nci_info),
63                 size_t sig_length)
65     ASSERT_ARGS(pcc_params)
67     /* NCI and PCC have a 1 to 1 mapping except an
68        extra char in PCC for invocant and slurpy */
69     size_t       buf_length = sig_length + 2 + 1;
71     /* avoid malloc churn on common signatures */
72     char         static_buf[16];
73     char * const sig_buf = sig_length <= sizeof static_buf ?
74                             static_buf :
75                             (char *)mem_sys_allocate(buf_length);
77     size_t j = 0;
78     size_t i;
80     for (i = 0; i < sig_length; ++i) {
81         const INTVAL c = Parrot_str_indexed(interp, sig, i);
83         PARROT_ASSERT(j < buf_length - 1);
85         switch (c) {
86           case (INTVAL)'0':    /* null ptr or such - doesn't consume a reg */
87             break;
88           case (INTVAL)'f':
89           case (INTVAL)'N':
90           case (INTVAL)'d':
91             sig_buf[j++] = 'N';
92             break;
93           case (INTVAL)'I':   /* INTVAL */
94           case (INTVAL)'l':   /* long */
95           case (INTVAL)'i':   /* int */
96           case (INTVAL)'s':   /* short */
97           case (INTVAL)'c':   /* char */
98             sig_buf[j++] = 'I';
99             break;
100           case (INTVAL)'S':
101           case (INTVAL)'t':   /* string, pass a cstring */
102             sig_buf[j++] = 'S';
103             break;
104           case (INTVAL)'J':   /* interpreter */
105             break;
106           case (INTVAL)'p':   /* push pmc->data */
107           case (INTVAL)'P':   /* push PMC * */
108           case (INTVAL)'V':   /* push PMC * */
109           case (INTVAL)'2':
110           case (INTVAL)'3':
111           case (INTVAL)'4':
112             sig_buf[j++] = 'P';
113             break;
114           case (INTVAL)'v':
115             /* null return */
116             if (j == 0)
117                 sig_buf[j++] = '\0';
118             break;
119           case (INTVAL)'O':   /* push PMC * invocant */
120             sig_buf[j++] = 'P';
121             sig_buf[j++] = 'i';
122             break;
123           case (INTVAL)'@':   /* push PMC * slurpy */
124             sig_buf[j++] = 'P';
125             sig_buf[j++] = 's';
126             break;
127           case (INTVAL)'b': /* buffer (void*) pass Buffer_bufstart(SReg) */
128           case (INTVAL)'B': /* buffer (void**) pass &Buffer_bufstart(SReg) */
129             sig_buf[j++] = 'S';
130             break;
131           default:
132             Parrot_ex_throw_from_c_args(interp, NULL,
133                     EXCEPTION_JIT_ERROR,
134                     "Unknown param Signature %c\n", (char)c);
135             break;
136         }
137     }
139     PARROT_ASSERT(j < buf_length);
140     sig_buf[j++] = '\0';
143     nci_info->pcc_return_signature =
144         Parrot_str_new(interp, sig_buf, 1);
146     nci_info->pcc_params_signature = j ?
147         Parrot_str_new(interp, sig_buf + 1, j - 1) :
148         CONST_STRING(interp, "");
150     if (sig_buf != static_buf)
151         mem_sys_free(sig_buf);
156 =item C<static nci_thunk_t build_func(PARROT_INTERP, Parrot_NCI_attributes
157 *nci_info)>
159 Actually build the NCI thunk.
161 =cut
165 PARROT_IGNORABLE_RESULT
166 static nci_thunk_t
167 build_func(PARROT_INTERP, ARGMOD(Parrot_NCI_attributes *nci_info))
169     ASSERT_ARGS(build_func)
171     STRING * const key      = nci_info->signature;
172     const size_t key_length = Parrot_str_byte_length(interp, key);
174     pcc_params(interp, key, nci_info, key_length);
176     /* Arity is length of that string minus one (the return type). */
177     nci_info->arity       = key_length - 1;
179     /* Build call function. */
180     nci_info->fb_info     = build_call_func(interp, key);
181     nci_info->func        = F2DPTR(VTABLE_get_pointer(interp, nci_info->fb_info));
183     return (nci_thunk_t)nci_info->func;
187 pmclass NCI auto_attrs provides invokable {
188     /* NCI thunk handling attributes */
189     /* NCI thunk handling attributes */
190     ATTR STRING    *signature;              /* The signature. */
191     ATTR void      *func;                   /* Function pointer to call. */
192     ATTR PMC       *fb_info;                /* Frame-builder info */
193     ATTR void      *orig_func;              /* Function pointer
194                                              * used to create func */
195     /* Parrot Sub-ish attributes */
196     ATTR STRING    *pcc_params_signature;
197     ATTR STRING    *pcc_return_signature;
198     ATTR INTVAL     arity;                  /* Cached arity of the NCI. */
200     /* MMD fields */
201     ATTR STRING    *long_signature;         /* The full signature. */
202     ATTR PMC       *multi_sig;              /* type tuple array (?) */
206 =item C<METHOD get_multisig()>
208 Return the MMD signature PMC, if any or a Null PMC.
210 =cut
214     METHOD get_multisig() {
215         PMC *sig;
216         GET_ATTR_multi_sig(INTERP, SELF, sig);
217         if (PMC_IS_NULL(sig))
218             sig = PMCNULL;
219         RETURN(PMC *sig);
220     }
224 =item C<void init()>
226 Initializes the NCI with a C<NULL> function pointer.
228 =cut
232     VTABLE void init() {
233         PObj_custom_mark_SET(SELF);
234     }
236     VTABLE void *get_pointer() {
237         return PARROT_NCI(SELF)->orig_func;
238     }
242 =item C<void set_pointer_keyed_str(STRING *key, void *func)>
244 Sets the specified function pointer and signature (C<*key>).
246 =cut
250     VTABLE void set_pointer_keyed_str(STRING *key, void *func) {
251         Parrot_NCI_attributes * const nci_info   = PARROT_NCI(SELF);
253         /* Store the original function and signature. */
254         SET_ATTR_orig_func(INTERP, SELF, func);
256         /* ensure that the STRING signature is constant */
257         if (!PObj_constant_TEST(key)) {
258             char * const key_c      = Parrot_str_to_cstring(INTERP, key);
259             const size_t key_length = Parrot_str_byte_length(interp, key);
260             key                     = Parrot_str_new_init(interp, key_c, key_length,
261                                         Parrot_default_encoding_ptr, PObj_constant_FLAG);
262             Parrot_str_free_cstring(key_c);
263         }
265         nci_info->signature = key;
266     }
270 =item C<void mark()>
272 Mark any referenced strings and PMCs.
274 =cut
277     VTABLE void mark() {
278         if (PARROT_NCI(SELF)) {
279             Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
281             Parrot_gc_mark_PMC_alive(interp, nci_info->fb_info);
282             Parrot_gc_mark_PMC_alive(interp, nci_info->multi_sig);
284             Parrot_gc_mark_STRING_alive(interp, nci_info->signature);
285             Parrot_gc_mark_STRING_alive(interp, nci_info->long_signature);
286             Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_params_signature);
287             Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_return_signature);
288         }
289     }
293 =item C<PMC *clone()>
295 Creates and returns a clone of the NCI.
297 =cut
301     VTABLE PMC *clone() {
302         Parrot_NCI_attributes * const nci_info_self = PARROT_NCI(SELF);
303         Parrot_NCI_attributes *nci_info_ret;
304         void                  *orig_func;
306         PMC * const ret     = Parrot_pmc_new(INTERP, SELF->vtable->base_type);
307         nci_info_ret        = PARROT_NCI(ret);
309         /* FIXME if data is malloced (JIT/i386!) then we need
310          * the length of data here, to memcpy it
311          * ManagedStruct or Buffer?
312          */
313         nci_info_ret->func                  = nci_info_self->func;
314         nci_info_ret->fb_info               = nci_info_self->fb_info;
315         nci_info_ret->orig_func             = nci_info_self->orig_func;
316         nci_info_ret->signature             = nci_info_self->signature;
317         nci_info_ret->pcc_params_signature  = nci_info_self->pcc_params_signature;
318         nci_info_ret->pcc_return_signature  = nci_info_self->pcc_params_signature;
319         nci_info_ret->arity                 = nci_info_self->arity;
320         PObj_get_FLAGS(ret)                 = PObj_get_FLAGS(SELF);
322         return ret;
323     }
327 =item C<INTVAL defined()>
329 Returns whether the NCI is defined.
331 =cut
335     VTABLE INTVAL defined() {
336         Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
337         return nci_info->orig_func != NULL;
338     }
342 =item C<opcode_t *invoke(void *next)>
344 Calls the associated C function, returning C<*next>. If the invocant is a
345 class, the PMC arguments are shifted down.
347 =cut
351     VTABLE opcode_t *invoke(void *next) {
352         Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
353         nci_thunk_t                   func;
354         PMC                          *fb_info;
355         char                         *sig_str;
356         void                         *orig_func;
357         PMC                          *cont;
359         GET_ATTR_orig_func(INTERP, SELF, orig_func);
360         func = (nci_thunk_t)D2FPTR(nci_info->func);
362         GET_ATTR_fb_info(INTERP, SELF, fb_info);
364         if (!func) {
365             /* build the thunk only when necessary */
366             func = build_func(interp, nci_info);
368             if (!func)
369                 Parrot_ex_throw_from_c_args(INTERP, NULL,
370                     EXCEPTION_INVALID_OPERATION,
371                     "attempt to call NULL function");
372         }
374         func(INTERP, SELF, fb_info);
375         cont = INTERP->current_cont;
377         /*
378          * If the NCI function was tailcalled, the return result
379          * is already passed back to the caller of this frame
380          * - see  Parrot_init_ret_nci(). We therefore invoke the
381          * return continuation here, which gets rid of this frame
382          * and returns the real return address
383          */
384         if (cont && cont != NEED_CONTINUATION
385         && (PObj_get_FLAGS(cont) & SUB_FLAG_TAILCALL)) {
386             cont = Parrot_pcc_get_continuation(interp, CURRENT_CONTEXT(interp));
387             next = VTABLE_invoke(INTERP, cont, next);
388         }
390         return (opcode_t *)next;
391     }
395 =item C<INTVAL get_integer()>
397 Returns the function pointer as an integer.
399 =cut
403     VTABLE INTVAL get_integer() {
404         Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
405         if (!nci_info->func)
406             build_func(INTERP, nci_info);
407         return (INTVAL)nci_info->func;
408     }
412 =item C<INTVAL get_bool()>
414 Returns the boolean value of the pointer.
416 =cut
420     VTABLE INTVAL get_bool() {
421         Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
422         return (0 != (INTVAL)nci_info->orig_func);
423     }
427 =item C<METHOD arity()>
429 Return the arity of the NCI (the number of arguments).
431 =cut
434     METHOD arity() {
435         Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
436         INTVAL arity = 0;
438         if (nci_info) {
439             if (!nci_info->func)
440                 build_func(INTERP, nci_info);
441             if (nci_info->func) {
442                 arity = nci_info->arity;
443                 RETURN(INTVAL arity);
444             }
445         }
447         Parrot_ex_throw_from_c_args(INTERP, NULL,
448             EXCEPTION_INVALID_OPERATION,
449             "You cannot get the arity of an undefined NCI.");
450     }
455 =back
457 =head1 SEE ALSO
459 F<docs/pdds/pdd03_calling_conventions.pod>.
461 =head1 HISTORY
463 Initial revision by sean 2002/08/04.
465 =cut
470  * Local variables:
471  *   c-file-style: "parrot"
472  * End:
473  * vim: expandtab shiftwidth=4:
474  */