[t] Convert t/pmc/fixedpmcarray.t to PIR and add tests
[parrot.git] / src / pic.c
blob7bd659890105b97c14e2c3a1206f9c2562dfe80f
1 /*
2 Copyright (C) 2004-2009, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/pic.c - Polymorphic Inline Cache
9 =head1 DESCRIPTION
11 The PIC supports inline caching for MMD and object method lookups in
12 prederefed run cores. Additionally opcodes that do some kind of lookup
13 like C<new_p_sc> are changed to faster variants.
15 For non-prederefed run-cores there's a less efficient variant which
16 is basically:
18 * the bytecode segment has an index per cached opcode (code->pic_index)
19 * this index points into pic_store
20 * TODO use the cache in opcodes
22 =head1 OPERATION SCHEME
24 Given this bytecode:
26 0 1 2 3 4 5
27 +--------------+---------------+----+----+-----------------+----------+
28 | infix_ic_p_p | .MMD_SUBTRACT | P5 | P6 | callmethodcc_sc | "method" |
29 +--------------+---------------+----+----+-----------------+----------+
31 In init_prederef the opcodes are replaced with prederef__, operands
32 are replaced with their addresses (&) in the const table or offsets
33 (+) in the register frame:
35 0 1 2 3 4 5
36 +--------------+---------------+----+----+-----------------+----------+
37 | prederef__ | .MMD_SUBTRACT | +P5| +P6| prederef__ |&"method" |
38 +--------------+---------------+----+----+-----------------+----------+
40 we have code->pic_index with an index into pic_store - the pic_index is
41 half the size of the bytecode and addressed with pc_offset/2:
43 0 1 2
44 +---+---+---+
45 | 1 | | 2 |
46 +---+---+---+
48 During predereferencing the opcode gets rewritten to the PIC variant,
49 the constant infix operation number is replaced with a pointer to the MIC
50 in the pic_store at the index pic_index:
52 0 1 2 3
53 +--------------------+-----+----+----+-----------------------+-----+
54 | pic_infix___ic_p_p | MIC1|+P5 |+P6 | pic_callmethodcc___sc | MIC2|
55 +--------------------+-----+----+----+-----------------------+-----+
57 This can be further optimized due to static inlining:
59 0 1 2 3
60 +--------------------+-----+----+----+-----------------------+-----+
61 | pic_inline_sub_p_p | MIC1|+P5 |+P6 | pic_callmethodcc___sc | MIC2|
62 +--------------------+-----+----+----+-----------------------+-----+
64 The opcode is an opcode number for the switched core or the actual code address
65 for the direct-threaded CGP core. With a little help of the JIT system we could
66 also dynamicall create inlined code.
68 Runcores with r/o (mmapped) bytecode can't be rewritten in this way, the
69 lookup of the cache has to be done in the opcode itself.
71 =head2 Functions
73 =over 4
75 =cut
79 #include "parrot/parrot.h"
80 #include "parrot/oplib/ops.h"
81 #include "parrot/runcore_api.h"
82 #include "pmc/pmc_fixedintegerarray.h"
83 #include "pmc/pmc_continuation.h"
84 #ifdef HAVE_COMPUTED_GOTO
85 # include "parrot/oplib/core_ops_cgp.h"
86 #endif
88 #ifdef HAS_JIT
89 # include "parrot/exec.h"
90 # include "jit.h"
91 #endif
93 /* needs a Makefile dependency */
94 /* #include "pmc/pmc_integer.h" */
96 /* XXX Define this in a header file */
97 extern void Parrot_Integer_i_subtract_Integer(Interp* , PMC* pmc, PMC* value);
100 * hack to turn on inlining - just sub_p_p for mops done
103 #define ENABLE_INLINING 0
105 /* HEADERIZER HFILE: include/parrot/pic.h */
107 /* HEADERIZER BEGIN: static */
108 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
110 static int is_pic_func(PARROT_INTERP,
111 ARGIN(void **pc),
112 ARGOUT(Parrot_MIC *mic),
113 ARGIN(Parrot_runcore_t *runcore))
114 __attribute__nonnull__(1)
115 __attribute__nonnull__(2)
116 __attribute__nonnull__(3)
117 __attribute__nonnull__(4)
118 FUNC_MODIFIES(*mic);
120 static int is_pic_param(PARROT_INTERP,
121 ARGIN(void **pc),
122 ARGOUT(Parrot_MIC *mic),
123 opcode_t op)
124 __attribute__nonnull__(1)
125 __attribute__nonnull__(2)
126 __attribute__nonnull__(3)
127 FUNC_MODIFIES(*mic);
129 static int pass_int(PARROT_INTERP,
130 ARGIN(PMC *sig),
131 ARGIN(const char *src_base),
132 ARGIN(const void **src),
133 ARGOUT(char *dest_base),
134 ARGIN(void * const *dest))
135 __attribute__nonnull__(1)
136 __attribute__nonnull__(2)
137 __attribute__nonnull__(3)
138 __attribute__nonnull__(4)
139 __attribute__nonnull__(5)
140 __attribute__nonnull__(6)
141 FUNC_MODIFIES(*dest_base);
143 static int pass_mixed(PARROT_INTERP,
144 ARGIN(PMC *sig),
145 ARGIN(const char *src_base),
146 ARGIN(void * const *src),
147 ARGOUT(char *dest_base),
148 ARGIN(void * const *dest))
149 __attribute__nonnull__(1)
150 __attribute__nonnull__(2)
151 __attribute__nonnull__(3)
152 __attribute__nonnull__(4)
153 __attribute__nonnull__(5)
154 __attribute__nonnull__(6)
155 FUNC_MODIFIES(*dest_base);
157 static int pass_num(PARROT_INTERP,
158 ARGIN(PMC *sig),
159 ARGIN(const char *src_base),
160 ARGIN(const void **src),
161 ARGOUT(char *dest_base),
162 ARGIN(void * const *dest))
163 __attribute__nonnull__(1)
164 __attribute__nonnull__(2)
165 __attribute__nonnull__(3)
166 __attribute__nonnull__(4)
167 __attribute__nonnull__(5)
168 __attribute__nonnull__(6)
169 FUNC_MODIFIES(*dest_base);
171 static int pass_pmc(PARROT_INTERP,
172 ARGIN(PMC *sig),
173 ARGIN(const char *src_base),
174 ARGIN(const void **src),
175 ARGOUT(char *dest_base),
176 ARGIN(void * const *dest))
177 __attribute__nonnull__(1)
178 __attribute__nonnull__(2)
179 __attribute__nonnull__(3)
180 __attribute__nonnull__(4)
181 __attribute__nonnull__(5)
182 __attribute__nonnull__(6)
183 FUNC_MODIFIES(*dest_base);
185 static int pass_str(PARROT_INTERP,
186 ARGIN(PMC *sig),
187 ARGIN(const char *src_base),
188 ARGIN(const void **src),
189 ARGOUT(char *dest_base),
190 ARGIN(void * const *dest))
191 __attribute__nonnull__(1)
192 __attribute__nonnull__(2)
193 __attribute__nonnull__(3)
194 __attribute__nonnull__(4)
195 __attribute__nonnull__(5)
196 __attribute__nonnull__(6)
197 FUNC_MODIFIES(*dest_base);
199 #define ASSERT_ARGS_is_pic_func __attribute__unused__ int _ASSERT_ARGS_CHECK = \
200 PARROT_ASSERT_ARG(interp) \
201 || PARROT_ASSERT_ARG(pc) \
202 || PARROT_ASSERT_ARG(mic) \
203 || PARROT_ASSERT_ARG(runcore)
204 #define ASSERT_ARGS_is_pic_param __attribute__unused__ int _ASSERT_ARGS_CHECK = \
205 PARROT_ASSERT_ARG(interp) \
206 || PARROT_ASSERT_ARG(pc) \
207 || PARROT_ASSERT_ARG(mic)
208 #define ASSERT_ARGS_pass_int __attribute__unused__ int _ASSERT_ARGS_CHECK = \
209 PARROT_ASSERT_ARG(interp) \
210 || PARROT_ASSERT_ARG(sig) \
211 || PARROT_ASSERT_ARG(src_base) \
212 || PARROT_ASSERT_ARG(src) \
213 || PARROT_ASSERT_ARG(dest_base) \
214 || PARROT_ASSERT_ARG(dest)
215 #define ASSERT_ARGS_pass_mixed __attribute__unused__ int _ASSERT_ARGS_CHECK = \
216 PARROT_ASSERT_ARG(interp) \
217 || PARROT_ASSERT_ARG(sig) \
218 || PARROT_ASSERT_ARG(src_base) \
219 || PARROT_ASSERT_ARG(src) \
220 || PARROT_ASSERT_ARG(dest_base) \
221 || PARROT_ASSERT_ARG(dest)
222 #define ASSERT_ARGS_pass_num __attribute__unused__ int _ASSERT_ARGS_CHECK = \
223 PARROT_ASSERT_ARG(interp) \
224 || PARROT_ASSERT_ARG(sig) \
225 || PARROT_ASSERT_ARG(src_base) \
226 || PARROT_ASSERT_ARG(src) \
227 || PARROT_ASSERT_ARG(dest_base) \
228 || PARROT_ASSERT_ARG(dest)
229 #define ASSERT_ARGS_pass_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = \
230 PARROT_ASSERT_ARG(interp) \
231 || PARROT_ASSERT_ARG(sig) \
232 || PARROT_ASSERT_ARG(src_base) \
233 || PARROT_ASSERT_ARG(src) \
234 || PARROT_ASSERT_ARG(dest_base) \
235 || PARROT_ASSERT_ARG(dest)
236 #define ASSERT_ARGS_pass_str __attribute__unused__ int _ASSERT_ARGS_CHECK = \
237 PARROT_ASSERT_ARG(interp) \
238 || PARROT_ASSERT_ARG(sig) \
239 || PARROT_ASSERT_ARG(src_base) \
240 || PARROT_ASSERT_ARG(src) \
241 || PARROT_ASSERT_ARG(dest_base) \
242 || PARROT_ASSERT_ARG(dest)
243 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
244 /* HEADERIZER END: static */
249 =item C<void parrot_PIC_alloc_store(PackFile_ByteCode *cs, size_t n)>
251 Initialize the PIC storage for the given code segment with the capacitiy of
252 holding at least C<n> MIC entries. The PIC_store itself, room for C<n> MICs and
253 some space for PICs is allocated as one piece. MICs are returned from the start
254 of usable memory, PICs from the rear.
256 =cut
260 void
261 parrot_PIC_alloc_store(ARGOUT(PackFile_ByteCode *cs), size_t n)
263 ASSERT_ARGS(parrot_PIC_alloc_store)
264 Parrot_PIC_store *store;
265 size_t size;
268 * estimated 95% of calls are monomorphic, 5% are polymorphic
269 * we need therefore:
271 #define POLYMORPHIC 0.05
272 size_t poly = (size_t)(n * POLYMORPHIC) * sizeof (Parrot_PIC);
274 if (!poly)
275 poly = 2 * sizeof (Parrot_PIC);
277 size = n * sizeof (Parrot_MIC) + poly + sizeof (Parrot_PIC_store);
279 store = (Parrot_PIC_store *)mem_sys_allocate_zeroed(size);
280 store->prev = NULL;
281 cs->pic_store = store;
282 store->pic = (Parrot_PIC *)((char *)store + size);
283 store->usable = poly;
284 store->mic = (Parrot_MIC *)((char*)store + sizeof (Parrot_PIC_store));
285 store->n_mics = n;
290 =item C<void parrot_PIC_destroy(PackFile_ByteCode *cs)>
292 Free memory for the PIC storage.
294 =cut
298 void
299 parrot_PIC_destroy(ARGMOD(PackFile_ByteCode *cs))
301 ASSERT_ARGS(parrot_PIC_destroy)
302 Parrot_PIC_store *store = cs->pic_store;
304 while (store) {
305 Parrot_PIC_store * const prev = store->prev;
306 mem_sys_free(store);
307 store = prev;
310 cs->pic_store = NULL;
315 =item C<int parrot_PIC_op_is_cached(int op_code)>
317 Return true, if the opcode needs a PIC slot.
319 =cut
323 PARROT_CONST_FUNCTION
325 parrot_PIC_op_is_cached(int op_code)
327 ASSERT_ARGS(parrot_PIC_op_is_cached)
328 switch (op_code) {
329 case PARROT_OP_get_params_pc:
330 case PARROT_OP_set_returns_pc:
331 case PARROT_OP_set_args_pc:
332 return 1;
333 default:
334 return 0;
340 =item C<Parrot_MIC* parrot_PIC_alloc_mic(const PARROT_INTERP, size_t n)>
342 Allocate a new MIC structure for the C<n>th cached opcode in this
343 bytecode segement.
345 =cut
349 PARROT_WARN_UNUSED_RESULT
350 PARROT_CANNOT_RETURN_NULL
351 Parrot_MIC*
352 parrot_PIC_alloc_mic(const PARROT_INTERP, size_t n)
354 ASSERT_ARGS(parrot_PIC_alloc_mic)
355 Parrot_PIC_store * const store = interp->code->pic_store;
356 PARROT_ASSERT(n < store->n_mics);
357 return store->mic + n;
362 =item C<Parrot_PIC* parrot_PIC_alloc_pic(PARROT_INTERP)>
364 Allocate a new PIC structure for the C<n>th cached opcode in this
365 bytecode segement.
367 =cut
371 PARROT_WARN_UNUSED_RESULT
372 PARROT_CANNOT_RETURN_NULL
373 Parrot_PIC*
374 parrot_PIC_alloc_pic(PARROT_INTERP)
376 ASSERT_ARGS(parrot_PIC_alloc_pic)
377 Parrot_PIC_store *store = interp->code->pic_store;
378 Parrot_PIC_store *new_store;
380 if (store->usable < sizeof (Parrot_PIC)) {
381 size_t size =
382 (size_t)(store->n_mics * POLYMORPHIC) * sizeof (Parrot_PIC);
384 if (size == 0)
385 size = 2 * sizeof (Parrot_PIC);
387 new_store = (Parrot_PIC_store *)
388 mem_sys_allocate_zeroed(size + sizeof (Parrot_PIC_store));
389 new_store->prev = store;
390 interp->code->pic_store = new_store;
392 new_store->pic = (Parrot_PIC *)((char *)new_store + size
393 + sizeof (Parrot_PIC_store));
394 new_store->usable = size;
396 /* the addon store has only poly-morphic slots
397 * point the monomorphic to the old store */
398 new_store->mic = store->mic;
399 new_store->n_mics = store->n_mics;
400 store = new_store;
402 store->usable -= sizeof (Parrot_PIC);
403 return --store->pic;
408 =item C<void * parrot_pic_opcode(PARROT_INTERP, INTVAL op)>
410 =cut
414 PARROT_WARN_UNUSED_RESULT
415 PARROT_CAN_RETURN_NULL
416 void *
417 parrot_pic_opcode(PARROT_INTERP, INTVAL op)
419 ASSERT_ARGS(parrot_pic_opcode)
420 #ifdef HAVE_COMPUTED_GOTO
421 op_lib_t *cg_lib;
422 #endif
423 const Parrot_runcore_t *core = interp->run_core;
425 if (PARROT_RUNCORE_PREDEREF_OPS_TEST(core)
426 && !PARROT_RUNCORE_CGOTO_OPS_TEST(core))
427 return (void *)op;
428 #ifdef HAVE_COMPUTED_GOTO
429 cg_lib = PARROT_CORE_CGP_OPLIB_INIT(1);
430 return ((void **)cg_lib->op_func_table)[op];
431 #else
432 return NULL;
433 #endif
439 =item C<static int pass_int(PARROT_INTERP, PMC *sig, const char *src_base, const
440 void **src, char *dest_base, void * const *dest)>
442 =cut
446 static int
447 pass_int(PARROT_INTERP, ARGIN(PMC *sig), ARGIN(const char *src_base),
448 ARGIN(const void **src), ARGOUT(char *dest_base), ARGIN(void * const *dest))
450 ASSERT_ARGS(pass_int)
451 int i;
452 int n = VTABLE_elements(interp, sig);
454 for (i = 2; n; ++i, --n) {
455 const INTVAL arg = *(const INTVAL *)(src_base + ((const opcode_t*)src)[i]);
456 *(INTVAL *)(dest_base + ((const opcode_t*)dest)[i]) = arg;
458 return i;
463 =item C<static int pass_num(PARROT_INTERP, PMC *sig, const char *src_base, const
464 void **src, char *dest_base, void * const *dest)>
466 =cut
470 static int
471 pass_num(PARROT_INTERP, ARGIN(PMC *sig), ARGIN(const char *src_base),
472 ARGIN(const void **src), ARGOUT(char *dest_base), ARGIN(void * const *dest))
474 ASSERT_ARGS(pass_num)
475 int i;
476 int n = VTABLE_elements(interp, sig);
478 for (i = 2; n; ++i, --n) {
479 const FLOATVAL arg = *(const FLOATVAL *)(src_base + ((const opcode_t*)src)[i]);
480 *(FLOATVAL *)(dest_base + ((const opcode_t*)dest)[i]) = arg;
482 return i;
487 =item C<static int pass_str(PARROT_INTERP, PMC *sig, const char *src_base, const
488 void **src, char *dest_base, void * const *dest)>
490 =cut
494 static int
495 pass_str(PARROT_INTERP, ARGIN(PMC *sig), ARGIN(const char *src_base),
496 ARGIN(const void **src), ARGOUT(char *dest_base), ARGIN(void * const *dest))
498 ASSERT_ARGS(pass_str)
499 int i;
500 int n = VTABLE_elements(interp, sig);
502 for (i = 2; n; ++i, --n) {
503 STRING * const arg = *(STRING* const *)(src_base + ((const opcode_t*)src)[i]);
504 *(STRING* *)(dest_base + ((const opcode_t*)dest)[i]) = arg;
507 return i;
512 =item C<static int pass_pmc(PARROT_INTERP, PMC *sig, const char *src_base, const
513 void **src, char *dest_base, void * const *dest)>
515 =cut
519 static int
520 pass_pmc(PARROT_INTERP, ARGIN(PMC *sig), ARGIN(const char *src_base),
521 ARGIN(const void **src), ARGOUT(char *dest_base), ARGIN(void * const *dest))
523 ASSERT_ARGS(pass_pmc)
524 int i;
525 int n = VTABLE_elements(interp, sig);
527 for (i = 2; n; ++i, --n) {
528 PMC * const arg = *(PMC* const *)(src_base + ((const opcode_t*)src)[i]);
529 *(PMC* *)(dest_base + ((const opcode_t*)dest)[i])= arg;
531 return i;
536 =item C<static int pass_mixed(PARROT_INTERP, PMC *sig, const char *src_base,
537 void * const *src, char *dest_base, void * const *dest)>
539 =cut
543 static int
544 pass_mixed(PARROT_INTERP, ARGIN(PMC *sig), ARGIN(const char *src_base),
545 ARGIN(void * const *src), ARGOUT(char *dest_base), ARGIN(void * const *dest))
547 ASSERT_ARGS(pass_mixed)
548 int i;
549 INTVAL *bitp;
550 int n = VTABLE_elements(interp, sig);
552 ASSERT_SIG_PMC(sig);
553 GETATTR_FixedIntegerArray_int_array(interp, sig, bitp);
555 for (i = 2; n; ++i, --n) {
556 const INTVAL bits = *bitp++;
557 switch (bits) {
558 case PARROT_ARG_INTVAL:
560 const INTVAL argI = *(const INTVAL *)(src_base + ((const opcode_t*)src)[i]);
561 *(INTVAL *)(dest_base + ((const opcode_t*)dest)[i])= argI;
563 break;
564 case PARROT_ARG_INTVAL|PARROT_ARG_CONSTANT:
565 *(INTVAL *)(dest_base + ((const opcode_t*)dest)[i]) = (INTVAL)(src)[i];
566 break;
567 case PARROT_ARG_FLOATVAL:
569 const FLOATVAL argN = *(const FLOATVAL *)(src_base + ((const opcode_t*)src)[i]);
570 *(FLOATVAL *)(dest_base + ((const opcode_t*)dest)[i])= argN;
572 break;
573 case PARROT_ARG_FLOATVAL|PARROT_ARG_CONSTANT:
575 const FLOATVAL argN = *(const FLOATVAL*)(src)[i];
576 *(FLOATVAL *)(dest_base + ((const opcode_t*)dest)[i])= argN;
578 break;
579 case PARROT_ARG_STRING:
581 STRING *argS = *(STRING * const *)(src_base + ((const opcode_t *)src)[i]);
583 if (argS && PObj_constant_TEST(argS))
584 argS = Parrot_str_new_COW(interp, argS);
586 *(STRING **)(dest_base + ((const opcode_t*)dest)[i]) = argS;
588 break;
589 case PARROT_ARG_STRING|PARROT_ARG_CONSTANT:
591 STRING *argS = (STRING *)(src)[i];
592 if (argS && PObj_constant_TEST(argS))
593 argS = Parrot_str_new_COW(interp, argS);
594 *(STRING **)(dest_base + ((const opcode_t *)dest)[i]) = argS;
596 break;
597 case PARROT_ARG_PMC:
599 PMC* const argP = *(PMC * const *)(src_base + ((const opcode_t*)src)[i]);
600 *(PMC* *)(dest_base + ((const opcode_t*)dest)[i])= argP;
602 break;
603 case PARROT_ARG_PMC|PARROT_ARG_CONSTANT:
605 PMC* const argP = (PMC*)(src)[i];
606 *(PMC* *)(dest_base + ((const opcode_t*)dest)[i])= argP;
608 break;
609 default:
610 Parrot_ex_throw_from_c_args(interp, NULL, 1,
611 "bogus signature 0x%x", bits);
612 break;
615 return i;
620 =item C<int parrot_pic_check_sig(PARROT_INTERP, PMC *sig1, PMC *sig2, int
621 *type)>
623 return argument count and type of the signature or -1 if not pic-able
624 the type PARROT_ARG_CONSTANT stands for mixed types or constants
626 =cut
630 PARROT_WARN_UNUSED_RESULT
632 parrot_pic_check_sig(PARROT_INTERP, ARGIN(PMC *sig1), ARGIN(PMC *sig2),
633 ARGOUT(int *type))
635 ASSERT_ARGS(parrot_pic_check_sig)
636 int i, n, t0;
638 ASSERT_SIG_PMC(sig1);
639 ASSERT_SIG_PMC(sig2);
641 n = VTABLE_elements(interp, sig1);
643 if (n != VTABLE_elements(interp, sig2))
644 return -1;
646 if (!n) {
647 *type = 0;
648 return 0;
651 for (i = 0; i < n; ++i) {
652 int t1 = VTABLE_get_integer_keyed_int(interp, sig1, i);
653 int t2 = VTABLE_get_integer_keyed_int(interp, sig2, i);
655 if (i) {
656 t0 = 0;
658 else {
659 t0 = t1 & PARROT_ARG_TYPE_MASK;
660 *type = t0;
663 if (t1 & PARROT_ARG_CONSTANT) {
664 *type = PARROT_ARG_CONSTANT;
665 t1 &= ~PARROT_ARG_CONSTANT;
668 if (t1 & ~PARROT_ARG_TYPE_MASK)
669 return -1;
671 if (t2 & PARROT_ARG_CONSTANT) {
672 *type = PARROT_ARG_CONSTANT;
673 t2 &= ~PARROT_ARG_CONSTANT;
676 if (t2 & ~PARROT_ARG_TYPE_MASK)
677 return -1;
679 if (t2 != t1)
680 return -1;
682 if (t1 != t0)
683 *type = PARROT_ARG_CONSTANT;
686 return n;
691 =item C<static int is_pic_param(PARROT_INTERP, void **pc, Parrot_MIC *mic,
692 opcode_t op)>
694 =cut
698 static int
699 is_pic_param(PARROT_INTERP, ARGIN(void **pc), ARGOUT(Parrot_MIC *mic), opcode_t op)
701 ASSERT_ARGS(is_pic_param)
702 PMC *sig2;
703 PMC *caller_ctx;
704 opcode_t *args;
705 PMC * const sig1 = (PMC *)(pc[1]);
706 PMC *ctx = CURRENT_CONTEXT(interp);
707 int type = 0;
709 /* check params */
711 if (op == PARROT_OP_set_returns_pc) {
712 PMC * const ccont = Parrot_pcc_get_continuation(interp, ctx);
713 if (!PMC_cont(ccont)->address)
714 return 0;
715 caller_ctx = PMC_cont(ccont)->to_ctx;
716 args = Parrot_pcc_get_results(interp, caller_ctx);
718 else {
719 caller_ctx = Parrot_pcc_get_caller_ctx(interp, ctx);
720 args = interp->current_args;
723 if (args) {
724 const INTVAL const_nr = args[1];
725 int n;
727 /* check current_args signature */
728 sig2 = Parrot_pcc_get_pmc_constant(interp, caller_ctx, const_nr);
729 n = parrot_pic_check_sig(interp, sig1, sig2, &type);
731 if (n == -1)
732 return 0;
734 else {
735 if (VTABLE_elements(interp, sig1) == 0) {
736 sig2 = NULL;
737 type = 0;
739 else
740 return 0;
743 switch (type) {
744 case PARROT_ARG_INTVAL:
745 mic->lru.f.real_function = (funcptr_t)pass_int;
746 break;
747 case PARROT_ARG_FLOATVAL:
748 mic->lru.f.real_function = (funcptr_t)pass_num;
749 break;
750 case PARROT_ARG_STRING:
751 mic->lru.f.real_function = (funcptr_t)pass_str;
752 break;
753 case PARROT_ARG_PMC:
754 mic->lru.f.real_function = (funcptr_t)pass_pmc;
755 break;
756 case PARROT_ARG_CONSTANT:
757 mic->lru.f.real_function = (funcptr_t)pass_mixed;
758 break;
759 default:
760 return 0;
763 mic->m.sig = sig1;
765 /* remember this sig2 - it has to match the other end at call time */
766 mic->lru.u.signature = sig2;
768 return 1;
774 =item C<static int is_pic_func(PARROT_INTERP, void **pc, Parrot_MIC *mic,
775 Parrot_runcore_t *runcore)>
777 =cut
781 static int
782 is_pic_func(PARROT_INTERP, ARGIN(void **pc), ARGOUT(Parrot_MIC *mic),
783 ARGIN(Parrot_runcore_t *runcore))
785 ASSERT_ARGS(is_pic_func)
787 * if we have these opcodes
789 * set_args '..' ...
790 * set_p_pc Px, PFunx
791 * get_results '..' ...
792 * invokecc_p Px
794 * and all args are matching the called sub and we don't have
795 * too many args, and only INTVAL or FLOATVAL, the
796 * whole sequence is replaced by the C<callr> pic opcode.
798 * Oh, I forgot to mention - the to-be-called C function is of
799 * course compiled on-the-fly by the JIT compiler ;)
801 * pc is at set_args
804 PMC *sub, *sig_results;
805 opcode_t *op, n;
806 int flags;
808 PMC * const ctx = CURRENT_CONTEXT(interp);
809 PMC * const sig_args = (PMC *)(pc[1]);
811 ASSERT_SIG_PMC(sig_args);
812 n = VTABLE_elements(interp, sig_args);
813 interp->current_args = (opcode_t*)pc + Parrot_pcc_get_pred_offset(interp, ctx);
814 pc += 2 + n;
815 op = (opcode_t*)pc + Parrot_pcc_get_pred_offset(interp, ctx);
817 if (*op != PARROT_OP_set_p_pc)
818 return 0;
820 do_prederef(pc, interp, runcore);
821 sub = (PMC *)(pc[2]);
823 PARROT_ASSERT(PObj_is_PMC_TEST(sub));
825 if (sub->vtable->base_type != enum_class_Sub)
826 return 0;
828 pc += 3; /* results */
829 op = (opcode_t *)pc + Parrot_pcc_get_pred_offset(interp, ctx);
831 if (*op != PARROT_OP_get_results_pc)
832 return 0;
834 do_prederef(pc, interp, runcore);
835 sig_results = (PMC *)(pc[1]);
836 ASSERT_SIG_PMC(sig_results);
838 Parrot_pcc_set_results(interp, ctx, (opcode_t *)pc + Parrot_pcc_get_pred_offset(interp, ctx));
839 if (!parrot_pic_is_safe_to_jit(interp, sub, sig_args, sig_results, &flags))
840 return 0;
842 mic->lru.f.real_function = parrot_pic_JIT_sub(interp, sub, flags);
843 mic->m.sig = sig_args;
845 return 1;
850 =item C<void parrot_PIC_prederef(PARROT_INTERP, opcode_t op, void **pc_pred,
851 Parrot_runcore_t *core)>
853 Define either the normal prederef function or the PIC stub, if PIC for
854 this opcode function is available. Called from C<do_prederef>.
856 =cut
860 void
861 parrot_PIC_prederef(PARROT_INTERP, opcode_t op, ARGOUT(void **pc_pred),
862 ARGIN(Parrot_runcore_t *core))
864 ASSERT_ARGS(parrot_PIC_prederef)
865 op_func_t * const prederef_op_func = interp->op_lib->op_func_table;
866 opcode_t * const cur_opcode = (opcode_t *)pc_pred;
867 Parrot_MIC *mic = NULL;
869 if (parrot_PIC_op_is_cached(op)) {
870 const PackFile_ByteCode * const cs = interp->code;
871 size_t n = cur_opcode
872 - (opcode_t *)cs->prederef.code;
875 * pic_index is half the size of the code
876 * XXX if it's there - pbc_merge needs updates
878 PARROT_ASSERT(cs->pic_index);
879 n = cs->pic_index->data[n / 2];
880 mic = parrot_PIC_alloc_mic(interp, n);
883 switch (op) {
884 case PARROT_OP_get_params_pc:
885 if (is_pic_param(interp, pc_pred, mic, op)) {
886 pc_pred[1] = (void *)mic;
887 op = PARROT_OP_pic_get_params___pc;
889 break;
890 case PARROT_OP_set_returns_pc:
891 if (is_pic_param(interp, pc_pred, mic, op)) {
892 pc_pred[1] = (void *)mic;
893 op = PARROT_OP_pic_set_returns___pc;
895 break;
896 case PARROT_OP_set_args_pc:
897 if (is_pic_func(interp, pc_pred, mic, core)) {
898 pc_pred[1] = (void *)mic;
899 op = PARROT_OP_pic_callr___pc;
901 break;
902 default:
903 break;
906 /* rewrite opcode */
907 if (PARROT_RUNCORE_PREDEREF_OPS_TEST(core)
908 && !PARROT_RUNCORE_CGOTO_OPS_TEST(core))
909 *pc_pred = (void **)op;
910 else
911 *pc_pred = ((void **)prederef_op_func)[op];
916 =item C<void parrot_pic_find_infix_v_pp(PARROT_INTERP, PMC *left, PMC *right,
917 Parrot_MIC *mic, opcode_t *cur_opcode)>
919 =cut
923 void
924 parrot_pic_find_infix_v_pp(PARROT_INTERP, ARGIN(PMC *left), ARGIN(PMC *right),
925 ARGOUT(Parrot_MIC *mic), ARGOUT(opcode_t *cur_opcode))
927 ASSERT_ARGS(parrot_pic_find_infix_v_pp)
928 /* unused; deprecated */
933 =back
935 =head1 AUTHOR
937 Leopold Toetsch with many hints from Ken Fox.
939 =head1 SEE ALSO
941 L<src/multidispatch.c>, L<src/object.c>, L<src/interp/interpreter.c>,
942 L<ops/core_ops_cgp.c>, L<include/parrot/pic.h>, L<ops/pic.ops>
944 =cut
950 * Local variables:
951 * c-file-style: "parrot"
952 * End:
953 * vim: expandtab shiftwidth=4: