add generated_hello.pbc to examples-clean
[parrot.git] / src / pmc / nci.pmc
blob21defdd8dac78c81bbd9728e8c788e7e467e39d6
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 */
53 static void
54 pcc_params(PARROT_INTERP, ARGIN(STRING *sig), ARGMOD(Parrot_NCI_attributes *nci_info),
55                 size_t sig_length)
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 */
64     char         static_buf[16];
65     char * const sig_buf = sig_length <= sizeof static_buf ?
66                             static_buf :
67                             (char *)mem_sys_allocate(buf_length);
69     size_t j = 0;
70     size_t i;
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);
77         switch (c) {
78           case (INTVAL)'0':    /* null ptr or such - doesn't consume a reg */
79             break;
80           case (INTVAL)'f':
81           case (INTVAL)'N':
82           case (INTVAL)'d':
83             sig_buf[j++] = 'N';
84             break;
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 */
90             sig_buf[j++] = 'I';
91             break;
92           case (INTVAL)'S':
93           case (INTVAL)'t':   /* string, pass a cstring */
94             sig_buf[j++] = 'S';
95             break;
96           case (INTVAL)'J':   /* interpreter */
97             break;
98           case (INTVAL)'p':   /* push pmc->data */
99           case (INTVAL)'P':   /* push PMC * */
100           case (INTVAL)'V':   /* push PMC * */
101           case (INTVAL)'2':
102           case (INTVAL)'3':
103           case (INTVAL)'4':
104             sig_buf[j++] = 'P';
105             break;
106           case (INTVAL)'v':
107             /* null return */
108             if (j == 0)
109                 sig_buf[j++] = '\0';
110             break;
111           case (INTVAL)'O':   /* push PMC * invocant */
112             sig_buf[j++] = 'P';
113             sig_buf[j++] = 'i';
114             break;
115           case (INTVAL)'@':   /* push PMC * slurpy */
116             sig_buf[j++] = 'P';
117             sig_buf[j++] = 's';
118             break;
119           case (INTVAL)'b': /* buffer (void*) pass Buffer_bufstart(SReg) */
120           case (INTVAL)'B': /* buffer (void**) pass &Buffer_bufstart(SReg) */
121             sig_buf[j++] = 'S';
122             break;
123           default:
124             Parrot_ex_throw_from_c_args(interp, NULL,
125                     EXCEPTION_JIT_ERROR,
126                     "Unknown param Signature %c\n", (char)c);
127             break;
128         }
129     }
131     PARROT_ASSERT(j < buf_length);
132     sig_buf[j++] = '\0';
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
149 static nci_thunk_t
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. */
183     /* MMD fields */
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.
193 =cut
197     METHOD get_multisig() {
198         PMC *sig;
199         GET_ATTR_multi_sig(INTERP, SELF, sig);
200         if (PMC_IS_NULL(sig))
201             sig = PMCNULL;
202         RETURN(PMC *sig);
203     }
207 =item C<METHOD set_raw_nci_ptr(void *func)>
209 Sets the specified function pointer and raw flag.
211 =cut
215     METHOD make_raw_nci(PMC *func) {
216         VTABLE_set_pointer(interp, SELF, (void *)func);
217     }
221 =item C<void init()>
223 Initializes the NCI with a C<NULL> function pointer.
225 =cut
229     VTABLE void init() {
230         /* Mark that we're not a raw NCI. */
231         PObj_flag_CLEAR(private2, SELF);
232         PObj_custom_mark_SET(SELF);
233     }
237 =item C<void set_pointer_keyed_str(STRING *key, void *func)>
239 Sets the specified function pointer and signature (C<*key>).
241 =cut
245     VTABLE void set_pointer(void *ptr) {
246         SET_ATTR_orig_func(INTERP, SELF, ptr);
247         PObj_flag_SET(private2, SELF);
248     }
250     VTABLE void *get_pointer() {
251         return PARROT_NCI(SELF)->orig_func;
252     }
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);
267         }
269         nci_info->signature = key;
270     }
274 =item C<void mark()>
276 Mark any referenced strings and PMCs.
278 =cut
281     VTABLE void mark() {
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);
291         }
292     }
296 =item C<PMC *clone()>
298 Creates and returns a clone of the NCI.
300 =cut
304     VTABLE PMC *clone() {
305         Parrot_NCI_attributes * const nci_info_self = PARROT_NCI(SELF);
306         Parrot_NCI_attributes *nci_info_ret;
307         void                  *orig_func;
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?
315          */
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);
325         return ret;
326     }
330 =item C<INTVAL defined()>
332 Returns whether the NCI is defined.
334 =cut
338     VTABLE INTVAL defined() {
339         Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
340         return nci_info->orig_func != NULL;
341     }
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.
350 =cut
354     VTABLE opcode_t *invoke(void *next) {
355         Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
356         nci_thunk_t                   func;
357         PMC                          *fb_info;
358         char                         *sig_str;
359         void                         *orig_func;
360         PMC                          *cont;
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);
369         if (!func) {
370             /* build the thunk only when necessary */
371             func = build_func(interp, nci_info);
373             if (!func)
374                 Parrot_ex_throw_from_c_args(INTERP, NULL,
375                     EXCEPTION_INVALID_OPERATION,
376                     "attempt to call NULL function");
377         }
379         func(INTERP, SELF, fb_info);
380         cont = INTERP->current_cont;
382         /*
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
388          */
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);
393         }
395         return (opcode_t *)next;
396     }
400 =item C<INTVAL get_integer()>
402 Returns the function pointer as an integer.
404 =cut
408     VTABLE INTVAL get_integer() {
409         Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
410         if (!nci_info->func)
411             build_func(INTERP, nci_info);
412         return (INTVAL)nci_info->func;
413     }
417 =item C<INTVAL get_bool()>
419 Returns the boolean value of the pointer.
421 =cut
425     VTABLE INTVAL get_bool() {
426         Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
427         return (0 != (INTVAL)nci_info->orig_func);
428     }
432 =item C<METHOD arity()>
434 Return the arity of the NCI (the number of arguments).
436 =cut
439     METHOD arity() {
440         Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF);
441         INTVAL arity = 0;
443         if (nci_info) {
444             if (!nci_info->func)
445                 build_func(INTERP, nci_info);
446             if (nci_info->func) {
447                 arity = nci_info->arity;
448                 RETURN(INTVAL arity);
449             }
450         }
452         Parrot_ex_throw_from_c_args(INTERP, NULL,
453             EXCEPTION_INVALID_OPERATION,
454             "You cannot get the arity of an undefined NCI.");
455     }
460 =back
462 =head1 SEE ALSO
464 F<docs/pdds/pdd03_calling_conventions.pod>.
466 =head1 HISTORY
468 Initial revision by sean 2002/08/04.
470 =cut
475  * Local variables:
476  *   c-file-style: "parrot"
477  * End:
478  * vim: expandtab shiftwidth=4:
479  */