fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / runcore / cores.c
blob04a2404741c9d695132c9c7d9d772ac43cc74aaa
1 /*
2 Copyright (C) 2001-2009, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/runcore/cores.c - Parrot's execution runcores
9 =head1 DESCRIPTION
11 During execution, the runcore is like the heart of Parrot. The runcore
12 controls calling the various opcodes with the correct data, and making
13 sure that program flow moves properly. Some runcores, such as the
14 I<precomputed C goto runcore> are optimized for speed and don't perform
15 many tasks beyond finding and dispatching opcodes. Other runcores,
16 such as the I<GC-Debug>, I<debug> and I<profiling> runcores help with
17 typical software maintenance and analysis tasks. We'll talk about all
18 of these throughout the chapter.
20 Runcores must pass execution to each opcode in the incoming bytecode
21 stream. This is called I<dispatching> the opcodes. Because the different
22 runcores are structured in different ways, the opcodes themselves must
23 be formated differently. The opcode compiler compiles opcodes into a
24 number of separate formats, depending on what runcores are included in
25 the compiled Parrot. Because of this, understanding opcodes first
26 requires an understanding of the Parrot runcores.
28 Parrot has multiple runcores. Some are useful for particular maintenance
29 tasks, some are only available as optimizations in certain compilers,
30 some are intended for general use, and some are just interesing flights
31 of fancy with no practical benefits. Here we list the various runcores,
32 their uses, and their benefits.
34 =head2 Slow Core
36 The slow core is a basic runcore design that treats each opcode as a
37 separate function at the C level. Each function is called, and returns
38 the address of the next opcode to be called by the core. The slow core
39 performs bounds checking to ensure that the next opcode to be called is
40 properly in bounds, and not somewhere random in memory. Because of this
41 modular approach where opcodes are treated as separate executable
42 entities many other runcores, especially diagnostic and maintenance
43 cores are based on this design. The program counter C<pc> is the current
44 index into the bytecode stream. Here is a pseudocode representation for
45 how the slow core works:
47 while(1) {
48 pc = NEXT_OPCODE;
49 if(pc < LOW_BOUND || pc > HIGH_BOUND)
50 throw exception;
51 DISPATCH_OPCODE(pc);
52 UPDATE_INTERPRETER();
55 =head2 Fast Core
57 The fast core is a bare-bones core that doesn't do any of the
58 bounds-checking or context updating that the slow core does. The fast
59 core is the way Parrot should run, and is used to find and debug places
60 where execution strays outside of its normal bounds. In pseudocode, the
61 fast core is very much like the slow core except it doesn't do the bounds
62 checking between each instruction, and doesn't update the interpreter's
63 current context for each dispatch.
65 while(1) {
66 pc = NEXT_OPCODE;
67 DISPATCH_OPCODE(pc);
70 =head2 Switch Core
72 As its name implies, the switch core uses a gigantic C C<switch / case>
73 structure to execute opcodes. Here's a brief example of how this
74 architecture works:
76 for( ; ; ++current_opcode) {
77 switch(*current_opcode) {
78 case opcode_1:
79 ...
80 case opcode_2:
81 ...
82 case opcode_3:
83 ...
87 This is quite a fast architecture for dispatching opcodes because it all
88 happens within a single function. The only operations performed between
89 opcodes is a jump back to the top of the loop, incrementing the opcode
90 pointer, dereferencing the opcode pointer, and then a jump to the C<case>
91 statement for the next opcode.
93 =head2 Computed Goto Core
95 I<Computed Goto> is a feature of some C compilers where a label is
96 treated as a piece of data that can be stored as a C<void *> pointer. Each
97 opcode becomes simply a label in a very large function, and pointers to the
98 labels are stored in a large array. Calling an opcode is as easy as taking
99 that opcode's number as the index of the label array, and calling the
100 associated label. Sound complicated? It is a little, especially to C
101 programmers who are not used to using labels, much less treating them as
102 first class data items.
104 Notice that computed goto is a feature only available in some compilers
105 such as GCC, and will not be available in every distribution of Parrot,
106 depending what compilers were used to build it.
108 As was mentioned earlier, not all compilers support computed goto, which
109 means that this core will not be built on platforms that don't support it.
110 However, it's still an interesting topic to study so we will look at it
111 briefly here. For compilers that support it, computed goto labels are
112 C<void **> values. In the computed goto core, all the labels represent
113 different opcodes, so they are stored in an array:
115 void *my_labels[] = {
116 &&label1,
117 &&label2,
118 &&label3
121 label1:
123 label2:
125 label3:
128 Jumping to one of these labels is done with a command like this:
130 goto *my_labels[opcode_number];
132 Actually, opcodes are pointed to by an C<opcode_t *> pointer, and all
133 opcodes are stored sequentially in memory, so the actual jump in the
134 computed goto core must increment the pointer and then jump to the new
135 version. In C it looks something like this:
137 goto *my_labels[*(current_opcode += 1)];
139 Each opcode is an index into the array of labels, and at the end of each
140 opcode an instruction like this is performed to move to the next opcode
141 in series, or else some kind of control flow occurs that moves it to a
142 non-sequential location:
144 goto *my_lables[*(current_opcode = destination)];
146 These are simplifications on what really happens in this core, because
147 the actual code has been optimized quite a bit from what has been
148 presented here. However, as we shall see with the precomputed goto core,
149 it isn't optimized as aggressively as is possible.
151 =head2 Precomputed Goto Core
153 The precomputed goto core is an amazingly fast optimized core that uses
154 the same computed goto feature, but performs the array dereferencing
155 before the core even starts. The compiled bytecode is fed into a
156 preprocessor that converts the bytecode instruction numbers into label
157 pointer values. In the computed goto core, you have this
158 operation to move to the next opcode:
160 goto *my_labels[*(current_opcode += 1)];
162 This single line of code is deceptively complex. A number of machine code
163 operations must be performed to complete this step: The value of
164 C<current_opcode> must be incremented to the next value, that value must
165 be dereferenced to find the opcode value. In C, arrays are pointers, so
166 C<my_labels> gets dereferenced and an offset is taken from it to find
167 the stored label reference. That label reference is then dereferenced, and
168 the jump is performed.
170 That's a lot of steps to execute before we can jump to the next opcode.
171 What if each opcode value was replaced with the value of the jump
172 label beforehand? If C<current_opcode> points to a label pointer directly,
173 we don't need to perform an additional dereference on the array at all. We
174 can replace that entire mess above with this line:
176 goto **(current_opcode += 1);
178 That's far fewer machine instructions to execute before we can move to the
179 next opcode, which means faster throughput. Remember that whatever dispatch
180 mechanism is used will be called after every single opcode, and some large
181 programs may have millions of opcodes! Every single machine instruction
182 that can be cut out of the dispatch mechanism could increase the execution
183 speed of Parrot in a significant and noticable way. B<The dispatch mechanism
184 used by the various runcores is hardly the largest performance bottleneck in
185 Parrot anyway, but we like to use faster cores to shave every little bit of
186 speed out of the system>.
188 The caveat of course is that the predereferenced computed goto core is only
189 available with compilers that support computed goto, such as GCC. Parrot
190 will not have access to this core if it is built with a different compiler.
192 =head2 Tracing Core
194 To come.
196 =head2 Profiling Core
198 The profiling core analyzes the performance of Parrot, and helps to
199 determine where bottlenecks and trouble spots are in the programs that
200 run on top of Parrot. When Parrot calls a PIR subroutine it sets up the
201 environment, allocates storage for the passed parameters and the return
202 values, passes the parameters, and calls a new runcore to execute it. To
203 calculate the amount of time that each subroutine takes, we need to
204 measure the amount of time spent in each runcore from the time the core
205 begins to the time the core executes. The profiling core does exactly
206 this, acting very similarly to a slow core but also measuring the amount
207 of time it takes for the core to complete. The tracing core actually
208 keeps track of a few additional values, including the number of GC cycles
209 run while in the subroutine, the number of each opcode called and the
210 number of calls to each subroutine made. All this information is helpfully
211 printed to the STDERR output for later analysis.
213 =head2 GC Debug Core
215 Parrot's garbage collector has been known as a weakness in the system
216 for several years. In fact, the garbage collector and memory management
217 subsystem was one of the last systems to be improved and rewritten before
218 the release of version 1.0. It's not that garbage collection isn't
219 important, but instead that it was so hard to do earlier in the project.
221 Early on when the GC was such a weakness, and later when the GC was under
222 active development, it was useful to have an operational mode that would
223 really exercise the GC and find bugs that otherwise could hide by sheer
224 chance. The GC debug runcore was this tool. The core executes a complete
225 collection iteration between every single opcode. The throughput
226 performance is terrible, but that's not the point: it's almost guaranteed
227 to find problems in the memory system if they exist.
229 =head2 Debug Core
231 The debug core works like a normal software debugger, such as GDB. The
232 debug core executes each opcode, and then prompts the user to enter a
233 command. These commands can be used to continue execution, step to the
234 next opcode, or examine and manipulate data from the executing program.
237 =head2 Functions
239 =over 4
241 =cut
245 #include "parrot/runcore_api.h"
246 #include "parrot/embed.h"
247 #include "parrot/runcore_trace.h"
248 #include "cores.str"
250 #include "parrot/oplib/ops.h"
251 #include "parrot/oplib/core_ops.h"
252 #include "parrot/dynext.h"
254 #include "pmc/pmc_sub.h"
255 #include "pmc/pmc_callcontext.h"
257 #ifdef WIN32
258 # define getpid _getpid
259 #endif
261 /* HEADERIZER HFILE: include/parrot/runcore_api.h */
263 /* HEADERIZER BEGIN: static */
264 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
266 PARROT_WARN_UNUSED_RESULT
267 PARROT_CAN_RETURN_NULL
268 static opcode_t * runops_debugger_core(PARROT_INTERP,
269 SHIM(Parrot_runcore_t *runcore),
270 ARGIN(opcode_t *pc))
271 __attribute__nonnull__(1)
272 __attribute__nonnull__(3);
274 PARROT_WARN_UNUSED_RESULT
275 PARROT_CAN_RETURN_NULL
276 static opcode_t * runops_exec_core(PARROT_INTERP,
277 ARGIN(Parrot_runcore_t *runcore),
278 ARGIN(opcode_t *pc))
279 __attribute__nonnull__(1)
280 __attribute__nonnull__(2)
281 __attribute__nonnull__(3);
283 PARROT_WARN_UNUSED_RESULT
284 PARROT_CAN_RETURN_NULL
285 static opcode_t * runops_fast_core(PARROT_INTERP,
286 SHIM(Parrot_runcore_t *runcore),
287 ARGIN(opcode_t *pc))
288 __attribute__nonnull__(1)
289 __attribute__nonnull__(3);
291 PARROT_WARN_UNUSED_RESULT
292 PARROT_CAN_RETURN_NULL
293 static opcode_t * runops_gc_debug_core(PARROT_INTERP,
294 SHIM(Parrot_runcore_t *runcore),
295 ARGIN(opcode_t *pc))
296 __attribute__nonnull__(1)
297 __attribute__nonnull__(3);
299 PARROT_WARN_UNUSED_RESULT
300 PARROT_CAN_RETURN_NULL
301 static opcode_t * runops_slow_core(PARROT_INTERP,
302 SHIM(Parrot_runcore_t *runcore),
303 ARGIN(opcode_t *pc))
304 __attribute__nonnull__(1)
305 __attribute__nonnull__(3);
307 PARROT_WARN_UNUSED_RESULT
308 PARROT_CAN_RETURN_NULL
309 static opcode_t * runops_trace_core(PARROT_INTERP, ARGIN(opcode_t *pc))
310 __attribute__nonnull__(1)
311 __attribute__nonnull__(2);
313 #define ASSERT_ARGS_runops_debugger_core __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
314 PARROT_ASSERT_ARG(interp) \
315 , PARROT_ASSERT_ARG(pc))
316 #define ASSERT_ARGS_runops_exec_core __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
317 PARROT_ASSERT_ARG(interp) \
318 , PARROT_ASSERT_ARG(runcore) \
319 , PARROT_ASSERT_ARG(pc))
320 #define ASSERT_ARGS_runops_fast_core __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
321 PARROT_ASSERT_ARG(interp) \
322 , PARROT_ASSERT_ARG(pc))
323 #define ASSERT_ARGS_runops_gc_debug_core __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
324 PARROT_ASSERT_ARG(interp) \
325 , PARROT_ASSERT_ARG(pc))
326 #define ASSERT_ARGS_runops_slow_core __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
327 PARROT_ASSERT_ARG(interp) \
328 , PARROT_ASSERT_ARG(pc))
329 #define ASSERT_ARGS_runops_trace_core __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
330 PARROT_ASSERT_ARG(interp) \
331 , PARROT_ASSERT_ARG(pc))
332 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
333 /* HEADERIZER END: static */
338 =item C<void Parrot_runcore_slow_init(PARROT_INTERP)>
340 Registers the slow runcore with Parrot.
342 =cut
346 void
347 Parrot_runcore_slow_init(PARROT_INTERP)
349 ASSERT_ARGS(Parrot_runcore_slow_init)
351 Parrot_runcore_t * const coredata = mem_gc_allocate_zeroed_typed(interp, Parrot_runcore_t);
352 coredata->name = CONST_STRING(interp, "slow");
353 coredata->id = PARROT_SLOW_CORE;
354 coredata->opinit = PARROT_CORE_OPLIB_INIT;
355 coredata->runops = runops_slow_core;
356 coredata->prepare_run = NULL;
357 coredata->destroy = NULL;
358 coredata->flags = 0;
360 PARROT_RUNCORE_FUNC_TABLE_SET(coredata);
362 Parrot_runcore_register(interp, coredata);
368 =item C<void Parrot_runcore_fast_init(PARROT_INTERP)>
370 Registers the fast runcore with Parrot.
372 =cut
376 void
377 Parrot_runcore_fast_init(PARROT_INTERP)
379 ASSERT_ARGS(Parrot_runcore_fast_init)
381 Parrot_runcore_t * const coredata = mem_gc_allocate_zeroed_typed(interp, Parrot_runcore_t);
382 coredata->name = CONST_STRING(interp, "fast");
383 coredata->id = PARROT_FAST_CORE;
384 coredata->opinit = PARROT_CORE_OPLIB_INIT;
385 coredata->runops = runops_fast_core;
386 coredata->destroy = NULL;
387 coredata->prepare_run = NULL;
388 coredata->flags = 0;
390 PARROT_RUNCORE_FUNC_TABLE_SET(coredata);
392 Parrot_runcore_register(interp, coredata);
398 =item C<void Parrot_runcore_exec_init(PARROT_INTERP)>
400 Registers the exec runcore with Parrot.
402 =cut
406 void
407 Parrot_runcore_exec_init(PARROT_INTERP)
409 ASSERT_ARGS(Parrot_runcore_exec_init)
411 Parrot_runcore_t * const coredata = mem_gc_allocate_zeroed_typed(interp, Parrot_runcore_t);
412 coredata->name = CONST_STRING(interp, "exec");
413 coredata->id = PARROT_EXEC_CORE;
414 coredata->opinit = PARROT_CORE_OPLIB_INIT;
415 coredata->runops = runops_exec_core;
416 coredata->destroy = NULL;
417 coredata->prepare_run = NULL;
418 coredata->flags = 0;
420 Parrot_runcore_register(interp, coredata);
426 =item C<void Parrot_runcore_gc_debug_init(PARROT_INTERP)>
428 Registers the gc_debug runcore with Parrot.
430 =cut
434 void
435 Parrot_runcore_gc_debug_init(PARROT_INTERP)
437 ASSERT_ARGS(Parrot_runcore_gc_debug_init)
439 Parrot_runcore_t * const coredata = mem_gc_allocate_zeroed_typed(interp, Parrot_runcore_t);
440 coredata->name = CONST_STRING(interp, "gc_debug");
441 coredata->id = PARROT_GC_DEBUG_CORE;
442 coredata->opinit = PARROT_CORE_OPLIB_INIT;
443 coredata->runops = runops_gc_debug_core;
444 coredata->destroy = NULL;
445 coredata->prepare_run = NULL;
446 coredata->flags = 0;
448 PARROT_RUNCORE_FUNC_TABLE_SET(coredata);
450 Parrot_runcore_register(interp, coredata);
456 =item C<void Parrot_runcore_debugger_init(PARROT_INTERP)>
458 Registers the debugger runcore with Parrot.
460 =cut
464 void
465 Parrot_runcore_debugger_init(PARROT_INTERP)
467 ASSERT_ARGS(Parrot_runcore_debugger_init)
469 Parrot_runcore_t * const coredata = mem_gc_allocate_zeroed_typed(interp, Parrot_runcore_t);
470 coredata->name = CONST_STRING(interp, "debugger");
471 coredata->id = PARROT_DEBUGGER_CORE;
472 coredata->opinit = PARROT_CORE_OPLIB_INIT;
473 coredata->prepare_run = NULL;
474 coredata->runops = runops_debugger_core;
475 coredata->destroy = NULL;
476 coredata->flags = 0;
478 PARROT_RUNCORE_FUNC_TABLE_SET(coredata);
480 Parrot_runcore_register(interp, coredata);
486 =item C<static opcode_t * runops_fast_core(PARROT_INTERP, Parrot_runcore_t
487 *runcore, opcode_t *pc)>
489 Runs the Parrot operations starting at C<pc> until there are no more
490 operations. This performs no bounds checking, profiling, or tracing.
492 =cut
496 PARROT_WARN_UNUSED_RESULT
497 PARROT_CAN_RETURN_NULL
498 static opcode_t *
499 runops_fast_core(PARROT_INTERP, SHIM(Parrot_runcore_t *runcore), ARGIN(opcode_t *pc))
501 ASSERT_ARGS(runops_fast_core)
503 /* disable pc */
504 Parrot_pcc_set_pc(interp, CURRENT_CONTEXT(interp), NULL);
506 while (pc) {
507 /* TODO
508 * Decide do we need check here.
509 * Fast-core cause segfaults even on test suite
510 if (pc < code_start || pc >= code_end)
511 Parrot_ex_throw_from_c_args(interp, NULL, 1,
512 "attempt to access code outside of current code segment");
514 DO_OP(pc, interp);
517 return pc;
521 #ifdef code_start
522 # undef code_start
523 #endif
524 #ifdef code_end
525 # undef code_end
526 #endif
528 #define code_start interp->code->base.data
529 #define code_end (interp->code->base.data + interp->code->base.size)
535 =item C<static opcode_t * runops_trace_core(PARROT_INTERP, opcode_t *pc)>
537 Runs the Parrot operations starting at C<pc> until there are no more
538 operations, using the tracing interpreter.
540 =cut
544 PARROT_WARN_UNUSED_RESULT
545 PARROT_CAN_RETURN_NULL
546 static opcode_t *
547 runops_trace_core(PARROT_INTERP, ARGIN(opcode_t *pc))
549 ASSERT_ARGS(runops_trace_core)
551 static size_t gc_mark_runs, gc_collect_runs;
552 Interp *debugger;
554 gc_mark_runs = Parrot_gc_count_mark_runs(interp);
555 gc_collect_runs = Parrot_gc_count_collect_runs(interp);
556 if (interp->pdb) {
557 debugger = interp->pdb->debugger;
558 PARROT_ASSERT(debugger);
560 else {
561 PMC *pio;
564 * using a distinct interpreter for tracing should be ok
565 * - just in case, make it easy to switch
567 Parrot_debugger_init(interp);
568 PARROT_ASSERT(interp->pdb);
569 debugger = interp->pdb->debugger;
570 PARROT_ASSERT(debugger);
572 /* set the top of the stack so GC can trace it for GC-able pointers
573 * see trace_system_areas() in src/gc/system.c */
574 debugger->lo_var_ptr = interp->lo_var_ptr;
576 pio = Parrot_io_STDERR(debugger);
578 if (Parrot_io_is_tty(debugger, pio))
579 Parrot_io_setlinebuf(debugger, pio);
580 else {
581 /* this is essential (100 x faster!) and should probably
582 * be in init/open code */
583 Parrot_io_setbuf(debugger, pio, 8192);
587 trace_op(interp, code_start, code_end, pc);
588 while (pc) {
589 size_t runs;
590 if (pc < code_start || pc >= code_end)
591 Parrot_ex_throw_from_c_args(interp, NULL, 1,
592 "attempt to access code outside of current code segment");
594 Parrot_pcc_set_pc(interp, CURRENT_CONTEXT(interp), pc);
596 DO_OP(pc, interp);
597 trace_op(interp, code_start, code_end, pc);
599 runs = Parrot_gc_count_mark_runs(interp);
600 if (gc_mark_runs != runs) {
601 gc_mark_runs = runs;
602 Parrot_io_eprintf(debugger, " GC mark\n");
605 runs = Parrot_gc_count_collect_runs(interp);
606 if (gc_collect_runs != runs) {
607 gc_collect_runs = runs;
608 Parrot_io_eprintf(debugger, " GC collect\n");
612 Parrot_io_flush(debugger, Parrot_io_STDERR(debugger));
614 return pc;
620 =item C<static opcode_t * runops_slow_core(PARROT_INTERP, Parrot_runcore_t
621 *runcore, opcode_t *pc)>
623 Runs the Parrot operations starting at C<pc> until there are no more
624 operations, with tracing and bounds checking enabled.
626 =cut
630 PARROT_WARN_UNUSED_RESULT
631 PARROT_CAN_RETURN_NULL
632 static opcode_t *
633 runops_slow_core(PARROT_INTERP, SHIM(Parrot_runcore_t *runcore), ARGIN(opcode_t *pc))
635 ASSERT_ARGS(runops_slow_core)
637 if (Interp_trace_TEST(interp, PARROT_TRACE_OPS_FLAG))
638 return runops_trace_core(interp, pc);
640 while (pc) {
641 if (pc < code_start || pc >= code_end)
642 Parrot_ex_throw_from_c_args(interp, NULL, 1,
643 "attempt to access code outside of current code segment");
645 Parrot_pcc_set_pc(interp, CURRENT_CONTEXT(interp), pc);
647 DO_OP(pc, interp);
650 return pc;
656 =item C<static opcode_t * runops_gc_debug_core(PARROT_INTERP, Parrot_runcore_t
657 *runcore, opcode_t *pc)>
659 Runs the Parrot operations starting at C<pc> until there are no more
660 operations, performing a full GC run before each op. This is very slow, but
661 it's also a very quick way to find GC problems.
663 =cut
667 PARROT_WARN_UNUSED_RESULT
668 PARROT_CAN_RETURN_NULL
669 static opcode_t *
670 runops_gc_debug_core(PARROT_INTERP, SHIM(Parrot_runcore_t *runcore), ARGIN(opcode_t *pc))
672 ASSERT_ARGS(runops_gc_debug_core)
673 while (pc) {
674 if (pc < code_start || pc >= code_end)
675 Parrot_ex_throw_from_c_args(interp, NULL, 1,
676 "attempt to access code outside of current code segment");
678 Parrot_gc_mark_and_sweep(interp, GC_trace_stack_FLAG);
679 Parrot_pcc_set_pc(interp, CURRENT_CONTEXT(interp), pc);
681 DO_OP(pc, interp);
684 return pc;
688 #undef code_start
689 #undef code_end
693 =item C<static opcode_t * runops_debugger_core(PARROT_INTERP, Parrot_runcore_t
694 *runcore, opcode_t *pc)>
696 Used by the debugger, under construction
698 =cut
702 PARROT_WARN_UNUSED_RESULT
703 PARROT_CAN_RETURN_NULL
704 static opcode_t *
705 runops_debugger_core(PARROT_INTERP, SHIM(Parrot_runcore_t *runcore), ARGIN(opcode_t *pc))
707 ASSERT_ARGS(runops_debugger_core)
709 PARROT_ASSERT(interp->pdb);
711 if (interp->pdb->state & PDB_ENTER)
712 Parrot_debugger_start(interp, pc);
714 while (pc) {
715 if (pc < interp->code->base.data || pc >= interp->code->base.data + interp->code->base.size)
716 Parrot_ex_throw_from_c_args(interp, NULL, 1,
717 "attempt to access code outside of current code segment");
719 if (interp->pdb->state & PDB_GCDEBUG)
720 Parrot_gc_mark_and_sweep(interp, GC_trace_stack_FLAG);
722 if (interp->pdb->state & PDB_TRACING) {
723 trace_op(interp,
724 interp->code->base.data,
725 interp->code->base.data +
726 interp->code->base.size,
727 pc);
730 Parrot_pcc_set_pc(interp, CURRENT_CONTEXT(interp), pc);
731 DO_OP(pc, interp);
732 interp->pdb->cur_opcode = pc;
734 if (interp->pdb->state & PDB_STOPPED) {
735 Parrot_debugger_start(interp, pc);
737 else {
738 if (PDB_break(interp)) {
739 Parrot_debugger_start(interp, pc);
740 continue;
743 if (interp->pdb->tracing && --interp->pdb->tracing == 0)
744 Parrot_debugger_start(interp, pc);
748 return pc;
755 =item C<oplib_init_f get_core_op_lib_init(PARROT_INTERP, Parrot_runcore_t
756 *runcore)>
758 Returns an opcode's library C<op_lib> init function.
760 =cut
764 PARROT_WARN_UNUSED_RESULT
765 PARROT_CANNOT_RETURN_NULL
766 oplib_init_f
767 get_core_op_lib_init(SHIM_INTERP, ARGIN(Parrot_runcore_t *runcore))
769 ASSERT_ARGS(get_core_op_lib_init)
770 return runcore->opinit;
776 =item C<static opcode_t * runops_exec_core(PARROT_INTERP, Parrot_runcore_t
777 *runcore, opcode_t *pc)>
779 Runs the native executable version of the specified opcode.
781 =cut
785 PARROT_WARN_UNUSED_RESULT
786 PARROT_CAN_RETURN_NULL
787 static opcode_t *
788 runops_exec_core(PARROT_INTERP, ARGIN(Parrot_runcore_t *runcore), ARGIN(opcode_t *pc))
790 ASSERT_ARGS(runops_exec_core)
792 UNUSED(interp);
793 UNUSED(runcore);
794 UNUSED(pc);
796 return NULL;
802 =back
807 * Local variables:
808 * c-file-style: "parrot"
809 * End:
810 * vim: expandtab shiftwidth=4: