+ --debug is now --imcc-debug; make this more consistent with -D.
[parrot.git] / src / interpreter.c
blobe640f3ce95d93d6fe186c1f94c4b8506aec90453
1 /*
2 Copyright (C) 2001-2007, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/interpreter.c - Parrot Interpreter
9 =head1 DESCRIPTION
11 The interpreter API handles running the operations.
13 The predereferenced code chunk is pre-initialized with the opcode
14 function pointers, addresses, or opnumbers of the C<prederef__>
15 opcode. This opcode then calls the C<do_prederef()> function, which then
16 fills in the real function, address or op number.
18 Because the C<prederef__> opcode returns the same C<pc_prederef> it was
19 passed, the runops loop will re-execute the same location, which will
20 then have the pointer to the real C<prederef> opfunc and C<prederef>
21 args.
23 Pointer arithmetic is used to determine the index into the bytecode
24 corresponding to the currect opcode. The bytecode and prederef arrays
25 have the same number of elements because there is a one-to-one mapping.
27 =head2 Functions
29 =over 4
31 =cut
35 #include "parrot/parrot.h"
36 #include "interp_guts.h"
37 #include "parrot/oplib/core_ops.h"
38 #include "parrot/oplib/core_ops_switch.h"
39 #include "parrot/oplib/ops.h"
40 #include "runops_cores.h"
41 #if JIT_CAPABLE
42 # include "parrot/exec.h"
43 # include "jit.h"
44 #endif
45 #ifdef HAVE_COMPUTED_GOTO
46 # include "parrot/oplib/core_ops_cg.h"
47 # include "parrot/oplib/core_ops_cgp.h"
48 #endif
49 #include "parrot/dynext.h"
52 /* HEADERIZER HFILE: none */
53 /* XXX Needs to get done at the same time as the other interpreter files */
55 /* HEADERIZER BEGIN: static */
57 static void dynop_register_switch(size_t n_old, size_t n_new);
58 static void dynop_register_xx(PARROT_INTERP,
59 size_t n_old,
60 size_t n_new,
61 oplib_init_f init_func)
62 __attribute__nonnull__(1);
64 PARROT_WARN_UNUSED_RESULT
65 PARROT_CANNOT_RETURN_NULL
66 static oplib_init_f get_core_op_lib_init(PARROT_INTERP, int which)
67 __attribute__nonnull__(1);
69 PARROT_WARN_UNUSED_RESULT
70 PARROT_CANNOT_RETURN_NULL
71 static oplib_init_f get_dynamic_op_lib_init(SHIM_INTERP,
72 ARGIN(const PMC *lib))
73 __attribute__nonnull__(2);
75 static void init_prederef(PARROT_INTERP, int which)
76 __attribute__nonnull__(1);
78 static void load_prederef(PARROT_INTERP, int which)
79 __attribute__nonnull__(1);
81 static void notify_func_table(PARROT_INTERP,
82 ARGIN(op_func_t* table),
83 int on)
84 __attribute__nonnull__(1)
85 __attribute__nonnull__(2);
87 static void prederef_args(
88 ARGMOD(void **pc_prederef),
89 PARROT_INTERP,
90 ARGIN(opcode_t *pc),
91 ARGIN(const op_info_t *opinfo))
92 __attribute__nonnull__(1)
93 __attribute__nonnull__(2)
94 __attribute__nonnull__(3)
95 __attribute__nonnull__(4)
96 FUNC_MODIFIES(*pc_prederef);
98 PARROT_WARN_UNUSED_RESULT
99 PARROT_CANNOT_RETURN_NULL
100 static opcode_t * runops_cgp(PARROT_INTERP, ARGIN(opcode_t *pc))
101 __attribute__nonnull__(1)
102 __attribute__nonnull__(2);
104 PARROT_WARN_UNUSED_RESULT
105 PARROT_CAN_RETURN_NULL
106 static opcode_t * runops_exec(PARROT_INTERP, ARGIN(opcode_t *pc))
107 __attribute__nonnull__(1)
108 __attribute__nonnull__(2);
110 PARROT_WARN_UNUSED_RESULT
111 PARROT_CAN_RETURN_NULL
112 static opcode_t * runops_jit(PARROT_INTERP, ARGIN(opcode_t *pc))
113 __attribute__nonnull__(1)
114 __attribute__nonnull__(2);
116 PARROT_WARN_UNUSED_RESULT
117 PARROT_CANNOT_RETURN_NULL
118 static opcode_t * runops_switch(PARROT_INTERP, ARGIN(opcode_t *pc))
119 __attribute__nonnull__(1)
120 __attribute__nonnull__(2);
122 static void stop_prederef(PARROT_INTERP)
123 __attribute__nonnull__(1);
125 static void turn_ev_check(PARROT_INTERP, int on)
126 __attribute__nonnull__(1);
128 /* HEADERIZER END: static */
130 #if EXEC_CAPABLE
131 extern int Parrot_exec_run;
132 #endif
136 =item C<static void prederef_args>
138 Called from C<do_prederef()> to deal with any arguments.
140 C<pc_prederef> is the current opcode.
142 =cut
146 static void
147 prederef_args(ARGMOD(void **pc_prederef), PARROT_INTERP,
148 ARGIN(opcode_t *pc), ARGIN(const op_info_t *opinfo))
150 const PackFile_ConstTable * const const_table = interp->code->const_table;
152 const int regs_n = CONTEXT(interp->ctx)->n_regs_used[REGNO_NUM];
153 const int regs_i = CONTEXT(interp->ctx)->n_regs_used[REGNO_INT];
154 const int regs_p = CONTEXT(interp->ctx)->n_regs_used[REGNO_PMC];
155 const int regs_s = CONTEXT(interp->ctx)->n_regs_used[REGNO_STR];
156 /* prederef var part too */
157 const int m = opinfo->op_count;
158 int n = opinfo->op_count;
159 int i;
161 ADD_OP_VAR_PART(interp, interp->code, pc, n);
162 for (i = 1; i < n; i++) {
163 const opcode_t arg = pc[i];
164 int type;
165 if (i >= m) {
166 PMC * const sig = (PMC*) pc_prederef[1];
167 type = SIG_ITEM(sig, i - m);
168 type &= (PARROT_ARG_TYPE_MASK | PARROT_ARG_CONSTANT);
170 else
171 type = opinfo->types[i - 1];
173 switch (type) {
175 case PARROT_ARG_KI:
176 case PARROT_ARG_I:
177 if (arg < 0 || arg >= regs_i)
178 real_exception(interp, NULL, INTERP_ERROR, "Illegal register number");
179 pc_prederef[i] = (void *)REG_OFFS_INT(arg);
180 break;
182 case PARROT_ARG_N:
183 if (arg < 0 || arg >= regs_n)
184 real_exception(interp, NULL, INTERP_ERROR, "Illegal register number");
185 pc_prederef[i] = (void *)REG_OFFS_NUM(arg);
186 break;
188 case PARROT_ARG_K:
189 case PARROT_ARG_P:
190 if (arg < 0 || arg >= regs_p)
191 real_exception(interp, NULL, INTERP_ERROR, "Illegal register number");
192 pc_prederef[i] = (void *)REG_OFFS_PMC(arg);
193 break;
195 case PARROT_ARG_S:
196 if (arg < 0 || arg >= regs_s)
197 real_exception(interp, NULL, INTERP_ERROR, "Illegal register number");
198 pc_prederef[i] = (void *)REG_OFFS_STR(arg);
199 break;
201 case PARROT_ARG_KIC:
202 case PARROT_ARG_IC:
203 pc_prederef[i] = (void *)pc[i];
204 break;
206 case PARROT_ARG_NC:
207 if (arg < 0 || arg >= const_table->const_count)
208 real_exception(interp, NULL, INTERP_ERROR, "Illegal constant number");
209 pc_prederef[i] = (void *) &const_table->constants[arg]->u.number;
210 break;
212 case PARROT_ARG_SC:
213 if (arg < 0 || arg >= const_table->const_count)
214 real_exception(interp, NULL, INTERP_ERROR, "Illegal constant number");
215 pc_prederef[i] = (void *)const_table->constants[arg]->u.string;
216 break;
218 case PARROT_ARG_PC:
219 case PARROT_ARG_KC:
220 if (arg < 0 || arg >= const_table->const_count)
221 real_exception(interp, NULL, INTERP_ERROR, "Illegal constant number");
222 pc_prederef[i] = (void *)const_table->constants[arg]->u.key;
223 break;
224 default:
225 real_exception(interp, NULL, ARG_OP_NOT_HANDLED,
226 "Unhandled argtype 0x%x\n", type);
227 break;
234 =item C<void do_prederef>
236 This is called from within the run cores to predereference the current
237 opcode.
239 C<pc_prederef> is the current opcode, and C<type> is the run core type.
241 =cut
245 void
246 do_prederef(void **pc_prederef, PARROT_INTERP, int type)
248 const size_t offset = pc_prederef - interp->code->prederef.code;
249 opcode_t * const pc = ((opcode_t *)interp->code->base.data) + offset;
250 const op_info_t *opinfo;
251 size_t n;
253 if (*pc < 0 || *pc >= (opcode_t)interp->op_count)
254 real_exception(interp, NULL, INTERP_ERROR, "Illegal opcode");
255 opinfo = &interp->op_info_table[*pc];
256 /* first arguments - PIC needs it */
257 prederef_args(pc_prederef, interp, pc, opinfo);
258 switch (type) {
259 case PARROT_SWITCH_CORE:
260 case PARROT_SWITCH_JIT_CORE:
261 case PARROT_CGP_CORE:
262 case PARROT_CGP_JIT_CORE:
263 parrot_PIC_prederef(interp, *pc, pc_prederef, type);
264 break;
265 default:
266 real_exception(interp, NULL, 1, "Tried to prederef wrong core");
267 break;
270 * now remember backward branches, invoke and similar opcodes
272 n = opinfo->op_count;
273 if (((opinfo->jump & PARROT_JUMP_RELATIVE) &&
274 opinfo->types[n - 2] == PARROT_ARG_IC &&
275 pc[n - 1] < 0) || /* relative backward branch */
276 (opinfo->jump & PARROT_JUMP_ADDRESS)) {
277 Prederef * const pi = &interp->code->prederef;
279 * first time prederef.branches == NULL:
280 * estimate size to 1/16th of opcodes
282 if (!pi->branches) {
283 size_t nb = interp->code->base.size / 16;
284 if (nb < 8)
285 nb = (size_t)8;
286 pi->branches = (Prederef_branch *)mem_sys_allocate(
287 sizeof (Prederef_branch) * nb);
288 pi->n_allocated = nb;
289 pi->n_branches = 0;
291 else if (pi->n_branches >= pi->n_allocated) {
292 pi->n_allocated = (size_t) (pi->n_allocated * 1.5);
293 pi->branches = (Prederef_branch *)mem_sys_realloc(pi->branches,
294 sizeof (Prederef_branch) * pi->n_allocated);
296 pi->branches[pi->n_branches].offs = offset;
297 pi->branches[pi->n_branches].op = *pc_prederef;
298 ++pi->n_branches;
304 =item C<static void turn_ev_check>
306 Turn on or off event checking for prederefed cores.
308 Fills in the C<event_checker> opcode, or restores original ops in all
309 branch locations of the opcode stream.
311 Note that when C<on> is true, this is being called from the event
312 handler thread.
314 =cut
318 static void
319 turn_ev_check(PARROT_INTERP, int on)
321 const Prederef * const pi = &interp->code->prederef;
322 size_t i;
324 if (!pi->branches)
325 return;
326 for (i = 0; i < pi->n_branches; ++i) {
327 const size_t offs = pi->branches[i].offs;
328 if (on) {
329 interp->code->prederef.code[offs] =
330 ((void **)interp->op_lib->op_func_table)
331 [CORE_OPS_check_events__];
333 else
334 interp->code->prederef.code[offs] = pi->branches[i].op;
340 =item C<static oplib_init_f get_core_op_lib_init>
342 Returns an opcode's library C<op_lib> init function.
344 C<which> is the run core type.
346 =cut
350 PARROT_WARN_UNUSED_RESULT
351 PARROT_CANNOT_RETURN_NULL
352 static oplib_init_f
353 get_core_op_lib_init(PARROT_INTERP, int which)
355 oplib_init_f init_func;
356 switch (which) {
357 case PARROT_SWITCH_CORE:
358 case PARROT_SWITCH_JIT_CORE:
359 init_func = PARROT_CORE_SWITCH_OPLIB_INIT;
360 break;
361 #ifdef HAVE_COMPUTED_GOTO
362 case PARROT_CGP_CORE:
363 case PARROT_CGP_JIT_CORE:
364 init_func = PARROT_CORE_CGP_OPLIB_INIT;
365 break;
366 case PARROT_CGOTO_CORE:
367 init_func = PARROT_CORE_CG_OPLIB_INIT;
368 break;
369 #endif
370 case PARROT_EXEC_CORE: /* normal func core */
371 case PARROT_JIT_CORE: /* normal func core */
372 case PARROT_SLOW_CORE: /* normal func core */
373 case PARROT_FAST_CORE: /* normal func core */
374 case PARROT_GC_DEBUG_CORE: /* normal func core */
375 init_func = PARROT_CORE_OPLIB_INIT;
376 break;
377 default:
378 real_exception(interp, NULL, 1, "Couldn't find init_func for core %d", which);
380 return init_func;
386 =item C<static oplib_init_f get_dynamic_op_lib_init>
388 Returns an dynamic oplib's opcode's library C<op_lib> init function.
390 C<lib> will be a C<ParrotLibrary> PMC.
392 =cut
396 PARROT_WARN_UNUSED_RESULT
397 PARROT_CANNOT_RETURN_NULL
398 static oplib_init_f
399 get_dynamic_op_lib_init(SHIM_INTERP, ARGIN(const PMC *lib))
401 return (oplib_init_f) D2FPTR(PMC_struct_val(lib));
406 =item C<static void load_prederef>
408 C<< interp->op_lib >> = prederefed oplib.
410 =cut
414 static void
415 load_prederef(PARROT_INTERP, int which)
417 const oplib_init_f init_func = get_core_op_lib_init(interp, which);
418 int (*get_op)(const char * name, int full);
420 get_op = interp->op_lib->op_code;
421 interp->op_lib = init_func(1);
422 /* preserve the get_op function */
423 interp->op_lib->op_code = get_op;
424 if (interp->op_lib->op_count != interp->op_count)
425 real_exception(interp, NULL, PREDEREF_LOAD_ERROR,
426 "Illegal op count (%d) in prederef oplib\n",
427 (int)interp->op_lib->op_count);
432 =item C<static void init_prederef>
434 Initialize: load prederef C<func_table>, file prederef.code.
436 =cut
440 static void
441 init_prederef(PARROT_INTERP, int which)
443 load_prederef(interp, which);
444 if (!interp->code->prederef.code) {
445 const size_t N = interp->code->base.size;
446 opcode_t *pc = interp->code->base.data;
447 size_t i, n_pics;
448 void *pred_func;
449 /* Parrot_memalign_if_possible in OpenBSD allocates 256 if you ask for 312
450 -- Need to verify this, it may have been a bug elsewhere. If it works now,
451 we can remove the mem_sys_allocate_zeroed line below. */
452 #if 0
453 void **temp = (void **)mem_sys_allocate_zeroed(N * sizeof (void *));
454 #else
455 void **temp = (void **)Parrot_memalign_if_possible(256,
456 N * sizeof (void *));
457 #endif
459 * calc and remember pred_offset
461 CONTEXT(interp->ctx)->pred_offset = pc - (opcode_t*)temp;
463 /* fill with the prederef__ opcode function */
464 if (which == PARROT_SWITCH_CORE || which == PARROT_SWITCH_JIT_CORE)
465 pred_func = (void*) CORE_OPS_prederef__;
466 else
467 pred_func = ((void **)
468 interp->op_lib->op_func_table)[CORE_OPS_prederef__];
469 for (i = n_pics = 0; i < N;) {
470 op_info_t * const opinfo = &interp->op_info_table[*pc];
471 size_t n;
473 temp[i] = pred_func;
474 n = opinfo->op_count;
475 ADD_OP_VAR_PART(interp, interp->code, pc, n);
476 /* count ops that need a PIC */
477 if (parrot_PIC_op_is_cached(*pc))
478 n_pics++;
479 pc += n;
480 i += n;
483 interp->code->prederef.code = temp;
484 /* allocate pic store */
485 if (n_pics) {
486 /* pic_index is starting from 1 */
487 parrot_PIC_alloc_store(interp->code, n_pics + 1);
494 =item C<static void stop_prederef>
496 Restore the interpreter's op function tables to their initial state.
497 Also recreate the event function pointers. This is only necessary
498 for run-core changes, but we don't know the old run core.
500 =cut
504 static void
505 stop_prederef(PARROT_INTERP)
507 interp->op_func_table = PARROT_CORE_OPLIB_INIT(1)->op_func_table;
508 if (interp->evc_func_table) {
509 mem_sys_free(interp->evc_func_table);
510 interp->evc_func_table = NULL;
512 Parrot_setup_event_func_ptrs(interp);
515 #if EXEC_CAPABLE
519 =item C<void exec_init_prederef>
521 C<< interp->op_lib >> = prederefed oplib
523 The "normal" C<op_lib> has a copy in the interpreter structure - but get
524 the C<op_code> lookup function from standard core prederef has no
525 C<op_info_table>
527 =cut
531 void
532 exec_init_prederef(PARROT_INTERP, void *prederef_arena)
534 load_prederef(interp, PARROT_CGP_CORE);
536 if (!interp->code->prederef.code) {
537 void **temp = (void **)prederef_arena;
539 interp->code->prederef.code = temp;
540 /* TODO */
543 #endif
547 =item C<void * init_jit>
549 Initializes JIT function for the specified opcode and returns it.
551 =cut
555 PARROT_WARN_UNUSED_RESULT
556 PARROT_CAN_RETURN_NULL
557 void *
558 init_jit(PARROT_INTERP, SHIM(opcode_t *pc))
560 #if JIT_CAPABLE
561 opcode_t *code_start;
562 UINTVAL code_size; /* in opcodes */
563 opcode_t *code_end;
564 Parrot_jit_info_t *jit_info;
566 if (interp->code->jit_info)
567 return ((Parrot_jit_info_t *)interp->code->jit_info)->arena.start;
569 code_start = interp->code->base.data;
570 code_size = interp->code->base.size;
571 code_end = code_start + code_size;
573 # if defined HAVE_COMPUTED_GOTO && PARROT_I386_JIT_CGP
574 # ifdef __GNUC__
575 # ifdef PARROT_I386
576 init_prederef(interp, PARROT_CGP_CORE);
577 # endif
578 # endif
579 # endif
581 interp->code->jit_info =
582 jit_info = parrot_build_asm(interp, code_start, code_end,
583 NULL, JIT_CODE_FILE);
585 return jit_info->arena.start;
586 #else
587 UNUSED(interp);
588 return NULL;
589 #endif
594 =item C<void prepare_for_run>
596 Prepares to run the interpreter's run core.
598 =cut
602 void
603 prepare_for_run(PARROT_INTERP)
605 void *ignored;
606 switch (interp->run_core) {
607 case PARROT_JIT_CORE:
608 ignored = init_jit(interp, interp->code->base.data);
609 UNUSED(ignored);
610 break;
611 case PARROT_SWITCH_CORE:
612 case PARROT_SWITCH_JIT_CORE:
613 case PARROT_CGP_CORE:
614 case PARROT_CGP_JIT_CORE:
615 init_prederef(interp, interp->run_core);
616 break;
617 default:
618 break;
622 #ifdef PARROT_EXEC_OS_AIX
623 extern void* aix_get_toc();
624 #endif
628 =item C<static opcode_t * runops_jit>
630 Runs the JIT code for the specified opcode.
632 =cut
636 PARROT_WARN_UNUSED_RESULT
637 PARROT_CAN_RETURN_NULL
638 static opcode_t *
639 runops_jit(PARROT_INTERP, ARGIN(opcode_t *pc))
641 #if JIT_CAPABLE
642 # ifdef PARROT_EXEC_OS_AIX
643 /* AIX calling convention requires that function-call-by-ptr be made
644 through the following struct: */
645 struct ptrgl_t { jit_f functPtr; void *toc; void *env; } ptrgl_t;
646 ptrgl_t.functPtr = (jit_f) D2FPTR(init_jit(interp, pc));
647 ptrgl_t.env = NULL;
649 /* r2 (TOC) needs to point back here so we can return from non-JIT
650 functions */
651 ptrgl_t.toc = aix_get_toc();
653 ((jit_f) D2FPTR(&ptrgl_t)) (interp, pc);
654 # else
655 jit_f jit_code = (jit_f)(init_jit(interp, pc));
656 (jit_code) (interp, pc);
657 # endif
658 #else
659 UNUSED(interp);
660 UNUSED(pc);
661 #endif
662 return NULL;
667 =item C<static opcode_t * runops_exec>
669 Runs the native executable version of the specified opcode.
671 =cut
675 PARROT_WARN_UNUSED_RESULT
676 PARROT_CAN_RETURN_NULL
677 static opcode_t *
678 runops_exec(PARROT_INTERP, ARGIN(opcode_t *pc))
680 #if EXEC_CAPABLE
681 opcode_t *code_start;
682 UINTVAL code_size; /* in opcodes */
683 opcode_t *code_end;
685 code_start = interp->code->base.data;
686 code_size = interp->code->base.size;
687 code_end = code_start + code_size;
688 # if defined HAVE_COMPUTED_GOTO && defined USE_CGP
689 # ifdef __GNUC__
690 # ifdef PARROT_I386
691 init_prederef(interp, PARROT_CGP_CORE);
692 # endif
693 # endif
694 # endif
695 if (Parrot_exec_run == 2) {
696 void *ignored;
697 Parrot_exec_run = 0;
698 Interp_core_SET(interp, PARROT_JIT_CORE);
699 ignored = runops_jit(interp, pc);
700 UNUSED(ignored);
701 Interp_core_SET(interp, PARROT_EXEC_CORE);
703 else if (Parrot_exec_run == 1) {
704 Parrot_exec(interp, pc, code_start, code_end);
706 else
707 run_native(interp, pc, code_start);
709 #else
710 UNUSED(interp);
711 UNUSED(pc);
712 #endif
713 return NULL;
719 =item C<static opcode_t * runops_cgp>
721 Runs the C C<goto>, predereferenced core.
723 =cut
727 PARROT_WARN_UNUSED_RESULT
728 PARROT_CANNOT_RETURN_NULL
729 static opcode_t *
730 runops_cgp(PARROT_INTERP, ARGIN(opcode_t *pc))
732 #ifdef HAVE_COMPUTED_GOTO
733 opcode_t * const code_start = (opcode_t *)interp->code->base.data;
734 opcode_t *pc_prederef;
735 init_prederef(interp, PARROT_CGP_CORE);
736 pc_prederef = (opcode_t*)interp->code->prederef.code + (pc - code_start);
737 pc = cgp_core(pc_prederef, interp);
738 return pc;
739 #else
740 UNUSED(pc);
741 PIO_eprintf(interp,
742 "Computed goto unavailable in this configuration.\n");
743 Parrot_exit(interp, 1);
744 #endif
749 =item C<static opcode_t * runops_switch>
751 Runs the C<switch> core.
753 =cut
757 PARROT_WARN_UNUSED_RESULT
758 PARROT_CANNOT_RETURN_NULL
759 static opcode_t *
760 runops_switch(PARROT_INTERP, ARGIN(opcode_t *pc))
762 opcode_t * const code_start = (opcode_t *)interp->code->base.data;
763 opcode_t *pc_prederef;
764 init_prederef(interp, PARROT_SWITCH_CORE);
765 pc_prederef = (opcode_t*)interp->code->prederef.code + (pc - code_start);
766 pc = switch_core(pc_prederef, interp);
767 return pc;
772 =item C<void runops_int>
774 Run Parrot operations of loaded code segment until an end opcode is
775 reached. Run core is selected depending on the C<Interp_flags>. When a
776 C<restart> opcode is encountered, a different core may be selected and
777 evaluation of opcode continues.
779 =cut
783 void
784 runops_int(PARROT_INTERP, size_t offset)
786 int lo_var_ptr;
787 opcode_t *(*core) (PARROT_INTERP, opcode_t *) = NULL;
789 if (!interp->lo_var_ptr) {
791 * if we are entering the run loop the first time
793 interp->lo_var_ptr = (void *)&lo_var_ptr;
797 * setup event function ptrs
799 if (!interp->save_func_table) {
800 Parrot_setup_event_func_ptrs(interp);
803 interp->resume_offset = offset;
804 interp->resume_flag |= RESUME_RESTART;
806 while (interp->resume_flag & RESUME_RESTART) {
807 opcode_t * const pc = (opcode_t *)
808 interp->code->base.data + interp->resume_offset;
810 interp->resume_offset = 0;
811 interp->resume_flag &= ~(RESUME_RESTART | RESUME_INITIAL);
812 switch (interp->run_core) {
813 case PARROT_SLOW_CORE:
815 core = runops_slow_core;
817 if (Interp_flags_TEST(interp, PARROT_PROFILE_FLAG)) {
818 core = runops_profile_core;
819 if (interp->profile == NULL) {
820 interp->profile = mem_allocate_zeroed_typed(RunProfile);
821 interp->profile->data = (ProfData *)
822 mem_sys_allocate_zeroed((interp->op_count +
823 PARROT_PROF_EXTRA) * sizeof (ProfData));
826 break;
827 case PARROT_FAST_CORE:
828 core = runops_fast_core;
829 break;
830 case PARROT_CGOTO_CORE:
831 #ifdef HAVE_COMPUTED_GOTO
832 core = runops_cgoto_core;
833 #else
834 real_exception(interp, NULL, 1, "Error: PARROT_CGOTO_CORE not available");
835 #endif
836 break;
837 case PARROT_CGP_CORE:
838 case PARROT_CGP_JIT_CORE:
839 #ifdef HAVE_COMPUTED_GOTO
840 core = runops_cgp;
841 #else
842 real_exception(interp, NULL, 1, "Error: PARROT_CGP_CORE not available");
843 #endif
844 break;
845 case PARROT_SWITCH_CORE:
846 case PARROT_SWITCH_JIT_CORE:
847 core = runops_switch;
848 break;
849 case PARROT_JIT_CORE:
850 #if !JIT_CAPABLE
851 real_exception(interp, NULL, JIT_UNAVAILABLE,
852 "Error: PARROT_JIT_FLAG is set, "
853 "but interpreter is not JIT_CAPABLE!\n");
854 #else
855 core = runops_jit;
856 #endif
857 break;
858 case PARROT_EXEC_CORE:
859 #if !EXEC_CAPABLE
860 real_exception(interp, NULL, EXEC_UNAVAILABLE,
861 "Error: PARROT_EXEC_FLAG is set, "
862 "but interpreter is not EXEC_CAPABLE!\n");
863 #else
864 core = runops_exec;
865 #endif
866 break;
867 case PARROT_GC_DEBUG_CORE:
868 core = runops_gc_debug_core;
869 break;
870 default:
871 real_exception(interp, NULL, UNIMPLEMENTED,
872 "ambigious runcore switch used");
873 break;
877 /* run it finally */
878 core(interp, pc);
879 /* if we have fallen out with resume and we were running CGOTO, set
880 * the stacktop again to a sane value, so that restarting the runloop
881 * is ok.
883 if (interp->resume_flag & RESUME_RESTART) {
884 if ((int)interp->resume_offset < 0)
885 real_exception(interp, NULL, 1, "branch_cs: illegal resume offset");
886 stop_prederef(interp);
893 =item C<void Parrot_setup_event_func_ptrs>
895 Setup a C<func_table> containing pointers (or addresses) of the
896 C<check_event__> opcode.
898 TODO: Free it at destroy. Handle run-core changes.
900 =cut
904 void
905 Parrot_setup_event_func_ptrs(PARROT_INTERP)
907 const size_t n = interp->op_count;
908 const oplib_init_f init_func = get_core_op_lib_init(interp, interp->run_core);
909 op_lib_t * const lib = init_func(1);
911 * remember op_func_table
913 interp->save_func_table = lib->op_func_table;
914 if (!lib->op_func_table)
915 return;
916 /* function or CG core - prepare func_table */
917 if (!interp->evc_func_table) {
918 size_t i;
920 interp->evc_func_table = (op_func_t *)mem_sys_allocate(
921 sizeof (op_func_t) * n);
922 for (i = 0; i < n; ++i)
923 interp->evc_func_table[i] = (op_func_t)
924 D2FPTR(((void**)lib->op_func_table)[CORE_OPS_check_events__]);
931 =back
933 =head2 Dynamic Loading Functions
935 =over 4
937 =item C<void dynop_register>
939 Register a dynamic oplib.
941 =cut
945 void
946 dynop_register(PARROT_INTERP, PMC* lib_pmc)
948 op_lib_t *lib, *core;
949 oplib_init_f init_func;
950 op_func_t *new_func_table, *new_evc_func_table;
951 op_info_t *new_info_table;
952 size_t i, n_old, n_new, n_tot;
954 if (n_interpreters > 1) {
955 /* This is not supported because oplibs are always shared.
956 * If we mem_sys_reallocate() the op_func_table while another
957 * interpreter is running using that exact op_func_table,
958 * this will cause problems
959 * Also, the mapping from op name to op number is global even for
960 * dynops (!). The mapping is done by get_op in core_ops.c (even for
961 * dynops) and uses a global hash as a cache and relies on modifications
962 * to the static-scoped core_op_lib data structure to see dynops.
964 real_exception(interp, NULL, 1, "loading a new dynoplib while more than "
965 "one thread is running is not supported.");
968 if (!interp->all_op_libs)
969 interp->all_op_libs = (op_lib_t **)mem_sys_allocate(
970 sizeof (op_lib_t *) * (interp->n_libs + 1));
971 else
972 interp->all_op_libs = (op_lib_t **)mem_sys_realloc(interp->all_op_libs,
973 sizeof (op_lib_t *) * (interp->n_libs + 1));
975 init_func = get_dynamic_op_lib_init(interp, lib_pmc);
976 lib = init_func(1);
978 interp->all_op_libs[interp->n_libs++] = lib;
980 * if we are registering an op_lib variant, called from below
981 * the base names of this lib and the previous one are the same
983 if (interp->n_libs >= 2 &&
984 (strcmp(interp->all_op_libs[interp->n_libs-2]->name,
985 lib->name) == 0)) {
986 /* registering is handled below */
987 return;
990 * when called from yyparse, we have to set up the evc_func_table
992 Parrot_setup_event_func_ptrs(interp);
994 n_old = interp->op_count;
995 n_new = lib->op_count;
996 n_tot = n_old + n_new;
997 core = PARROT_CORE_OPLIB_INIT(1);
999 PARROT_ASSERT(interp->op_count == core->op_count);
1000 new_evc_func_table = (op_func_t *)mem__sys_realloc(interp->evc_func_table,
1001 sizeof (op_func_t) * n_tot);
1002 if (core->flags & OP_FUNC_IS_ALLOCATED) {
1003 new_func_table = (op_func_t *)mem_sys_realloc(core->op_func_table,
1004 sizeof (op_func_t) * n_tot);
1005 new_info_table = (op_info_t *)mem_sys_realloc(core->op_info_table,
1006 sizeof (op_info_t) * n_tot);
1008 else {
1010 * allocate new op_func and info tables
1012 new_func_table = (op_func_t *)mem_sys_allocate(sizeof (op_func_t) * n_tot);
1013 new_info_table = (op_info_t *)mem_sys_allocate(sizeof (op_info_t) * n_tot);
1014 /* copy old */
1015 for (i = 0; i < n_old; ++i) {
1016 new_func_table[i] = interp->op_func_table[i];
1017 new_info_table[i] = interp->op_info_table[i];
1020 /* add new */
1021 for (i = n_old; i < n_tot; ++i) {
1022 new_func_table[i] = ((op_func_t*)lib->op_func_table)[i - n_old];
1023 new_info_table[i] = lib->op_info_table[i - n_old];
1025 * fill new ops of event checker func table
1026 * if we are running a different core, entries are
1027 * changed below
1029 new_evc_func_table[i] =
1030 interp->op_func_table[CORE_OPS_check_events__];
1032 interp->evc_func_table = new_evc_func_table;
1033 interp->save_func_table = new_func_table;
1035 * deinit core, so that it gets rehashed
1037 (void) PARROT_CORE_OPLIB_INIT(0);
1038 /* set table */
1039 core->op_func_table = interp->op_func_table = new_func_table;
1040 core->op_info_table = interp->op_info_table = new_info_table;
1041 core->op_count = interp->op_count = n_tot;
1042 core->flags = OP_FUNC_IS_ALLOCATED | OP_INFO_IS_ALLOCATED;
1043 /* done for plain core */
1044 #ifdef HAVE_COMPUTED_GOTO
1045 dynop_register_xx(interp, n_old, n_new, PARROT_CORE_CGP_OPLIB_INIT);
1046 dynop_register_xx(interp, n_old, n_new, PARROT_CORE_CG_OPLIB_INIT);
1047 #endif
1048 dynop_register_switch(n_old, n_new);
1053 =item C<static void dynop_register_xx>
1055 Register C<op_lib> with other cores.
1057 =cut
1061 static void
1062 dynop_register_xx(PARROT_INTERP,
1063 size_t n_old, size_t n_new, oplib_init_f init_func)
1065 op_lib_t *cg_lib, *new_lib;
1066 op_func_t *ops_addr = NULL;
1067 size_t n_tot;
1068 #if 0
1069 /* related to CG and CGP ops issue below */
1070 STRING *op_variant;
1071 #endif
1072 oplib_init_f new_init_func;
1073 PMC *lib_variant;
1075 n_tot = n_old + n_new;
1076 cg_lib = init_func(1);
1078 if (cg_lib->flags & OP_FUNC_IS_ALLOCATED) {
1079 ops_addr = (op_func_t *)mem_sys_realloc(cg_lib->op_func_table,
1080 n_tot * sizeof (op_func_t));
1082 else {
1083 size_t i;
1085 ops_addr = (op_func_t *)mem_sys_allocate(n_tot * sizeof (op_func_t));
1086 cg_lib->flags = OP_FUNC_IS_ALLOCATED;
1087 for (i = 0; i < n_old; ++i)
1088 ops_addr[i] = cg_lib->op_func_table[i];
1091 * XXX running CG and CGP ops currently works only via the wrapper
1093 * the problem is:
1094 * The actual runcores cg_core and cgp_core are very big functions.
1095 * The C compiler usually addresses "spilled" registers in the C stack.
1096 * The loaded opcode lib is another possibly big function, but with
1097 * a likely different stack layout. Directly jumping around between
1098 * code locations in these two opcode functions works, but access
1099 * to stack-ed (or spilled) variables fails badly.
1101 * We would need to prepare the assembly source of the opcode
1102 * lib so that all variable access on the stack has the same
1103 * layout and compile the prepared assembly to ops_cgp?.o
1105 * The switched core is different anyway, as we can't extend the
1106 * compiled big switch statement with the new cases. We have
1107 * always to use the wrapper__ opcode called from the default case.
1109 #if 0
1110 /* check if the lib_pmc exists with a _xx flavor */
1111 new_init_func = get_op_lib_init(0, 0, lib_pmc);
1112 new_lib = new_init_func(1);
1113 op_variant = Parrot_sprintf_c(interp, "%s_ops%s",
1114 new_lib->name, cg_lib->suffix);
1115 lib_variant = Parrot_load_lib(interp, op_variant, NULL);
1116 #endif
1118 * XXX running CG and CGP ops currently works only via the wrapper
1120 if (0 /*lib_variant */) {
1121 size_t i;
1123 new_init_func = get_dynamic_op_lib_init(interp, lib_variant);
1124 new_lib = new_init_func(1);
1125 for (i = n_old; i < n_tot; ++i)
1126 ops_addr[i] = (new_lib->op_func_table)[i - n_old];
1127 new_lib->op_func_table = ops_addr;
1128 new_lib->op_count = n_tot;
1129 new_init_func((long) ops_addr);
1131 else {
1132 size_t i;
1133 /* if not install wrappers */
1134 /* fill new entries with the wrapper op */
1135 for (i = n_old; i < n_tot; ++i)
1136 ops_addr[i] = (cg_lib->op_func_table)[CORE_OPS_wrapper__];
1139 * if we are running this core, update event check ops
1141 if ((int)interp->run_core == cg_lib->core_type) {
1142 size_t i;
1144 for (i = n_old; i < n_tot; ++i)
1145 interp->evc_func_table[i] =
1146 (op_func_t)ops_addr[CORE_OPS_check_events__];
1147 interp->save_func_table = ops_addr;
1150 * tell the cg_core about the new jump table
1152 cg_lib->op_func_table = ops_addr;
1153 cg_lib->op_count = n_tot;
1154 init_func((long) ops_addr);
1159 =item C<static void dynop_register_switch>
1161 RT#48260: Not yet documented!!!
1163 =cut
1167 static void
1168 dynop_register_switch(size_t n_old, size_t n_new)
1170 op_lib_t * const lib = PARROT_CORE_SWITCH_OPLIB_INIT(1);
1171 lib->op_count = n_old + n_new;
1176 =item C<static void notify_func_table>
1178 Tell the interpreter's running core about the new function table.
1180 =cut
1184 static void
1185 notify_func_table(PARROT_INTERP, ARGIN(op_func_t* table), int on)
1187 const oplib_init_f init_func = get_core_op_lib_init(interp, interp->run_core);
1189 init_func((long) table);
1190 switch (interp->run_core) {
1191 case PARROT_SLOW_CORE: /* normal func core */
1192 case PARROT_FAST_CORE: /* normal func core */
1193 case PARROT_CGOTO_CORE: /* cgoto address list */
1194 PARROT_ASSERT(table);
1195 interp->op_func_table = table;
1196 break;
1197 case PARROT_CGP_CORE:
1198 case PARROT_CGP_JIT_CORE:
1199 turn_ev_check(interp, on);
1200 break;
1201 default:
1202 break;
1208 =item C<void disable_event_checking>
1210 Restore old function table.
1212 XXX This is only implemented for the function core at present.
1214 =cut
1218 PARROT_API
1219 void
1220 disable_event_checking(PARROT_INTERP)
1223 * restore func table
1225 PARROT_ASSERT(interp->save_func_table);
1226 notify_func_table(interp, interp->save_func_table, 0);
1231 =item C<void enable_event_checking>
1233 Replace func table with one that does event checking for all opcodes.
1235 NOTE: C<enable_event_checking()> is called async by the event handler
1236 thread. All action done from here has to be async safe.
1238 XXX This is only implemented for the function core at present.
1240 =cut
1244 PARROT_API
1245 void
1246 enable_event_checking(PARROT_INTERP)
1249 * put table in place
1251 notify_func_table(interp, interp->evc_func_table, 1);
1257 =back
1259 =head1 SEE ALSO
1261 F<include/parrot/interpreter.h>, F<src/inter_cb.c>, F<src/inter_create.c>,
1262 F<src/inter_misc.c>, F<src/inter_run.c>.
1264 =cut
1270 * Local variables:
1271 * c-file-style: "parrot"
1272 * End:
1273 * vim: expandtab shiftwidth=4: