2 Copyright (C) 2001-2007, The Perl Foundation.
7 src/interpreter.c - Parrot Interpreter
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>
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.
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"
42 # include "parrot/exec.h"
45 #ifdef HAVE_COMPUTED_GOTO
46 # include "parrot/oplib/core_ops_cg.h"
47 # include "parrot/oplib/core_ops_cgp.h"
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
,
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
),
84 __attribute__nonnull__(1)
85 __attribute__nonnull__(2);
87 static void prederef_args(
88 ARGMOD(void **pc_prederef
),
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 */
131 extern int Parrot_exec_run
;
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.
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
;
161 ADD_OP_VAR_PART(interp
, interp
->code
, pc
, n
);
162 for (i
= 1; i
< n
; i
++) {
163 const opcode_t arg
= pc
[i
];
166 PMC
* const sig
= (PMC
*) pc_prederef
[1];
167 type
= SIG_ITEM(sig
, i
- m
);
168 type
&= (PARROT_ARG_TYPE_MASK
| PARROT_ARG_CONSTANT
);
171 type
= opinfo
->types
[i
- 1];
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
);
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
);
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
);
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
);
203 pc_prederef
[i
] = (void *)pc
[i
];
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
;
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
;
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
;
225 real_exception(interp
, NULL
, ARG_OP_NOT_HANDLED
,
226 "Unhandled argtype 0x%x\n", type
);
234 =item C<void do_prederef>
236 This is called from within the run cores to predereference the current
239 C<pc_prederef> is the current opcode, and C<type> is the run core type.
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
;
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
);
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
);
266 real_exception(interp
, NULL
, 1, "Tried to prederef wrong core");
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
283 size_t nb
= interp
->code
->base
.size
/ 16;
286 pi
->branches
= (Prederef_branch
*)mem_sys_allocate(
287 sizeof (Prederef_branch
) * nb
);
288 pi
->n_allocated
= nb
;
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
;
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
319 turn_ev_check(PARROT_INTERP
, int on
)
321 const Prederef
* const pi
= &interp
->code
->prederef
;
326 for (i
= 0; i
< pi
->n_branches
; ++i
) {
327 const size_t offs
= pi
->branches
[i
].offs
;
329 interp
->code
->prederef
.code
[offs
] =
330 ((void **)interp
->op_lib
->op_func_table
)
331 [CORE_OPS_check_events__
];
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.
350 PARROT_WARN_UNUSED_RESULT
351 PARROT_CANNOT_RETURN_NULL
353 get_core_op_lib_init(PARROT_INTERP
, int which
)
355 oplib_init_f init_func
;
357 case PARROT_SWITCH_CORE
:
358 case PARROT_SWITCH_JIT_CORE
:
359 init_func
= PARROT_CORE_SWITCH_OPLIB_INIT
;
361 #ifdef HAVE_COMPUTED_GOTO
362 case PARROT_CGP_CORE
:
363 case PARROT_CGP_JIT_CORE
:
364 init_func
= PARROT_CORE_CGP_OPLIB_INIT
;
366 case PARROT_CGOTO_CORE
:
367 init_func
= PARROT_CORE_CG_OPLIB_INIT
;
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
;
378 real_exception(interp
, NULL
, 1, "Couldn't find init_func for core %d", which
);
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.
396 PARROT_WARN_UNUSED_RESULT
397 PARROT_CANNOT_RETURN_NULL
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.
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.
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
;
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. */
453 void **temp
= (void **)mem_sys_allocate_zeroed(N
* sizeof (void *));
455 void **temp
= (void **)Parrot_memalign_if_possible(256,
456 N
* sizeof (void *));
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__
;
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
];
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
))
483 interp
->code
->prederef
.code
= temp
;
484 /* allocate pic store */
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.
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
);
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
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
;
547 =item C<void * init_jit>
549 Initializes JIT function for the specified opcode and returns it.
555 PARROT_WARN_UNUSED_RESULT
556 PARROT_CAN_RETURN_NULL
558 init_jit(PARROT_INTERP
, SHIM(opcode_t
*pc
))
561 opcode_t
*code_start
;
562 UINTVAL code_size
; /* in opcodes */
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
576 init_prederef(interp
, PARROT_CGP_CORE
);
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
;
594 =item C<void prepare_for_run>
596 Prepares to run the interpreter's run core.
603 prepare_for_run(PARROT_INTERP
)
606 switch (interp
->run_core
) {
607 case PARROT_JIT_CORE
:
608 ignored
= init_jit(interp
, interp
->code
->base
.data
);
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
);
622 #ifdef PARROT_EXEC_OS_AIX
623 extern void* aix_get_toc();
628 =item C<static opcode_t * runops_jit>
630 Runs the JIT code for the specified opcode.
636 PARROT_WARN_UNUSED_RESULT
637 PARROT_CAN_RETURN_NULL
639 runops_jit(PARROT_INTERP
, ARGIN(opcode_t
*pc
))
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
));
649 /* r2 (TOC) needs to point back here so we can return from non-JIT
651 ptrgl_t
.toc
= aix_get_toc();
653 ((jit_f
) D2FPTR(&ptrgl_t
)) (interp
, pc
);
655 jit_f jit_code
= (jit_f
)(init_jit(interp
, pc
));
656 (jit_code
) (interp
, pc
);
667 =item C<static opcode_t * runops_exec>
669 Runs the native executable version of the specified opcode.
675 PARROT_WARN_UNUSED_RESULT
676 PARROT_CAN_RETURN_NULL
678 runops_exec(PARROT_INTERP
, ARGIN(opcode_t
*pc
))
681 opcode_t
*code_start
;
682 UINTVAL code_size
; /* in opcodes */
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
691 init_prederef(interp
, PARROT_CGP_CORE
);
695 if (Parrot_exec_run
== 2) {
698 Interp_core_SET(interp
, PARROT_JIT_CORE
);
699 ignored
= runops_jit(interp
, pc
);
701 Interp_core_SET(interp
, PARROT_EXEC_CORE
);
703 else if (Parrot_exec_run
== 1) {
704 Parrot_exec(interp
, pc
, code_start
, code_end
);
707 run_native(interp
, pc
, code_start
);
719 =item C<static opcode_t * runops_cgp>
721 Runs the C C<goto>, predereferenced core.
727 PARROT_WARN_UNUSED_RESULT
728 PARROT_CANNOT_RETURN_NULL
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
);
742 "Computed goto unavailable in this configuration.\n");
743 Parrot_exit(interp
, 1);
749 =item C<static opcode_t * runops_switch>
751 Runs the C<switch> core.
757 PARROT_WARN_UNUSED_RESULT
758 PARROT_CANNOT_RETURN_NULL
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
);
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.
784 runops_int(PARROT_INTERP
, size_t offset
)
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
));
827 case PARROT_FAST_CORE
:
828 core
= runops_fast_core
;
830 case PARROT_CGOTO_CORE
:
831 #ifdef HAVE_COMPUTED_GOTO
832 core
= runops_cgoto_core
;
834 real_exception(interp
, NULL
, 1, "Error: PARROT_CGOTO_CORE not available");
837 case PARROT_CGP_CORE
:
838 case PARROT_CGP_JIT_CORE
:
839 #ifdef HAVE_COMPUTED_GOTO
842 real_exception(interp
, NULL
, 1, "Error: PARROT_CGP_CORE not available");
845 case PARROT_SWITCH_CORE
:
846 case PARROT_SWITCH_JIT_CORE
:
847 core
= runops_switch
;
849 case PARROT_JIT_CORE
:
851 real_exception(interp
, NULL
, JIT_UNAVAILABLE
,
852 "Error: PARROT_JIT_FLAG is set, "
853 "but interpreter is not JIT_CAPABLE!\n");
858 case PARROT_EXEC_CORE
:
860 real_exception(interp
, NULL
, EXEC_UNAVAILABLE
,
861 "Error: PARROT_EXEC_FLAG is set, "
862 "but interpreter is not EXEC_CAPABLE!\n");
867 case PARROT_GC_DEBUG_CORE
:
868 core
= runops_gc_debug_core
;
871 real_exception(interp
, NULL
, UNIMPLEMENTED
,
872 "ambigious runcore switch used");
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
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.
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
)
916 /* function or CG core - prepare func_table */
917 if (!interp
->evc_func_table
) {
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__
]);
933 =head2 Dynamic Loading Functions
937 =item C<void dynop_register>
939 Register a dynamic oplib.
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));
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
);
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
,
986 /* registering is handled below */
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
);
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
);
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
];
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
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);
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
);
1048 dynop_register_switch(n_old
, n_new
);
1053 =item C<static void dynop_register_xx>
1055 Register C<op_lib> with other cores.
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
;
1069 /* related to CG and CGP ops issue below */
1072 oplib_init_f new_init_func
;
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
));
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
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.
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
);
1118 * XXX running CG and CGP ops currently works only via the wrapper
1120 if (0 /*lib_variant */) {
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
);
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
) {
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!!!
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.
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
;
1197 case PARROT_CGP_CORE
:
1198 case PARROT_CGP_JIT_CORE
:
1199 turn_ev_check(interp
, on
);
1208 =item C<void disable_event_checking>
1210 Restore old function table.
1212 XXX This is only implemented for the function core at present.
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.
1246 enable_event_checking(PARROT_INTERP
)
1249 * put table in place
1251 notify_func_table(interp
, interp
->evc_func_table
, 1);
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>.
1271 * c-file-style: "parrot"
1273 * vim: expandtab shiftwidth=4: