1 /*
2 Copyright (C) 2001-2015, Parrot Foundation.
3 
4 =head1 NAME
5 
6 src/runcore/main.c - main functions for Parrot runcores
7 
8 =head1 DESCRIPTION
9 
10 The runcore API handles running the operations.
11 
12 =head2 Functions
13 
14 =over 4
15 
16 =cut
17 
18 */
19 
20 #include "parrot/parrot.h"
21 #include "parrot/runcore_api.h"
22 #include "parrot/runcore_profiling.h"
23 #include "parrot/runcore_subprof.h"
24 #include "parrot/oplib/core_ops.h"
25 #include "parrot/oplib/ops.h"
26 #include "main.str"
27 
28 #include "parrot/dynext.h"
29 #include "pmc/pmc_parrotlibrary.h"
30 #include "pmc/pmc_callcontext.h"
31 
32 
33 /* HEADERIZER HFILE: include/parrot/runcore_api.h */
34 /* XXX Needs to get done at the same time as the other interpreter files */
35 
36 /* HEADERIZER BEGIN: static */
37 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
38 
39 PARROT_WARN_UNUSED_RESULT
40 PARROT_CANNOT_RETURN_NULL
41 static oplib_init_f get_dynamic_op_lib_init(PARROT_INTERP,
42     ARGIN(const PMC *lib))
43         __attribute__nonnull__(2);
44 
45 #define ASSERT_ARGS_get_dynamic_op_lib_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
46        PARROT_ASSERT_ARG(lib))
47 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
48 /* HEADERIZER END: static */
49 
50 /*
51 
52 =item C<void Parrot_runcore_init(PARROT_INTERP)>
53 
54 Initializes the runcores.
55 
56 =cut
57 
58 */
59 
60 void
Parrot_runcore_init(PARROT_INTERP)61 Parrot_runcore_init(PARROT_INTERP)
62 {
63     ASSERT_ARGS(Parrot_runcore_init)
64     STRING * const default_core = CONST_STRING(interp, "fast");
65 
66     interp->cores        = NULL;
67     interp->num_cores    = 0;
68 
69     Parrot_runcore_slow_init(interp);
70     Parrot_runcore_fast_init(interp);
71 
72     Parrot_runcore_subprof_init(interp);
73     /* Parrot_runcore_exec_init(interp); */
74     Parrot_runcore_gc_debug_init(interp);
75     Parrot_runcore_debugger_init(interp);
76 
77     Parrot_runcore_profiling_init(interp);
78 
79     /* set the default runcore */
80     Parrot_runcore_switch(interp, default_core);
81 }
82 
83 
84 /*
85 
86 =item C<INTVAL Parrot_runcore_register(PARROT_INTERP, Parrot_runcore_t
87 *coredata)>
88 
89 Registers a new runcore with Parrot.  Returns 1 on success, 0 on failure.
90 
91 =cut
92 
93 */
94 
95 PARROT_EXPORT
96 INTVAL
Parrot_runcore_register(PARROT_INTERP,ARGIN (Parrot_runcore_t * coredata))97 Parrot_runcore_register(PARROT_INTERP, ARGIN(Parrot_runcore_t *coredata))
98 {
99     ASSERT_ARGS(Parrot_runcore_register)
100     size_t i = interp->num_cores++;
101 
102     interp->cores = mem_gc_realloc_n_typed_zeroed(interp, interp->cores,
103             interp->num_cores, i, Parrot_runcore_t *);
104 
105     interp->cores[i] = coredata;
106 
107     return 1;
108 }
109 
110 
111 /*
112 
113 =item C<void Parrot_runcore_switch(PARROT_INTERP, STRING *name)>
114 
115 Switches to a named runcore.  Throws an exception on an unknown runcore.
116 
117 =cut
118 
119 */
120 
121 PARROT_EXPORT
122 void
Parrot_runcore_switch(PARROT_INTERP,ARGIN (STRING * name))123 Parrot_runcore_switch(PARROT_INTERP, ARGIN(STRING *name))
124 {
125     ASSERT_ARGS(Parrot_runcore_switch)
126 
127     size_t num_cores = interp->num_cores;
128     size_t i;
129 
130     if (interp->run_core
131     &&  STRING_equal(interp, name, interp->run_core->name))
132         return;
133 
134     for (i = 0; i < num_cores; ++i) {
135         if (STRING_equal(interp, name, interp->cores[i]->name)) {
136             interp->run_core = interp->cores[i];
137             return;
138         }
139     }
140 
141     /* XXX This might end in an endless exception cycle. Better panic here? */
142     Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_UNIMPLEMENTED,
143         "Invalid runcore %Ss requested", name);
144 }
145 
146 
147 /*
148 
149 =item C<static oplib_init_f get_dynamic_op_lib_init(PARROT_INTERP, const PMC
150 *lib)>
151 
152 Returns an dynamic oplib's opcode's library C<op_lib> init function.
153 
154 C<lib> will be a C<ParrotLibrary> PMC.
155 
156 =cut
157 
158 */
159 
160 PARROT_WARN_UNUSED_RESULT
161 PARROT_CANNOT_RETURN_NULL
162 static oplib_init_f
get_dynamic_op_lib_init(SHIM_INTERP,ARGIN (const PMC * lib))163 get_dynamic_op_lib_init(SHIM_INTERP, ARGIN(const PMC *lib))
164 {
165     ASSERT_ARGS(get_dynamic_op_lib_init)
166     return (oplib_init_f)D2FPTR(
167             ((Parrot_ParrotLibrary_attributes *)PMC_data(lib))->oplib_init);
168 }
169 
170 
171 /*
172 
173 =item C<void prepare_for_run(PARROT_INTERP)>
174 
175 Prepares to run the interpreter's run core.
176 
177 =cut
178 
179 */
180 
181 void
prepare_for_run(PARROT_INTERP)182 prepare_for_run(PARROT_INTERP)
183 {
184     ASSERT_ARGS(prepare_for_run)
185     const runcore_prepare_fn_type prepare_run = interp->run_core->prepare_run;
186 
187     if (prepare_run)
188         (*prepare_run)(interp, interp->run_core);
189 }
190 
191 
192 /*
193 
194 =item C<void runops_int(PARROT_INTERP, size_t offset)>
195 
196 Run Parrot operations of loaded code segment until an end opcode is
197 reached.  Run core is selected depending on the C<Interp_flags>.  When a
198 C<restart> opcode is encountered, a different core may be selected and
199 evaluation of opcode continues.
200 
201 =cut
202 
203 */
204 
205 void
runops_int(PARROT_INTERP,size_t offset)206 runops_int(PARROT_INTERP, size_t offset)
207 {
208     ASSERT_ARGS(runops_int)
209 
210     interp->resume_offset = offset;
211     interp->resume_flag  |= RESUME_RESTART;
212 
213     while (interp->resume_flag & RESUME_RESTART) {
214         opcode_t * const pc = interp->code->base.data + interp->resume_offset;
215         const runcore_runops_fn_type core = interp->run_core->runops;
216 
217         interp->resume_offset = 0;
218         interp->resume_flag  &= ~(RESUME_RESTART | RESUME_INITIAL);
219 
220         (*core)(interp, interp->run_core, pc);
221 
222         /* if we have fallen out with resume and we were running CGOTO, set
223          * the stacktop again to a sane value, so that restarting the runloop
224          * is ok. */
225         if (interp->resume_flag & RESUME_RESTART) {
226             if ((int)interp->resume_offset < 0)
227                 Parrot_ex_throw_from_c_noargs(interp, EXCEPTION_INTERNAL_PANIC,
228                     "branch_cs: illegal resume offset");
229         }
230     }
231 }
232 
233 
234 /*
235 
236 =item C<void Parrot_runcore_destroy(PARROT_INTERP)>
237 
238 Shuts down the runcores and deallocates any dynops memory.
239 
240 =cut
241 
242 */
243 
244 void
Parrot_runcore_destroy(PARROT_INTERP)245 Parrot_runcore_destroy(PARROT_INTERP)
246 {
247     ASSERT_ARGS(Parrot_runcore_destroy)
248     size_t            num_cores = interp->num_cores;
249     size_t            i;
250 
251     for (i = 0; i < num_cores; ++i) {
252         Parrot_runcore_t * const core = interp->cores[i];
253         const runcore_destroy_fn_type destroy = core->destroy;
254 
255         if (destroy)
256             (*destroy)(interp, core);
257 
258         mem_gc_free(interp, core);
259     }
260 
261     if (interp->cores)
262         mem_gc_free(interp, interp->cores);
263 
264     interp->cores    = NULL;
265     interp->run_core = NULL;
266 
267     if (interp->all_op_libs)
268         mem_gc_free(interp, interp->all_op_libs);
269 
270     interp->all_op_libs = NULL;
271 }
272 
273 
274 /*
275 
276 =back
277 
278 =head2 Dynamic Loading Functions
279 
280 =over 4
281 
282 =item C<void Parrot_dynop_register(PARROT_INTERP, PMC *lib_pmc)>
283 
284 Register a dynamic oplib.
285 
286 =cut
287 
288 */
289 
290 PARROT_EXPORT
291 void
Parrot_dynop_register(PARROT_INTERP,ARGIN (PMC * lib_pmc))292 Parrot_dynop_register(PARROT_INTERP, ARGIN(PMC *lib_pmc))
293 {
294     ASSERT_ARGS(Parrot_dynop_register)
295     op_lib_t     *lib;
296     oplib_init_f  init_func;
297 
298     if (!interp->all_op_libs)
299         interp->all_op_libs = mem_gc_allocate_n_zeroed_typed(interp,
300                 interp->n_libs + 1, op_lib_t*);
301     else
302         interp->all_op_libs = mem_gc_realloc_n_typed_zeroed(interp, interp->all_op_libs,
303                 interp->n_libs + 1, interp->n_libs, op_lib_t *);
304 
305     init_func = get_dynamic_op_lib_init(interp, lib_pmc);
306     lib       = init_func(interp, 1);
307 
308     interp->all_op_libs[interp->n_libs++] = lib;
309 
310     /* if we are registering an op_lib variant, called from below the base
311      * names of this lib and the previous one are the same */
312     if (interp->n_libs >= 2
313     && (STREQ(interp->all_op_libs[interp->n_libs-2]->name, lib->name)))
314         return;
315 
316     parrot_hash_oplib(interp, lib);
317 }
318 
319 /*
320 
321 =item C<void dynop_register(PARROT_INTERP, PMC *lib_pmc)>
322 
323 This function is deprecated, use C<Parrot_dynop_register> instead.
324 
325 =cut
326 
327 */
328 
329 PARROT_EXPORT
330 PARROT_DEPRECATED
331 void
dynop_register(PARROT_INTERP,ARGIN (PMC * lib_pmc))332 dynop_register(PARROT_INTERP, ARGIN(PMC *lib_pmc))
333 {
334     ASSERT_ARGS(dynop_register)
335     Parrot_dynop_register(interp, lib_pmc);
336 }
337 
338 /*
339 
340 =item C<void parrot_hash_oplib(PARROT_INTERP, op_lib_t *lib)>
341 
342 Add the ops in C<lib> to the global name => op_info hash.
343 
344 =cut
345 
346 */
347 
348 void
parrot_hash_oplib(PARROT_INTERP,ARGIN (op_lib_t * lib))349 parrot_hash_oplib(PARROT_INTERP, ARGIN(op_lib_t *lib))
350 {
351     ASSERT_ARGS(parrot_hash_oplib)
352 
353     int i;
354 
355     DECL_CONST_CAST;
356 
357     for (i = 0; i < lib->op_count; i++) {
358         op_info_t *op = &lib->op_info_table[i];
359         Parrot_hash_put(interp, interp->op_hash, PARROT_const_cast(char *, op->full_name),
360                                                  (void *)op);
361 
362         if (!Parrot_hash_exists(interp, interp->op_hash, PARROT_const_cast(char *, op->name)))
363             Parrot_hash_put(interp, interp->op_hash, PARROT_const_cast(char *, op->name),
364                                                      (void *)op);
365     }
366 }
367 
368 
369 /*
370 
371 =item C<void Parrot_runcore_disable_event_checking(PARROT_INTERP)>
372 
373 Restore old function table.
374 
375 XXX This is only implemented for the function core at present.
376 
377 =cut
378 
379 */
380 
381 PARROT_EXPORT
382 void
Parrot_runcore_disable_event_checking(PARROT_INTERP)383 Parrot_runcore_disable_event_checking(PARROT_INTERP)
384 {
385     ASSERT_ARGS(Parrot_runcore_disable_event_checking)
386     PackFile_ByteCode *cs = interp->code;
387     /* restore func table */
388     PARROT_ASSERT(cs->save_func_table);
389     cs->op_func_table   = cs->save_func_table;
390     cs->save_func_table = NULL;
391 }
392 
393 
394 /*
395 
396 =item C<void Parrot_runcore_enable_event_checking(PARROT_INTERP)>
397 
398 Replace func table with one that does event checking for all opcodes.
399 
400 NOTE: C<enable_event_checking()> is called async by the event handler
401 thread. All action done from here has to be async safe.
402 
403 XXX This is only implemented for the function core at present.
404 
405 =cut
406 
407 */
408 
409 PARROT_EXPORT
410 void
Parrot_runcore_enable_event_checking(PARROT_INTERP)411 Parrot_runcore_enable_event_checking(PARROT_INTERP)
412 {
413     ASSERT_ARGS(Parrot_runcore_enable_event_checking)
414     PackFile_ByteCode *cs = interp->code;
415 
416     /* only save if we're not already event checking */
417     if (cs->save_func_table == NULL)
418         cs->save_func_table = cs->op_func_table;
419 
420     /* ensure event checking table is big enough */
421     if (interp->evc_func_table_size < cs->op_count) {
422         size_t i;
423         op_lib_t *core_lib = get_core_op_lib_init(interp, interp->run_core)(interp, 1);
424 
425         interp->evc_func_table = interp->evc_func_table ?
426                                     mem_gc_realloc_n_typed_zeroed(interp,
427                                         interp->evc_func_table, cs->op_count,
428                                         interp->evc_func_table_size, op_func_t) :
429                                     mem_gc_allocate_n_zeroed_typed(interp,
430                                         cs->op_count, op_func_t);
431 
432         for (i = interp->evc_func_table_size; i < cs->op_count; i++)
433             interp->evc_func_table[i] =
434                 core_lib->op_func_table[PARROT_OP_check_events__];
435 
436         interp->evc_func_table_size = cs->op_count;
437     }
438 
439     /* put evc table in place */
440     cs->op_func_table   = interp->evc_func_table;
441 }
442 
443 
444 /*
445 
446 =back
447 
448 =head1 SEE ALSO
449 
450 F<include/parrot/interpreter.h>, F<src/interp/inter_cb.c>,
451 F<src/interp/inter_create.c>, F<src/interp/inter_misc.c>, F<src/call/ops.c>.
452 
453 =cut
454 
455 */
456 
457 
458 /*
459  * Local variables:
460  *   c-file-style: "parrot"
461  * End:
462  * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
463  */
464