[svn:parrot] r48261 - branches/gsoc_instrument/src/dynpmc
khairul at svn.parrot.org
khairul at svn.parrot.org
Tue Aug 3 03:10:22 UTC 2010
Author: khairul
Date: Tue Aug 3 03:10:21 2010
New Revision: 48261
URL: https://trac.parrot.org/parrot/changeset/48261
Log:
Refactored runcore functions out of Instrument.pmc
Added:
branches/gsoc_instrument/src/dynpmc/instrument_extern.h
branches/gsoc_instrument/src/dynpmc/instrument_private.h
branches/gsoc_instrument/src/dynpmc/instrumentruncore.pmc
Modified:
branches/gsoc_instrument/src/dynpmc/Defines.in
branches/gsoc_instrument/src/dynpmc/Rules.in
branches/gsoc_instrument/src/dynpmc/instrument.pmc
Modified: branches/gsoc_instrument/src/dynpmc/Defines.in
==============================================================================
--- branches/gsoc_instrument/src/dynpmc/Defines.in Tue Aug 3 02:53:14 2010 (r48260)
+++ branches/gsoc_instrument/src/dynpmc/Defines.in Tue Aug 3 03:10:21 2010 (r48261)
@@ -28,7 +28,9 @@
src/dynpmc/instrumentop.pmc \
src/dynpmc/instrumentvtable.pmc \
src/dynpmc/instrumentclass.pmc \
- src/dynpmc/instrumentobject.pmc
+ src/dynpmc/instrumentobject.pmc \
+ src/dynpmc/instrumentinvokable.pmc \
+ src/dynpmc/instrumentruncore.pmc
DYNPMC_INSTRUMENT_OBJS = \
src/dynpmc/instrument$(O) \
@@ -37,7 +39,9 @@
src/dynpmc/instrumentop$(O) \
src/dynpmc/instrumentvtable$(O) \
src/dynpmc/instrumentclass$(O) \
- src/dynpmc/instrumentobject$(O)
+ src/dynpmc/instrumentobject$(O) \
+ src/dynpmc/instrumentinvokable$(O) \
+ src/dynpmc/instrumentruncore$(O)
DYNPMC_H_FILES = \
include/parrot/caches.h \
Modified: branches/gsoc_instrument/src/dynpmc/Rules.in
==============================================================================
--- branches/gsoc_instrument/src/dynpmc/Rules.in Tue Aug 3 02:53:14 2010 (r48260)
+++ branches/gsoc_instrument/src/dynpmc/Rules.in Tue Aug 3 03:10:21 2010 (r48261)
@@ -272,3 +272,25 @@
src/dynpmc/instrumentobject.dump: src/dynpmc/instrumentobject.pmc vtable.dump $(CLASS_O_FILES) \
src/dynpmc/instrumentclass.dump
$(PMC2CD) src/dynpmc/instrumentobject.pmc
+
+src/dynpmc/pmc_instrumentinvokable.h : src/dynpmc/instrumentinvokable.c
+
+src/dynpmc/instrumentinvokable$(O): src/dynpmc/instrumentinvokable.c $(DYNPMC_H_FILES) \
+ src/dynpmc/pmc_instrumentinvokable.h
+
+src/dynpmc/instrumentinvokable.c: src/dynpmc/instrumentinvokable.dump
+ $(PMC2CC) src/dynpmc/instrumentinvokable.pmc
+
+src/dynpmc/instrumentinvokable.dump: src/dynpmc/instrumentinvokable.pmc vtable.dump $(CLASS_O_FILES)
+ $(PMC2CD) src/dynpmc/instrumentinvokable.pmc
+
+src/dynpmc/pmc_instrumentruncore.h : src/dynpmc/instrumentruncore.c
+
+src/dynpmc/instrumentruncore$(O): src/dynpmc/instrumentruncore.c $(DYNPMC_H_FILES) \
+ src/dynpmc/pmc_instrumentruncore.h
+
+src/dynpmc/instrumentruncore.c: src/dynpmc/instrumentruncore.dump
+ $(PMC2CC) src/dynpmc/instrumentruncore.pmc
+
+src/dynpmc/instrumentruncore.dump: src/dynpmc/instrumentruncore.pmc vtable.dump $(CLASS_O_FILES)
+ $(PMC2CD) src/dynpmc/instrumentruncore.pmc
\ No newline at end of file
Modified: branches/gsoc_instrument/src/dynpmc/instrument.pmc
==============================================================================
--- branches/gsoc_instrument/src/dynpmc/instrument.pmc Tue Aug 3 02:53:14 2010 (r48260)
+++ branches/gsoc_instrument/src/dynpmc/instrument.pmc Tue Aug 3 03:10:21 2010 (r48261)
@@ -4,7 +4,7 @@
=head1 NAME
-src/dynpmc/instrument.pmc - Interface to hook into a child interpreter.
+src/dynpmc/instrument.pmc - Instrument
=head1 DESCRIPTION
@@ -25,75 +25,31 @@
#include "parrot/embed.h"
#include "parrot/opsenum.h"
-/*
- * Structures for the linked list data type.
- * TODO: Await merge to trunk of bacek's list. Then we use that instead.
- */
-
-typedef struct probe_node_t {
- struct probe_node_t *next, *prev;
- PMC *list_obj;
-} probe_node_t;
-
-typedef struct probe_list_t {
- probe_node_t *head, *tail;
-} probe_list_t;
-
-/*
- * Extend the runcore_t struct to include a reference
- * to the supervisor interpreter.
- */
+#include "instrument_private.h"
-typedef struct Instrument_runcore_t {
- STRING *name;
- int id;
- oplib_init_f opinit;
- runcore_runops_fn_type runops;
- runcore_destroy_fn_type destroy;
- runcore_prepare_fn_type prepare_run;
- INTVAL flags;
-
- /* End of common members */
- INTVAL has_ended;
- Parrot_Interp supervisor_interp;
- PMC *supervisor_pmc;
- probe_list_t **op_hooks;
- probe_list_t *op_catchall;
- PMC *old_dynlibs;
- PMC *instr_op;
-} Instrument_runcore_t;
-
-/* Runcore Function Prototypes */
-static void Instrument_runcore_init(PARROT_INTERP, Parrot_Interp supervisor, PMC *instrument);
-static opcode_t *Instrument_runcore_runops(PARROT_INTERP, Parrot_runcore_t *runcore, opcode_t *pc);
-static void Instrument_init_probes(Parrot_Interp supervisor, Parrot_Interp supervised);
-
-/* Helper prototype */
-static probe_list_t *Instrument_get_active_probes(opcode_t *pc, PARROT_INTERP);
-static probe_list_t *Instrument_fire_probes(probe_list_t *list, opcode_t *pc, PARROT_INTERP);
-static void raise_dynlib_event(PARROT_INTERP, PMC *lib);
-
-/* dynlib detection */
-static void fixup_vtables(Parrot_Interp src, Parrot_Interp dest);
-static void normalise_op_tables(Parrot_Interp src, Parrot_Interp dest);
-static void detect_loadlib(PARROT_INTERP);
-
-/* Linked List operations */
-static probe_list_t *probe_list_create_list(PARROT_INTERP);
-static probe_node_t *probe_list_create_node(PARROT_INTERP);
-static void probe_list_delete_list(PARROT_INTERP, probe_list_t *list);
-static void probe_list_delete_node(PARROT_INTERP, probe_node_t *node);
-static void probe_list_push(PARROT_INTERP, probe_list_t *list, PMC *item);
-static PMC *probe_list_pop(PARROT_INTERP, probe_list_t *list);
-static PMC *probe_list_remove(PARROT_INTERP, probe_list_t *list, probe_node_t *node);
-static probe_node_t *probe_list_find(PARROT_INTERP, probe_list_t *list, PMC *val);
+/* Helper prototypes. */
+probe_list_t *fire_callbacks(PARROT_INTERP, probe_list_t *callbacks, PMC *data, PMC *instr);
+PMC *instrument_pack_params(PARROT_INTERP, const char *format, ...);
+
+/* List related prototypes */
+probe_list_t *probe_list_create_list(PARROT_INTERP);
+probe_node_t *probe_list_create_node(PARROT_INTERP);
+void probe_list_delete_list(PARROT_INTERP, probe_list_t *list);
+void probe_list_delete_node(PARROT_INTERP, probe_node_t *node);
+void probe_list_push(PARROT_INTERP, probe_list_t *list, PMC *item);
+PMC *probe_list_pop(PARROT_INTERP, probe_list_t *list);
+PMC *probe_list_remove(PARROT_INTERP, probe_list_t *list, probe_node_t *node);
+probe_node_t *probe_list_find(PARROT_INTERP, probe_list_t *list, PMC *val);
+void probe_list_append(PARROT_INTERP, probe_list_t *dest, probe_list_t *src);
pmclass Instrument auto_attrs dynpmc provides hash group instrument_group {
- ATTR Parrot_Interp supervised; /* The interpreter running the code */
- ATTR PMC *probes; /* A list of probes registered. */
- ATTR PMC *evt_dispatcher; /* Reference the the EventDispatcher object. */
- ATTR PMC *instrument_gc; /* Reference to the InstrumentGC object. */
- ATTR PMC *instrument_classes; /* Registry to hold instances of InstrumentVtable. */
+ ATTR Parrot_Interp supervised; /* The interpreter running the code */
+ ATTR PMC *probes; /* A list of probes registered. */
+ ATTR PMC *instrument_rc; /* Reference to the InstrumentRuncore object. */
+ ATTR PMC *instrument_gc; /* Reference to the InstrumentGC object. */
+ ATTR PMC *instrument_classes; /* Registry to hold instances of InstrumentClass. */
+ ATTR Hash *instrument_objects; /* Registry of current instrumented objects. */
+ ATTR Hash *event_handlers; /* Reference to registered instrument event handlers. */
/*
@@ -107,44 +63,25 @@
VTABLE void init() {
Parrot_Instrument_attributes * const attr = PARROT_INSTRUMENT(SELF);
- PMC *evt_key1, *evt_key2, *nothing, *supervised_pmc;
- INTVAL evt_class_type, gc_class_type;
-
- /* Obtain the class type of Instrument::EventDispatcher. */
- evt_key1 = key_new_cstring(INTERP, "Instrument");
- evt_key2 = key_new_cstring(INTERP, "EventDispatcher");
- key_append(INTERP, evt_key1, evt_key2);
-
- evt_class_type = Parrot_pmc_get_type(INTERP, evt_key1);
+ INTVAL gc_class_type, rc_class_type;
/* Obtain the class type of InstrumentGC. */
gc_class_type = Parrot_pmc_get_type_str(INTERP, CONST_STRING(INTERP, "InstrumentGC"));
+ rc_class_type = Parrot_pmc_get_type_str(INTERP, CONST_STRING(INTERP, "InstrumentRuncore"));
/* Initialise the attributes. */
attr->supervised = Parrot_new(INTERP);
attr->probes = Parrot_pmc_new(INTERP, enum_class_Hash);
- attr->evt_dispatcher = Parrot_pmc_new(INTERP, evt_class_type);
+ attr->event_handlers = parrot_new_hash(INTERP);
attr->instrument_classes = Parrot_pmc_new(INTERP, enum_class_Hash);
-
- /* Initialise the event dispatcher */
- (PMC *nothing) = PCCINVOKE(INTERP, attr->evt_dispatcher, "_self_init");
-
- /* Initialize the runcore for the child interpreter */
- Instrument_runcore_init(attr->supervised, INTERP, SELF);
+ attr->instrument_rc = Parrot_pmc_new_init(INTERP, rc_class_type, SELF);
+ attr->instrument_gc = Parrot_pmc_new_init(INTERP, gc_class_type, SELF);
+ attr->instrument_objects = parrot_new_pointer_hash(INTERP);
/* Initialize the scheduler for the child interpreter */
attr->supervised->scheduler = Parrot_pmc_new(interp, enum_class_Scheduler);
attr->supervised->scheduler = VTABLE_share_ro(interp, attr->supervised->scheduler);
- /* Prepare the child interpreter's op table for instrumentation */
- Instrument_init_probes(INTERP, attr->supervised);
-
- /* Prepare for GC instrumentation. */
- supervised_pmc = VTABLE_get_pmc_keyed_int(attr->supervised,
- attr->supervised->iglobals,
- IGLOBALS_INTERPRETER);
- attr->instrument_gc = Parrot_pmc_new_init(INTERP, gc_class_type, supervised_pmc);
-
/* Set self to destroy manually */
PObj_custom_mark_destroy_SETALL(SELF);
}
@@ -161,24 +98,7 @@
VTABLE void destroy() {
Parrot_Instrument_attributes * const attr = PARROT_INSTRUMENT(SELF);
- Instrument_runcore_t *core = (Instrument_runcore_t *) attr->supervised->run_core;
- UINTVAL i;
-
- /* Delete the linked list entries. */
- if (core->op_catchall != NULL) {
- probe_list_delete_list(INTERP, core->op_catchall);
- }
- if (core->op_hooks != NULL) {
- for (i = 0; i < attr->supervised->op_count; i++) {
- if (core->op_hooks[i] != NULL) {
- probe_list_delete_list(INTERP, core->op_hooks[i]);
- }
- }
-
- mem_gc_free(INTERP, core->op_hooks);
- }
-
- /* Delete the supervised interpreter */
+ parrot_hash_destroy(INTERP, attr->event_handlers);
Parrot_destroy(attr->supervised);
}
@@ -194,14 +114,11 @@
VTABLE void mark() {
Parrot_Instrument_attributes * const attr = PARROT_INSTRUMENT(SELF);
- Instrument_runcore_t *core = (Instrument_runcore_t *) attr->supervised->run_core;
/* Mark attributes as alive */
Parrot_gc_mark_PMC_alive_fun(INTERP, attr->probes);
- Parrot_gc_mark_PMC_alive_fun(INTERP, attr->evt_dispatcher);
Parrot_gc_mark_PMC_alive_fun(INTERP, attr->instrument_gc);
- Parrot_gc_mark_PMC_alive_fun(INTERP, core->old_dynlibs);
- Parrot_gc_mark_PMC_alive_fun(INTERP, core->instr_op);
+ Parrot_gc_mark_PMC_alive_fun(INTERP, attr->instrument_rc);
Parrot_gc_mark_PMC_alive_fun(INTERP, attr->instrument_classes);
}
@@ -212,9 +129,9 @@
Get the property with the key.
Keys:
-probes : returns the hash of probes currently registered.
-eventdispatcher : returns the event dispatcher instance.
-gc : returns the InstrumentGC instance.
+probes : returns the clone of the hash of probes currently registered.
+runcore : returns the InstrumentRuncore instance.
+gc : returns the InstrumentGC instance.
Unknown keys are sent to the supervised interpreter.
@@ -231,13 +148,7 @@
/* probes: return the hash of probes */
name = CONST_STRING(INTERP, "probes");
if (Parrot_str_equal(INTERP, name, item)) {
- return attr->probes;
- }
-
- /* eventdispatcher: returns the event dispatcher instance */
- name = CONST_STRING(INTERP, "eventdispatcher");
- if (Parrot_str_equal(INTERP, name, item)) {
- return attr->evt_dispatcher;
+ return VTABLE_clone(INTERP, attr->probes);
}
/* gc: returns the InstrumentGC instance. */
@@ -246,6 +157,12 @@
return attr->instrument_gc;
}
+ /* runcore: returns the InstrumentRuncore instance. */
+ name = CONST_STRING(INTERP, "runcore");
+ if (Parrot_str_equal(INTERP, name, item)) {
+ return attr->instrument_rc;
+ }
+
/* push to the supervised interpreter. */
supervised_pmc = VTABLE_get_pmc_keyed_int(attr->supervised,
attr->supervised->iglobals,
@@ -296,9 +213,6 @@
}
}
- /* Fixup the vtables */
- fixup_vtables(INTERP, attr->supervised);
-
/* Begin Execution */
file_c = Parrot_str_to_cstring(attr->supervised, file);
status = imcc_run(attr->supervised,
@@ -354,498 +268,327 @@
*/
METHOD attach(PMC *obj) {
- PMC *enable_method, *id;
+ PMC *id;
Parrot_Instrument_attributes * const attr = PARROT_INSTRUMENT(SELF);
- /* We do not care what type of object it is,
- as long as the object has the attributes $!instr_obj and $!identifier
- and the method enable. */
-
- /* Set the instrument reference attribute of the object,
- and call its enable method. */
- VTABLE_set_attr_str(INTERP, obj,
- CONST_STRING(INTERP, "$!instr_obj"),
- SELF);
-
- /* Find the enable method */
- enable_method = VTABLE_find_method(INTERP, obj, CONST_STRING(INTERP, "_on_attach"));
- if (PMC_IS_NULL(enable_method)) {
- /* Error! Could not find the enable method. */
- Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
- "Could not locate the method '_on_attach'.");
- }
+ STRING *instr_attr = CONST_STRING(INTERP, "$!instr_obj");
+ STRING *id_attr = CONST_STRING(INTERP, "$!identifier");
+ STRING *_on_attach = CONST_STRING(INTERP, "_on_attach");
- /* Call the method.
- The first parameter to a method is the object itself.
- The enable method will be calling insert_op_hook to register the hooks. */
- Parrot_ext_call(INTERP, enable_method, "P->", obj);
+ VTABLE_set_attr_str(INTERP, obj, instr_attr, SELF);
+ Parrot_pcc_invoke_method_from_c_args(INTERP, obj, _on_attach, "->");
/* Register the probe. */
- id = VTABLE_get_attr_str(INTERP, obj, CONST_STRING(INTERP, "$!identifier"));
+ id = VTABLE_get_attr_str(INTERP, obj, id_attr);
VTABLE_set_pmc_keyed(INTERP, attr->probes, id, obj);
}
/*
+=item C<PMC* instrument_class(STRING *classname)>
-=item C<void *insert_op_hooks(PMC *probe, INTVAL op_num)>
-
-Insert a hook for the given op number.
+Returns the InstrumentClass instance associated with the given classname.
+Creates a new InstrumentClass instance if there is none currently associated.
=cut
-
*/
- METHOD insert_op_hook(PMC *probe, INTVAL op_num) {
+ METHOD instrument_class(STRING *classname) {
Parrot_Instrument_attributes * const attr = PARROT_INSTRUMENT(SELF);
- Instrument_runcore_t *core = (Instrument_runcore_t *) attr->supervised->run_core;
- probe_list_t **list = core->op_hooks;
- size_t index = op_num;
+ INTVAL class_type;
+ PMC *class_instr;
- if (index >= attr->supervised->op_count) {
- /* Invalid op num */
- Parrot_ex_throw_from_c_args(INTERP, NULL, 1, "Invalid op number %d.", index);
+ /* Lookup the classname in the InstrumentClass registry.
+ If the entry doesn't exist, create an entry for it. */
+ if (VTABLE_exists_keyed_str(INTERP, attr->instrument_classes, classname)) {
+ class_instr = VTABLE_get_pmc_keyed_str(INTERP, attr->instrument_classes, classname);
}
+ else if (Parrot_pmc_get_type_str(attr->supervised, classname) == 0) {
+ Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
+ "%Ss : Class not found, '%Ss'",
+ VTABLE_name(INTERP, SELF), classname);
+ }
+ else {
+ class_type = Parrot_pmc_get_type_str(INTERP, CONST_STRING(INTERP, "InstrumentClass"));
+ class_instr = Parrot_pmc_new_init(INTERP, class_type, SELF);
- if (list[index] == NULL) {
- list[index] = probe_list_create_list(INTERP);
+ () = PCCINVOKE(INTERP, class_instr, "attach_to_class", STRING *classname);
+
+ VTABLE_set_pmc_keyed_str(INTERP, attr->instrument_classes, classname, class_instr);
}
- probe_list_push(INTERP, list[index], probe);
+ RETURN(PMC *class_instr);
}
/*
+=item C<PMC* instrument_object(PMC *object)>
-=item C<void *remove_op_hooks(PMC *probe, INTVAL op_num)>
-
-Removes a hook for the given op number.
+Returns an Instrument::Event::Object instance that is tied to the given object.
+If none exists in cache, create a new instance and return it.
=cut
-
*/
- METHOD remove_op_hook(PMC *probe, INTVAL op_num) {
+ METHOD instrument_object(PMC *object) {
Parrot_Instrument_attributes * const attr = PARROT_INSTRUMENT(SELF);
- Instrument_runcore_t *core = (Instrument_runcore_t *) attr->supervised->run_core;
- probe_list_t **list = core->op_hooks;
- probe_node_t *node = NULL;
- size_t index = op_num;
+ PMC *obj_instr;
- if (index >= attr->supervised->op_count) {
- /* Invalid op num */
- Parrot_ex_throw_from_c_args(INTERP, NULL, 1, "Invalid op number %d.", index);
- }
-
- if (list[index] != NULL) {
- node = probe_list_find(INTERP, list[index], probe);
-
- if (node != NULL) {
- probe_list_remove(INTERP, list[index], node);
- }
- }
+ obj_instr = (PMC *) parrot_hash_get(INTERP, attr->instrument_objects, object);
+ if(PMC_IS_NULL(obj_instr)) {
+ INTVAL class_type, obj_type;
+ PMC *class_instr, *key;
- if (node == NULL) {
- /* Callback was not found. */
- PMC *id = VTABLE_get_attr_str(INTERP, probe, CONST_STRING(INTERP, "$!identifier"));
- Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
- "Probe '%Ss' not found in 'remove_op_hook'",
- VTABLE_get_string(INTERP, id));
- }
- }
+ key = key_new_cstring(INTERP, "Instrument");
+ key_append(INTERP, key, key_new_cstring(INTERP, "Event"));
+ key_append(INTERP, key, key_new_cstring(INTERP, "Object"));
-/*
-=item C<INTVAL count_op_hooks(INTVAL op_num)>
+ obj_type = Parrot_pmc_get_type(INTERP, key);
+ obj_instr = Parrot_pmc_new(INTERP, obj_type);
+ Parrot_pcc_invoke_method_from_c_args(INTERP, obj_instr,
+ CONST_STRING(INTERP, "new"), "->P", &obj_instr);
-Returns the number of enabled op hooks for the given op number.
+ class_type = Parrot_pmc_get_type_str(INTERP, CONST_STRING(INTERP, "InstrumentObject"));
+ class_instr = Parrot_pmc_new_init(INTERP, class_type, SELF);
-=cut
-*/
+ () = PCCINVOKE(INTERP, class_instr, "attach_to_object", PMC *object);
- METHOD count_op_hooks(INTVAL op_num) {
- Parrot_Instrument_attributes * const attr = PARROT_INSTRUMENT(SELF);
- Instrument_runcore_t *core = (Instrument_runcore_t *) attr->supervised->run_core;
- probe_list_t *list = core->op_hooks[op_num];
- probe_node_t *node = NULL;
- INTVAL count = 0;
+ VTABLE_set_attr_str(INTERP, obj_instr, CONST_STRING(INTERP, "$!object"), class_instr);
- node = (list != NULL) ? list->head : NULL;
- while (node != NULL) {
- count++;
- node = node->next;
+ parrot_hash_put(INTERP, attr->instrument_objects, object, obj_instr);
}
- RETURN(INTVAL count);
+ RETURN(PMC *obj_instr);
}
/*
-=item C<void *insert_op_catchall(PMC *probe)>
+=item C<PMC* instrument_op()>
-Register a catchall op callback
+Creates and returns an instance of Instrument::Probe that can be used
+to inspect ops being executed.
=cut
*/
- METHOD insert_op_catchall(PMC *probe) {
+ METHOD instrument_op() {
Parrot_Instrument_attributes * const attr = PARROT_INSTRUMENT(SELF);
- Instrument_runcore_t *core = (Instrument_runcore_t *) attr->supervised->run_core;
- probe_list_t *list = core->op_catchall;
+ PMC *key, *obj;
+ INTVAL type;
+
+ key = key_new_cstring(INTERP, "Instrument");
+ key_append(INTERP, key, key_new_cstring(INTERP, "Probe"));
+
+ type = Parrot_pmc_get_type(INTERP, key);
+ obj = Parrot_pmc_new(INTERP, type);
+ (PMC *obj) = PCCINVOKE(INTERP, obj, "new");
- probe_list_push(INTERP, list, probe);
+ VTABLE_set_attr_str(INTERP, obj, CONST_STRING(INTERP, "$!instr_obj"), SELF);
+ VTABLE_set_attr_str(INTERP, obj, CONST_STRING(INTERP, "$!rc_obj"), attr->instrument_rc);
+
+ RETURN(PMC *obj);
}
/*
-=item C<void *remove_op_catchall(PMC *probe)>
+=item C<void register_eventhandler(STRING *event, PMC *handler)>
-Deregister a catchall op callback
+Registers the given handler as a handler to the given event.
+Whenever the event is raised, the handler is called as well.
=cut
*/
- METHOD remove_op_catchall(PMC *probe) {
+ METHOD register_eventhandler(STRING *event, PMC *handler) {
Parrot_Instrument_attributes * const attr = PARROT_INSTRUMENT(SELF);
- Instrument_runcore_t *core = (Instrument_runcore_t *) attr->supervised->run_core;
- probe_list_t *list = core->op_catchall;
- probe_node_t *node = NULL;
-
- node = probe_list_find(INTERP, list, probe);
-
- if (node == NULL) {
- /* Callback was not found. */
- PMC *id = VTABLE_get_attr_str(INTERP, probe, CONST_STRING(INTERP, "$!identifier"));
- Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
- "Probe '%S' not found in 'remove_op_catchall'",
- VTABLE_get_string(INTERP, id));
+ probe_list_t *list;
+
+ list = (probe_list_t *) parrot_hash_get(INTERP, attr->event_handlers, event);
+ if(list == NULL) {
+ list = probe_list_create_list(INTERP);
+ parrot_hash_put(INTERP, attr->event_handlers, event, list);
}
- probe_list_remove(INTERP, list, node);
+ probe_list_push(INTERP, list, handler);
}
/*
-=item C<INTVAL count_op_catchalls()>
+=item C<void remove_eventhandler(STRING *event, PMC *handler)>
-Returns the number of enabled op catchall probes.
+Deregisters the given handler from the given event, preventing the
+handler from being called when the event is raised.
=cut
*/
- METHOD count_op_catchalls() {
+ METHOD remove_eventhandler(STRING *event, PMC *handler) {
Parrot_Instrument_attributes * const attr = PARROT_INSTRUMENT(SELF);
- Instrument_runcore_t *core = (Instrument_runcore_t *) attr->supervised->run_core;
- probe_list_t *list = core->op_catchall;
- probe_node_t *node = NULL;
- INTVAL count = 0;
-
- node = list->head;
- while (node != NULL) {
- count++;
- node = node->next;
+ probe_list_t *list;
+ probe_node_t *entry;
+
+ entry = NULL;
+ list = (probe_list_t *) parrot_hash_get(INTERP, attr->event_handlers, event);
+ if(list != NULL) {
+ entry = probe_list_find(INTERP, list, handler);
+ }
+
+ if(entry == NULL) {
+ /* Not found */
+ Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
+ "%Ss : Tried to remove a non-existing event handler, '%Ss'",
+ VTABLE_name(INTERP, SELF),
+ VTABLE_get_attr_str(INTERP, handler, CONST_STRING(INTERP, "$!identifier")));
}
- RETURN(INTVAL count);
+ probe_list_remove(INTERP, list, entry);
}
/*
-=item C<PMC* instrument_class(STRING *classname)>
+=item C<PMC* raise_event(STRING *event, PMC *data,
+PMC *recall :optional, INTVAL has_recall :opt_flag)>
+
+Raises the given event, passing data, SELF and the handler to the
+callbacks. If given an array of callbacks (recall), will call the
+callbacks in the array instead of regenerating a list of callbacks.
-Returns the InstrumentVtable instance associated with the given classname.
-Creates a new InstrumentVtable instance if there is none currently associated.
+Returns a Pointer pmc instance if any of the callbacks returns an
+invokable, which can then be passed back to raise_event to be recalled.
=cut
*/
- METHOD instrument_class(STRING *classname) {
+ METHOD raise_event(STRING *event, PMC *data,
+ PMC *recall :optional, INTVAL has_recall :opt_flag) {
Parrot_Instrument_attributes * const attr = PARROT_INSTRUMENT(SELF);
- INTVAL class_type;
- PMC *class_instr;
+ probe_list_t *ret_list, *cur_list;
+ PMC *ret;
- /* Lookup the classname in the InstrumentClass registry.
- If the entry doesn't exist, create an entry for it. */
- if (VTABLE_exists_keyed_str(INTERP, attr->instrument_classes, classname)) {
- class_instr = VTABLE_get_pmc_keyed_str(INTERP, attr->instrument_classes, classname);
- }
- else {
- class_type = Parrot_pmc_get_type_str(INTERP, CONST_STRING(INTERP, "InstrumentClass"));
- class_instr = Parrot_pmc_new_init(INTERP, class_type, SELF);
+ /* Build up the handlers to call. */
+ if(!has_recall || PMC_IS_NULL(recall)) {
+ Parrot_Context_info info;
+ PMC *event_tokens, *cur_event, *iter;
- () = PCCINVOKE(INTERP, class_instr, "attach_to_class", STRING *classname);
+ STRING *const_colons = CONST_STRING(INTERP, "::");
+ STRING *const_event = CONST_STRING(INTERP, "event");
+ STRING *const_file = CONST_STRING(INTERP, "file");
+ STRING *const_sub = CONST_STRING(INTERP, "sub");
+ STRING *const_line = CONST_STRING(INTERP, "line");
+ STRING *const_ns = CONST_STRING(INTERP, "namespace");
- VTABLE_set_pmc_keyed_str(INTERP, attr->instrument_classes, classname, class_instr);
- }
+ event_tokens = Parrot_str_split(INTERP, const_colons, event);
+ cur_event = Parrot_pmc_new(INTERP, enum_class_ResizableStringArray);
+ cur_list = probe_list_create_list(INTERP);
- RETURN(PMC *class_instr);
- }
+ iter = VTABLE_get_iter(INTERP, event_tokens);
+ while(VTABLE_get_bool(INTERP, iter)) {
+ STRING *key;
+ probe_list_t *to_add;
- METHOD instrument_object(PMC *classname) {
- Parrot_Instrument_attributes * const attr = PARROT_INSTRUMENT(SELF);
- INTVAL class_type;
- PMC *class_instr;
-
- class_type = Parrot_pmc_get_type_str(INTERP, CONST_STRING(INTERP, "InstrumentObject"));
- class_instr = Parrot_pmc_new_init(INTERP, class_type, SELF);
+ VTABLE_push_pmc(INTERP, cur_event, VTABLE_shift_pmc(INTERP, iter));
+ key = Parrot_str_join(INTERP, const_colons, cur_event);
- () = PCCINVOKE(INTERP, class_instr, "attach_to_object", PMC *classname);
+ to_add = (probe_list_t *) parrot_hash_get(INTERP, attr->event_handlers, key);
+ probe_list_append(INTERP, cur_list, to_add);
+ }
- RETURN(PMC *class_instr);
- }
+ /* Add common items to data. */
+ Parrot_Context_get_info(INTERP, CURRENT_CONTEXT(attr->supervised), &info);
+ VTABLE_set_pmc_keyed_str(INTERP, data, const_event, event_tokens);
+ VTABLE_set_string_keyed_str(INTERP, data, const_file, info.file);
+ VTABLE_set_string_keyed_str(INTERP, data, const_sub, info.subname);
+ VTABLE_set_string_keyed_str(INTERP, data, const_line, info.nsname);
+ VTABLE_set_integer_keyed_str(INTERP, data, const_line, info.line);
+ }
+ else {
+ cur_list = (probe_list_t *) VTABLE_get_pointer(INTERP, recall);
+ }
-}
+ /* Execute the handlers. */
+ ret_list = fire_callbacks(INTERP, cur_list, data, SELF);
+ ret = Parrot_pmc_new(INTERP, enum_class_Pointer);
+ VTABLE_set_pointer(INTERP, ret, ret_list);
-/*
- * Runcore Function Implementations
- */
+ RETURN(PMC *ret);
+ }
/*
- * This is the simplified custom runops function.
- * This is based on the PARROT_FAST_RUNCORE.
- */
+=item C<void refresh_probes()>
-static
-opcode_t *
-Instrument_runcore_runops(PARROT_INTERP, Parrot_runcore_t *runcore, opcode_t *pc) {
- Instrument_runcore_t *core = (Instrument_runcore_t *) runcore;
- Parrot_Interp supervisor = core->supervisor_interp;
- Parrot_runloop exc_handler;
+For all probes currently registered, refreshes all of them.
+All probes that are enabled when this is called will be disabled
+and then re-enabled, allowing them to re-register their events
+and hooks. This is very useful when loading dynlibs and such.
- /* Detect any dynlib loading, for example during load_bytecode. */
- detect_loadlib(interp);
+=cut
+*/
- /* Refresh the probes. */
- {
+ METHOD refresh_probes() {
PMC *iter, *probes;
STRING *enable, *disable, *attr_enabled;
- enable = CONST_STRING(supervisor, "enable");
- disable = CONST_STRING(supervisor, "disable");
- attr_enabled = CONST_STRING(supervisor, "$!is_enabled");
+ enable = CONST_STRING(INTERP, "enable");
+ disable = CONST_STRING(INTERP, "disable");
+ attr_enabled = CONST_STRING(INTERP, "$!is_enabled");
- GETATTR_Instrument_probes(supervisor, core->supervisor_pmc, probes);
- iter = VTABLE_get_iter(supervisor, probes);
+ GETATTR_Instrument_probes(INTERP, SELF, probes);
+ iter = VTABLE_get_iter(INTERP, probes);
- while (VTABLE_get_bool(supervisor, iter)) {
+ while (VTABLE_get_bool(INTERP, iter)) {
PMC *key, *obj, *enabled;
- key = VTABLE_shift_pmc(supervisor, iter);
- obj = VTABLE_get_pmc_keyed(supervisor, probes, key);
+ key = VTABLE_shift_pmc(INTERP, iter);
+ obj = VTABLE_get_pmc_keyed(INTERP, probes, key);
/* If this probe is disabled, ignore. */
- enabled = VTABLE_get_attr_str(supervisor, obj, attr_enabled);
- if (!VTABLE_get_integer(supervisor, enabled)) {
+ enabled = VTABLE_get_attr_str(INTERP, obj, attr_enabled);
+ if (!VTABLE_get_integer(INTERP, enabled)) {
continue;
}
- Parrot_pcc_invoke_method_from_c_args(supervisor, obj, disable, "->");
- Parrot_pcc_invoke_method_from_c_args(supervisor, obj, enable, "->");
- }
- }
-
- /* Setup an exception handler to handle exits and unhandled exceptions. */
- if (setjmp(exc_handler.resume)) {
- /* Check for exit or unhandled exception. */
- Parrot_Context_info info;
- INTVAL ret = Parrot_Context_get_info(interp, CURRENT_CONTEXT(interp), &info);
-
- if (*pc == enum_ops_exit_i || *pc == enum_ops_exit_ic) {
- /* Exit called. */
- Parrot_io_eprintf(supervisor, "Exit called in file \"%Ss\" line %d.\n",
- info.file, info.line);
- }
- else {
- /* Unhandled exception found. */
- INTVAL type = VTABLE_get_integer_keyed_str(interp, exc_handler.exception,
- CONST_STRING(interp, "type"));
- STRING *message = VTABLE_get_string(interp, exc_handler.exception);
- Parrot_io_eprintf(supervisor,
- "Unhandled exception of type (%d) thrown in file \"%Ss\" line %d,\n"
- "with message \"%Ss\".\n",
- type, info.file, info.line, message);
+ Parrot_pcc_invoke_method_from_c_args(INTERP, obj, disable, "->");
+ Parrot_pcc_invoke_method_from_c_args(INTERP, obj, enable, "->");
}
-
- /* Set the flag to exit all runloops. */
- core->has_ended = 1;
-
- return pc;
}
- Parrot_ex_add_c_handler(interp, &exc_handler);
-
- while (pc && !(core->has_ended)) {
- probe_list_t *callbacks, *recalls, *ignore;
- opcode_t *pc_copy = pc;
- Parrot_pcc_set_pc(interp, CURRENT_CONTEXT(interp), pc);
-
- /* Get the list of callbacks to call and execute the op. */
- callbacks = Instrument_get_active_probes(pc, interp);
- recalls = Instrument_fire_probes(callbacks, pc, interp);
- DO_OP(pc, interp);
- ignore = Instrument_fire_probes(recalls, pc_copy, interp);
- probe_list_delete_list(supervisor, ignore);
-
- /* Todo: Move this to a probe. This detects loadlib opcodes. */
- if (*pc_copy == enum_ops_loadlib_p_s
- || *pc_copy == enum_ops_loadlib_p_sc
- || *pc_copy == enum_ops_loadlib_p_s_p
- || *pc_copy == enum_ops_loadlib_p_sc_p
- || *pc_copy == enum_ops_loadlib_p_s_pc
- || *pc_copy == enum_ops_loadlib_p_sc_pc) {
- detect_loadlib(interp);
- }
-
- /* Force events */
- Parrot_cx_handle_tasks(interp, interp->scheduler);
- Parrot_cx_handle_tasks(supervisor, supervisor->scheduler);
- }
-
- return pc;
}
/*
- * This is the initializer for the runcore.
- * Sets up runcore_t.
- */
-
-static
-void
-Instrument_runcore_init(PARROT_INTERP, Parrot_Interp supervisor, PMC *instrument) {
- Instrument_runcore_t * const coredata =
- mem_gc_allocate_zeroed_typed(interp, Instrument_runcore_t);
- PMC *dynlibs, *interp_pmc;
- INTVAL instr_op_type;
-
- /* Get the pmc type of InstrumentOp. */
- interp_pmc = VTABLE_get_pmc_keyed_int(interp, interp->iglobals, IGLOBALS_INTERPRETER);
- instr_op_type = Parrot_pmc_get_type_str(supervisor, CONST_STRING(supervisor, "InstrumentOp"));
-
- /* Grab the dynlib hash. */
- dynlibs = VTABLE_get_pmc_keyed_int(interp, interp->iglobals, IGLOBALS_DYN_LIBS);
-
- /* Ensure the current loaded runcore is the slow core */
- Parrot_set_run_core(interp, PARROT_SLOW_CORE);
-
- /* Copy the runcore entry for the PARROT_SLOW_CORE,
- and then make modifications to it.
- Copy so that we get the opinit function pointer.
- */
- mem_copy_n_typed(coredata, interp->run_core, 1, Parrot_runcore_t);
-
- coredata->name = string_from_literal(interp, "instrument");
- coredata->runops = Instrument_runcore_runops;
- coredata->prepare_run = NULL;
- coredata->destroy = NULL;
- coredata->flags = 0;
- coredata->supervisor_interp = supervisor;
- coredata->supervisor_pmc = instrument;
- coredata->op_hooks = NULL;
- coredata->op_catchall = NULL;
- coredata->old_dynlibs = VTABLE_clone(supervisor, dynlibs);
- coredata->has_ended = 0;
- coredata->instr_op = Parrot_pmc_new_init(supervisor, instr_op_type, interp_pmc);
- PARROT_RUNCORE_FUNC_TABLE_SET((Parrot_runcore_t *)coredata);
+=item C<probe_list_t * fire_callbacks(PARROT_INTERP,
+probe_list_t *callbacks, PMC *data, PMC *instr)>
- Parrot_runcore_register(interp, (Parrot_runcore_t *) coredata);
+Calls the callbacks given in the list of callbacks, passing data, instr
+and the probe instance itself to the callback.
- /* Switch to this runcore. */
- Parrot_runcore_switch(interp, coredata->name);
-}
-
-/*
- * This is the initializer for the probe tables.
- * Probes are stored in the extended runcore_t.
- */
+Returns a list of callbacks that were returned by the invokables.
-static void Instrument_init_probes(Parrot_Interp supervisor, Parrot_Interp supervised) {
- Instrument_runcore_t *core;
- INTVAL op_count;
-
- core = (Instrument_runcore_t *) supervised->run_core;
- op_count = supervised->op_count;
-
- /* Create the probe list table */
- if (!core->op_hooks) {
- /* First time allocating. */
- core->op_hooks = mem_gc_allocate_n_zeroed_typed(supervisor, op_count, probe_list_t *);
- core->op_catchall = probe_list_create_list(supervisor);
- }
- else {
- /* Reallocate. */
- INTVAL old_count = supervisor->op_count;
- core->op_hooks = mem_gc_realloc_n_typed_zeroed(supervisor, core->op_hooks,
- op_count, old_count, probe_list_t *);
- }
-}
+For internal use only.
-/*
- * Returns a list of Probe objects to be called by Instrument_fire_probes.
- */
-
-static probe_list_t * Instrument_get_active_probes(opcode_t *pc, PARROT_INTERP) {
- probe_list_t *list;
- probe_node_t *cur_node;
- Instrument_runcore_t *core;
- Parrot_Interp supervisor;
-
- core = (Instrument_runcore_t *) interp->run_core;
- supervisor = core->supervisor_interp;
- list = probe_list_create_list(supervisor);
-
- /* Copy over the list entries for the catchalls
- and specific op probes into the list. */
- cur_node = core->op_catchall->head;
- while (cur_node != NULL) {
- probe_list_push(supervisor, list, cur_node->list_obj);
- cur_node = cur_node->next;
- }
-
- if (core->op_hooks[*pc] != NULL) {
- cur_node = core->op_hooks[*pc]->head;
- while (cur_node != NULL) {
- probe_list_push(supervisor, list, cur_node->list_obj);
- cur_node = cur_node->next;
- }
- }
+=cut
- return list;
-}
+*/
-/*
- * Executes the hooks given in the list 'list'.
- * Each entry in this list can either be the Probe object or a RPA that
- * has 2 elements, the Probe object and an invokable.
- * If the invokable returns a PMC that is also invokable, this return
- * value then goes into the recall list to be called after the op is executed.
- */
+probe_list_t *
+fire_callbacks(PARROT_INTERP, probe_list_t *callbacks, PMC *data, PMC *instr) {
+ probe_node_t *cur;
+ probe_list_t *ret_list;
-static probe_list_t * Instrument_fire_probes(probe_list_t *list, opcode_t *pc, PARROT_INTERP) {
- Parrot_Interp supervisor;
- PMC *instrument, *op_data;
- Instrument_runcore_t *core;
- probe_node_t *cur_probe;
- probe_list_t *recall_list;
-
- core = (Instrument_runcore_t *) interp->run_core;
- supervisor = core->supervisor_interp;
- instrument = core->supervisor_pmc;
- op_data = core->instr_op;
- recall_list = probe_list_create_list(supervisor);
+ STRING *array = CONST_STRING(interp, "array");
+ STRING *callback_attr = CONST_STRING(interp, "$!callback");
+ STRING *invokable = CONST_STRING(interp, "invokable");
- /* Update pc of InstrumentOp object. */
- VTABLE_set_pointer(supervisor, op_data, pc);
+ ret_list = probe_list_create_list(interp);
/* Execute the probes in the list. */
- cur_probe = list->head;
- while (cur_probe != NULL) {
+ for (cur = callbacks->head; cur != NULL; cur = cur->next) {
PMC *callback;
- PMC *probe;
+ PMC *handler;
- /* Get the probe and list object. */
- if (VTABLE_does(supervisor, cur_probe->list_obj, CONST_STRING(supervisor, "array"))) {
+ /* Get the handler and list object. */
+ if (VTABLE_does(interp, cur->list_obj, array)) {
/* Obtain the probe and callback from the RPA. */
- probe = VTABLE_get_pmc_keyed_int(supervisor, cur_probe->list_obj, 0);
- callback = VTABLE_get_pmc_keyed_int(supervisor, cur_probe->list_obj, 1);
+ handler = VTABLE_get_pmc_keyed_int(interp, cur->list_obj, 0);
+ callback = VTABLE_get_pmc_keyed_int(interp, cur->list_obj, 1);
}
else {
/* Node contains the probe object. Obtain the callback from its attributes. */
- probe = cur_probe->list_obj;
- callback = VTABLE_get_attr_str(supervisor, probe,
- CONST_STRING(supervisor, "$!callback"));
+ handler = cur->list_obj;
+ callback = VTABLE_get_attr_str(interp, handler, callback_attr);
}
if (!PMC_IS_NULL(callback)) {
@@ -853,191 +596,98 @@
If a PMC is returned, only push it into the recall list if
it is invokable. */
PMC *recall = PMCNULL;
- Parrot_ext_call(supervisor, callback,
- "PPP->P",
- op_data, instrument, probe,
- &recall);
- if (!PMC_IS_NULL(recall) && VTABLE_does(supervisor, recall,
- CONST_STRING(supervisor, "invokable"))) {
+ Parrot_ext_call(interp, callback, "PPP->P", data, instr, handler, &recall);
+
+ if (!PMC_IS_NULL(recall) && VTABLE_does(interp, recall, invokable)) {
PMC *list_entry;
- list_entry = Parrot_pmc_new(supervisor, enum_class_ResizablePMCArray);
- VTABLE_push_pmc(supervisor, list_entry, cur_probe->list_obj);
- VTABLE_push_pmc(supervisor, list_entry, recall);
+ list_entry = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
+ VTABLE_push_pmc(interp, list_entry, handler);
+ VTABLE_push_pmc(interp, list_entry, recall);
- probe_list_push(supervisor, recall_list, list_entry);
+ probe_list_push(interp, ret_list, list_entry);
}
}
-
- /* Go on to next entry. */
- cur_probe = cur_probe->next;
}
/* Cleanup list and return. */
- probe_list_delete_list(supervisor, list);
- return recall_list;
+ probe_list_delete_list(interp, callbacks);
+ return ret_list;
}
/*
- * Functions implementing internal detection of newly loaded dynlibs.
- */
-
-/*
- * Detect newly loaded dynlibs in the passed interp by comparing it
- * with a hash of previously known loaded dynlibs.
- */
-static void detect_loadlib(PARROT_INTERP) {
- PMC *dynlibs, *old_dynlibs, *super_dynlibs;
- Instrument_runcore_t *core;
- Parrot_Interp supervisor;
- INTVAL old_count, new_count;
-
- core = (Instrument_runcore_t *) interp->run_core;
- supervisor = core->supervisor_interp;
- super_dynlibs = supervisor->iglobals;
- old_dynlibs = core->old_dynlibs;
- dynlibs = VTABLE_get_pmc_keyed_int(interp, interp->iglobals, IGLOBALS_DYN_LIBS);
-
- /* Check if any libraries were loaded. */
- old_count = VTABLE_get_integer(supervisor, old_dynlibs);
- new_count = VTABLE_get_integer(interp, dynlibs);
-
- if (old_count != new_count) {
- PMC *iter;
- /* Normalise the vtables of both interps due to singletons. */
- fixup_vtables(interp, supervisor);
+=item C<PMC *instrument_pack_params(PARROT_INTERP, const char *format, ...)>
- /* Before we normalise the op tables, we need to update the hooks table. */
- Instrument_init_probes(supervisor, interp);
- normalise_op_tables(interp, supervisor);
+Packs the given variable list of arguments according to the given
+format into a ResizablePMCArray.
- /* Look for the new dynlibs and raise an event about them. */
- iter = VTABLE_get_iter(interp, dynlibs);
- while (VTABLE_get_bool(interp, iter)) {
- PMC *key;
+For internal use only.
- key = VTABLE_shift_pmc(interp, iter);
+=cut
- if (!VTABLE_exists_keyed(supervisor, old_dynlibs, key)) {
- /* New lib detected. */
- PMC *lib, *task, *task_hash, *task_data;
+*/
- lib = VTABLE_get_pmc_keyed(interp, dynlibs, key);
+PMC *instrument_pack_params(PARROT_INTERP, const char *format, ...) {
+ PMC *ret;
+ va_list args;
+ char const * cur;
- raise_dynlib_event(supervisor, lib);
+ va_start(args, format);
+ ret = Parrot_pmc_new(interp, enum_class_ResizablePMCArray);
- /* Add lib to the old dynlib hash */
- VTABLE_set_pmc_keyed(supervisor, old_dynlibs, key, lib);
+ for(cur = format; *cur != '\0'; cur++) {
+ /* P : PMC
+ I : integer
+ F : floatval
+ S : string
+ V : pointer */
+ switch(*cur) {
+ case 'P':
+ VTABLE_push_pmc(interp, ret, (PMC *) va_arg(args, PMC *));
+ break;
+ case 'I':
+ VTABLE_push_integer(interp, ret, (INTVAL) va_arg(args, INTVAL));
+ break;
+ case 'F':
+ VTABLE_push_float(interp, ret, (FLOATVAL) va_arg(args, FLOATVAL));
+ break;
+ case 'S':
+ VTABLE_push_string(interp, ret, (STRING *) va_arg(args, STRING *));
+ break;
+ case 'V':
+ {
+ PMC *ptr;
+ ptr = Parrot_pmc_new(interp, enum_class_Pointer);
+ VTABLE_set_pointer(interp, ptr, (void *) va_arg(args, void *));
+ VTABLE_push_pmc(interp, ret, ptr);
}
+ break;
+ default:
+ /* Unknown. */
+ Parrot_ex_throw_from_c_args(interp, NULL, 1,
+ "Unknown format in instrument_pack_params: %c\n", cur);
}
}
- /* Force handling of any pending tasks in super. */
- Parrot_cx_handle_tasks(supervisor, supervisor->scheduler);
+ return ret;
}
/*
- * Normalise the vtables between the source and dest interpreters.
- */
-static void fixup_vtables(Parrot_Interp src, Parrot_Interp dest) {
- INTVAL i;
-
- /* Extend dest's vtable. */
- if (dest->n_vtable_alloced < src->n_vtable_max) {
- INTVAL new_size;
-
- new_size = src->n_vtable_max + 16;
-
- dest->vtables = mem_gc_realloc_n_typed_zeroed(dest, dest->vtables,
- new_size, dest->n_vtable_alloced,
- VTABLE *);
- dest->n_vtable_alloced = new_size;
- }
-
- /* Copy over the new vtable entries. */
- for (i = dest->n_vtable_max; i < src->n_vtable_max; i++) {
- dest->vtables[i] = src->vtables[i];
- }
-
- dest->n_vtable_max = src->n_vtable_max;
-}
-
-/*
- * Normalise the op tables of the dest interpreter.
- */
-static void normalise_op_tables(Parrot_Interp src, Parrot_Interp dest) {
- op_lib_t *core_lib;
-
- /* Reset dest's optables if needed. */
- core_lib = dest->run_core->opinit(dest, 1);
- if (dest->op_count != core_lib->op_count) {
- dest->op_count = core_lib->op_count;
- dest->op_info_table = core_lib->op_info_table;
- dest->op_func_table = core_lib->op_func_table;
-
- /* Remove dest's evc_func_table */
- if (dest->evc_func_table != NULL) {
- mem_gc_free(dest, dest->evc_func_table);
-
- dest->evc_func_table = NULL;
- dest->save_func_table = NULL;
-
- Parrot_setup_event_func_ptrs(dest);
- }
- }
-}
-
-/*
- * Raises an Internal::loadlib event.
- */
-static void raise_dynlib_event(PARROT_INTERP, PMC *lib) {
- PMC *data, *task_hash, *task, *event;
-
- event = Parrot_pmc_new(interp, enum_class_ResizableStringArray);
- VTABLE_push_string(interp, event, CONST_STRING(interp, "Internal"));
- VTABLE_push_string(interp, event, CONST_STRING(interp, "loadlib"));
- VTABLE_push_string(interp, event, VTABLE_get_string(interp, lib));
-
- data = Parrot_pmc_new(interp, enum_class_Hash);
- VTABLE_set_string_keyed_str(interp, data,
- CONST_STRING(interp, "library"),
- VTABLE_get_string(interp, lib));
- VTABLE_set_pmc_keyed_str(interp, data,
- CONST_STRING(interp, "event"),
- event);
-
- task_hash = Parrot_pmc_new(interp, enum_class_Hash);
- VTABLE_set_string_keyed_str(interp, task_hash,
- CONST_STRING(interp, "type"),
- CONST_STRING(interp, "event"));
- VTABLE_set_string_keyed_str(interp, task_hash,
- CONST_STRING(interp, "subtype"),
- CONST_STRING(interp,
- "Instrument"));
- VTABLE_set_pmc_keyed_str(interp, task_hash,
- CONST_STRING(interp, "data"),
- data);
-
- task = Parrot_pmc_new_init(interp, enum_class_Task, task_hash);
- Parrot_cx_schedule_task(interp, task);
-}
-
-
-/*
* Functions implementing the linked list for the probes.
*/
/*
* Creates a new list.
*/
-static probe_list_t *probe_list_create_list(PARROT_INTERP) {
+probe_list_t *probe_list_create_list(PARROT_INTERP) {
probe_list_t *list;
list = mem_gc_allocate_zeroed_typed(interp, probe_list_t);
- list->head = NULL;
- list->tail = NULL;
+ list->head = NULL;
+ list->tail = NULL;
+ list->count = 0;
return list;
}
@@ -1045,7 +695,7 @@
/*
* Creates a new list node.
*/
-static probe_node_t *probe_list_create_node(PARROT_INTERP) {
+probe_node_t *probe_list_create_node(PARROT_INTERP) {
probe_node_t *node;
node = mem_gc_allocate_zeroed_typed(interp, probe_node_t);
@@ -1060,8 +710,9 @@
/*
* Deletes the list.
*/
-static void probe_list_delete_list(PARROT_INTERP, probe_list_t *list) {
+void probe_list_delete_list(PARROT_INTERP, probe_list_t *list) {
probe_node_t *node, *next;
+ if(list == NULL) { return; }
node = list->head;
while (node != NULL) {
@@ -1076,14 +727,15 @@
/*
* Deletes the node.
*/
-static void probe_list_delete_node(PARROT_INTERP, probe_node_t *node) {
+void probe_list_delete_node(PARROT_INTERP, probe_node_t *node) {
+ if(node == NULL) { return; }
mem_gc_free(interp, node);
}
/*
* Pushes item to the end of the list.
*/
-static void probe_list_push(PARROT_INTERP, probe_list_t *list, PMC *item) {
+void probe_list_push(PARROT_INTERP, probe_list_t *list, PMC *item) {
probe_node_t *node = probe_list_create_node(interp);
node->list_obj = item;
@@ -1096,12 +748,14 @@
list->tail->next = node;
list->tail = node;
}
+
+ list->count++;
}
/*
* Removes item at the end of the list.
*/
-static PMC * probe_list_pop(PARROT_INTERP, probe_list_t *list) {
+PMC * probe_list_pop(PARROT_INTERP, probe_list_t *list) {
PMC *item = PMCNULL;
probe_node_t *node = list->tail;
@@ -1119,6 +773,7 @@
probe_list_delete_node(interp, node);
}
+ list->count--;
return item;
}
@@ -1126,8 +781,9 @@
* Removes the given node. Used with probe_list_find.
* Returns the item in that node.
*/
-static PMC * probe_list_remove(PARROT_INTERP, probe_list_t *list, probe_node_t *node) {
+PMC * probe_list_remove(PARROT_INTERP, probe_list_t *list, probe_node_t *node) {
PMC *item;
+ if(node == NULL) { return PMCNULL; }
if (node == list->head) { list->head = node->next; }
if (node == list->tail) { list->tail = node->prev; }
@@ -1139,13 +795,14 @@
probe_list_delete_node(interp, node);
+ list->count--;
return item;
}
/*
* Locates item within the list and returns the node.
*/
-static probe_node_t *probe_list_find(PARROT_INTERP, probe_list_t *list, PMC *val) {
+probe_node_t *probe_list_find(PARROT_INTERP, probe_list_t *list, PMC *val) {
probe_node_t *cur_node = list->head;
while (cur_node != NULL) {
@@ -1158,6 +815,20 @@
}
/*
+ * Appends list src to the end of list dest.
+ * Nodes are duplicated.
+ */
+void probe_list_append(PARROT_INTERP, probe_list_t *dest, probe_list_t *src) {
+ probe_node_t *cur, *dup;
+ if(src == NULL || dest == NULL) { return; }
+
+ for(cur = src->head; cur != NULL; cur = cur->next) {
+ probe_list_push(interp, dest, cur->list_obj);
+ dest->count++;
+ }
+}
+
+/*
=back
=head1 SEE ALS0
Added: branches/gsoc_instrument/src/dynpmc/instrument_extern.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ branches/gsoc_instrument/src/dynpmc/instrument_extern.h Tue Aug 3 03:10:21 2010 (r48261)
@@ -0,0 +1,38 @@
+/* instrument_extern.h
+ * Copyright (C) 2010, Parrot Foundation.
+ * SVN Info
+ * $Id$
+ * Overview:
+ * This header defines as extern functions that are
+ * implemented in Instrument.pmc but used by others.
+ * Data Structure and Algorithms:
+ * History:
+ * Notes:
+ * References:
+ */
+
+#ifndef PARROT_INSTRUMENT_EXTERN_H_GUARD
+#define PARROT_INSTRUMENT_EXTERN_H_GUARD
+
+extern probe_list_t *fire_callbacks(PARROT_INTERP, probe_list_t *callbacks, PMC *data, PMC *instr);
+extern PMC *instrument_pack_params(PARROT_INTERP, const char *format, ...);
+
+/* Linked List operations */
+extern probe_list_t *probe_list_create_list(PARROT_INTERP);
+extern probe_node_t *probe_list_create_node(PARROT_INTERP);
+extern void probe_list_delete_list(PARROT_INTERP, probe_list_t *list);
+extern void probe_list_delete_node(PARROT_INTERP, probe_node_t *node);
+extern void probe_list_push(PARROT_INTERP, probe_list_t *list, PMC *item);
+extern PMC *probe_list_pop(PARROT_INTERP, probe_list_t *list);
+extern PMC *probe_list_remove(PARROT_INTERP, probe_list_t *list, probe_node_t *node);
+extern probe_node_t *probe_list_find(PARROT_INTERP, probe_list_t *list, PMC *val);
+extern void probe_list_append(PARROT_INTERP, probe_list_t *dest, probe_list_t *src);
+
+#endif /* PARROT_INSTRUMENT_EXTERN_H_GUARD */
+
+/*
+ * Local variables:
+ * c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */
\ No newline at end of file
Added: branches/gsoc_instrument/src/dynpmc/instrument_private.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ branches/gsoc_instrument/src/dynpmc/instrument_private.h Tue Aug 3 03:10:21 2010 (r48261)
@@ -0,0 +1,38 @@
+/* instrument_private.h
+ * Copyright (C) 2010, Parrot Foundation.
+ * SVN Info
+ * $Id$
+ * Overview:
+ * This header defines common data structures used by Instrument.
+ * Data Structure and Algorithms:
+ * History:
+ * Notes:
+ * References:
+ */
+
+#ifndef PARROT_INSTRUMENT_PRIVATE_H_GUARD
+#define PARROT_INSTRUMENT_PRIVATE_H_GUARD
+
+/*
+ * Structures for the linked list data type.
+ * TODO: Await merge to trunk of bacek's list. Then we use that instead.
+ */
+
+typedef struct probe_node_t {
+ struct probe_node_t *next, *prev;
+ PMC *list_obj;
+} probe_node_t;
+
+typedef struct probe_list_t {
+ probe_node_t *head, *tail;
+ INTVAL count;
+} probe_list_t;
+
+#endif /* PARROT_INSTRUMENT_PRIVATE_H_GUARD */
+
+/*
+ * Local variables:
+ * c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */
Added: branches/gsoc_instrument/src/dynpmc/instrumentruncore.pmc
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ branches/gsoc_instrument/src/dynpmc/instrumentruncore.pmc Tue Aug 3 03:10:21 2010 (r48261)
@@ -0,0 +1,713 @@
+/*
+Copyright (C) 2010, Parrot Foundation.
+$Id$
+
+=head1 NAME
+
+src/dynpmc/instrumentruncore.pmc - InstrumentRuncore
+
+=head1 DESCRIPTION
+
+Provides a way to instrument the runcore, thus allowing
+hooks into the execution of the ops.
+
+=head2 Methods
+
+=over 4
+
+=cut
+
+*/
+
+#include "parrot/embed.h"
+#include "parrot/runcore_api.h"
+#include "parrot/opsenum.h"
+
+#include "pmc_instrument.h"
+
+#include "instrument_private.h"
+#include "instrument_extern.h"
+
+/*
+ * Extend the runcore_t struct to include a reference
+ * to the supervisor interpreter.
+ */
+
+typedef struct instrument_runcore_t {
+ STRING *name;
+ int id;
+ oplib_init_f opinit;
+ runcore_runops_fn_type runops;
+ runcore_destroy_fn_type destroy;
+ runcore_prepare_fn_type prepare_run;
+ INTVAL flags;
+
+ /* End of common members */
+ INTVAL has_ended;
+ Parrot_Interp supervisor_interp;
+ PMC *instrument_rc;
+} instrument_runcore_t;
+
+/* Probe helpers. */
+void runcore_probes_setup(PARROT_INTERP, PMC *runcore);
+void runcore_probes_refresh_tables(PARROT_INTERP, PMC *runcore);
+probe_list_t* runcore_probes_get_probes(PARROT_INTERP, PMC *runcore, INTVAL op_num);
+probe_list_t* runcore_probes_fire_probes(PARROT_INTERP, PMC *runcore,
+ opcode_t *pc, probe_list_t *callbacks);
+
+/* Runcore helpers. */
+void runcore_runcore_setup(PARROT_INTERP, PMC *runcore);
+opcode_t* runcore_runcore_runops(PARROT_INTERP, Parrot_runcore_t *core_ptr, opcode_t *pc);
+
+/* Misc helpers */
+void runcore_library_update(PARROT_INTERP, PMC *runcore);
+void runcore_vtable_fixup(PARROT_INTERP, PMC *runcore);
+void runcore_optable_fixup(PARROT_INTERP, PMC *runcore);
+INTVAL runcore_does_loading(opcode_t *pc);
+
+pmclass InstrumentRuncore auto_attrs dynpmc group instrument_group {
+ ATTR PMC *instrument;
+ ATTR PMC *dynlibs;
+ ATTR struct probe_list_t **op_hooks;
+ ATTR INTVAL op_hooks_size;
+ ATTR struct probe_list_t *op_catchall;
+
+/*
+
+=item C<void init()>
+
+Throws an exception since this class should be instantiated using init_pmc instead.
+
+=item C<void init_pmc(PMC *instrument)>
+
+Initialises the PMC and prepares the supervised interpreter
+for running under supervision.
+
+=cut
+
+*/
+
+ VTABLE void init() {
+ /* Not supposed to be init on its own. */
+ Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
+ "%Ss should be instantiated with an Instrument instance.",
+ VTABLE_name(INTERP, SELF));
+ }
+
+ VTABLE void init_pmc(PMC *instrument) {
+ Parrot_InstrumentRuncore_attributes * const attr = PARROT_INSTRUMENTRUNCORE(SELF);
+
+ attr->instrument = instrument;
+ attr->dynlibs = Parrot_pmc_new(INTERP, enum_class_Hash);
+ attr->op_hooks = NULL;
+ attr->op_hooks_size = 0;
+ attr->op_catchall = NULL;
+
+ /* Instrument the runcore. */
+ runcore_runcore_setup(INTERP, SELF);
+
+ /* Set up the op probe tables. */
+ runcore_probes_setup(INTERP, SELF);
+
+ PObj_custom_mark_destroy_SETALL(SELF);
+ }
+
+/*
+
+=item C<void mark()>
+
+Marks internal data structures as live to the gc.
+
+=cut
+
+*/
+
+ VTABLE void mark() {
+ Parrot_InstrumentRuncore_attributes * const attr = PARROT_INSTRUMENTRUNCORE(SELF);
+ Parrot_gc_mark_PMC_alive_fun(INTERP, attr->dynlibs);
+ }
+
+/*
+
+=item C<void destroy()>
+
+Cleans up after the PMC.
+
+=cut
+
+*/
+
+ VTABLE void destroy() {
+ Parrot_InstrumentRuncore_attributes * const attr = PARROT_INSTRUMENTRUNCORE(SELF);
+ INTVAL i;
+
+ /* Delete the linked list entries. */
+ for (i = 0; i < attr->op_hooks_size; i++) {
+ if (attr->op_hooks[i] != NULL) {
+ probe_list_delete_list(INTERP, attr->op_hooks[i]);
+ }
+ }
+ mem_gc_free(INTERP, attr->op_hooks);
+ probe_list_delete_list(INTERP, attr->op_catchall);
+ }
+
+/*
+
+=item C<void *insert_op_hooks(PMC *probe, INTVAL op_num)>
+
+Insert a hook for the given op number.
+
+=cut
+
+*/
+
+ METHOD insert_op_hook(PMC *probe, INTVAL op_num) {
+ Parrot_InstrumentRuncore_attributes * const attr = PARROT_INSTRUMENTRUNCORE(SELF);
+
+ if (op_num >= attr->op_hooks_size) {
+ /* Invalid op num */
+ Parrot_ex_throw_from_c_args(INTERP, NULL, 1, "Invalid op number %d.", op_num);
+ }
+
+ if (attr->op_hooks[op_num] == NULL) {
+ attr->op_hooks[op_num] = probe_list_create_list(INTERP);
+ }
+
+ probe_list_push(INTERP, attr->op_hooks[op_num], probe);
+ }
+
+/*
+
+=item C<void *remove_op_hooks(PMC *probe, INTVAL op_num)>
+
+Removes a hook for the given op number.
+
+=cut
+
+*/
+
+ METHOD remove_op_hook(PMC *probe, INTVAL op_num) {
+ Parrot_InstrumentRuncore_attributes * const attr = PARROT_INSTRUMENTRUNCORE(SELF);
+ probe_node_t *node;
+
+ if (op_num >= attr->op_hooks_size) {
+ /* Invalid op num */
+ Parrot_ex_throw_from_c_args(INTERP, NULL, 1, "Invalid op number %d.", op_num);
+ }
+
+ if (attr->op_hooks[op_num] != NULL) {
+ node = probe_list_find(INTERP, attr->op_hooks[op_num], probe);
+ probe_list_remove(INTERP, attr->op_hooks[op_num], node);
+ }
+
+ if (node == NULL) {
+ /* Callback was not found. */
+ PMC *id = VTABLE_get_attr_str(INTERP, probe, CONST_STRING(INTERP, "$!identifier"));
+ Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
+ "Probe '%Ss' not found in 'remove_op_hook'",
+ VTABLE_get_string(INTERP, id));
+ }
+ }
+
+/*
+=item C<INTVAL count_op_hooks(INTVAL op_num)>
+
+Returns the number of enabled op hooks for the given op number.
+
+=cut
+*/
+
+ METHOD count_op_hooks(INTVAL op_num) {
+ Parrot_InstrumentRuncore_attributes * const attr = PARROT_INSTRUMENTRUNCORE(SELF);
+ probe_list_t *list = attr->op_hooks[op_num];
+ INTVAL count = (list == NULL) ? 0: list->count;
+
+ RETURN(INTVAL count);
+ }
+
+/*
+=item C<void *insert_op_catchall(PMC *probe)>
+
+Register a catchall op callback
+
+=cut
+*/
+
+ METHOD insert_op_catchall(PMC *probe) {
+ Parrot_InstrumentRuncore_attributes * const attr = PARROT_INSTRUMENTRUNCORE(SELF);
+ probe_list_push(INTERP, attr->op_catchall, probe);
+ }
+
+/*
+=item C<void *remove_op_catchall(PMC *probe)>
+
+Deregister a catchall op callback
+
+=cut
+*/
+
+ METHOD remove_op_catchall(PMC *probe) {
+ Parrot_InstrumentRuncore_attributes * const attr = PARROT_INSTRUMENTRUNCORE(SELF);
+ probe_node_t *node = NULL;
+
+ node = probe_list_find(INTERP, attr->op_catchall, probe);
+
+ if (node == NULL) {
+ /* Callback was not found. */
+ PMC *id = VTABLE_get_attr_str(INTERP, probe, CONST_STRING(INTERP, "$!identifier"));
+ Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
+ "Probe '%S' not found in 'remove_op_catchall'",
+ VTABLE_get_string(INTERP, id));
+ }
+
+ probe_list_remove(INTERP, attr->op_catchall, node);
+ }
+
+/*
+=item C<INTVAL count_op_catchalls()>
+
+Returns the number of enabled op catchall probes.
+
+=cut
+*/
+
+ METHOD count_op_catchalls() {
+ Parrot_InstrumentRuncore_attributes * const attr = PARROT_INSTRUMENTRUNCORE(SELF);
+ probe_list_t *list = attr->op_catchall;
+ INTVAL count = (list == NULL) ? 0: list->count;
+
+ RETURN(INTVAL count);
+ }
+}
+
+/*
+
+=item C<void runcore_probes_setup(PARROT_INTERP, PMC *runcore)>
+
+Initialises the attributes op_hooks and op_catchall for the given
+InstrumentRuncore instance.
+
+For internal use only.
+
+=cut
+
+*/
+void
+runcore_probes_setup(PARROT_INTERP, PMC *runcore) {
+ probe_list_t **hooks;
+ probe_list_t *catchall;
+ INTVAL count;
+ PMC *instrument;
+ Parrot_Interp supervised;
+
+ GETATTR_InstrumentRuncore_instrument(interp, runcore, instrument);
+ GETATTR_Instrument_supervised(interp, instrument, supervised);
+
+ count = supervised->op_count;
+ hooks = mem_gc_allocate_n_zeroed_typed(interp, count, probe_list_t *);
+ catchall = probe_list_create_list(interp);
+
+ SETATTR_InstrumentRuncore_op_hooks(interp, runcore, hooks);
+ SETATTR_InstrumentRuncore_op_catchall(interp, runcore, catchall);
+ SETATTR_InstrumentRuncore_op_hooks_size(interp, runcore, count);
+}
+
+/*
+
+=item C<void runcore_probes_refresh_tables(PARROT_INTERP, PMC *runcore)>
+
+Whenever the core op tables are updated, due to the loading of dynops,
+the op_hooks table must also be updated. This function will do the
+necessary updates.
+
+For internal use only.
+
+=cut
+
+*/
+
+void
+runcore_probes_refresh_tables(PARROT_INTERP, PMC *runcore) {
+ PMC *instrument;
+ probe_list_t **hooks;
+ INTVAL new_size, old_size;
+ Parrot_Interp supervised;
+
+ GETATTR_InstrumentRuncore_instrument(interp, runcore, instrument);
+ GETATTR_InstrumentRuncore_op_hooks(interp, runcore, hooks);
+ GETATTR_InstrumentRuncore_op_hooks_size(interp, runcore, old_size);
+ GETATTR_Instrument_supervised(interp, instrument, supervised);
+
+ new_size = supervised->op_count;
+
+ if (new_size > old_size) {
+ /* Reallocate the op_hooks table. */
+ hooks = mem_gc_realloc_n_typed_zeroed(interp, hooks, new_size, old_size, probe_list_t *);
+ SETATTR_InstrumentRuncore_op_hooks(interp, runcore, hooks);
+ SETATTR_InstrumentRuncore_op_hooks_size(interp, runcore, new_size);
+ }
+}
+
+/*
+
+=item C<probe_list_t* runcore_probes_get_probes(PARROT_INTERP, PMC *runcore, INTVAL op_num)>
+
+Returns the list of probes applicable to the given op number.
+This list will contain the catchall op hooks + op hooks specific to
+the op given.
+
+For internal use only.
+
+=cut
+
+*/
+
+probe_list_t*
+runcore_probes_get_probes(PARROT_INTERP, PMC *runcore, INTVAL op_num) {
+ probe_list_t *list;
+ probe_list_t **hooks;
+ probe_list_t *catchall;
+
+ GETATTR_InstrumentRuncore_op_hooks(interp, runcore, hooks);
+ GETATTR_InstrumentRuncore_op_catchall(interp, runcore, catchall);
+
+ list = probe_list_create_list(interp);
+
+ probe_list_append(interp, list, catchall);
+ probe_list_append(interp, list, hooks[op_num]);
+
+ return list;
+}
+
+/*
+
+=item C<probe_list_t* runcore_probes_fire_probes(PARROT_INTERP, PMC *runcore,
+opcode_t *pc, probe_list_t *callbacks))>
+
+Given a list of probes, set up the InstrumentOp instance and pass
+it to fire_callbacks for calls.
+
+For internal use only.
+
+=cut
+
+*/
+
+probe_list_t*
+runcore_probes_fire_probes(PARROT_INTERP, PMC *runcore, opcode_t *pc, probe_list_t *callbacks) {
+ PMC *op, *instrument, *interp_pmc;
+ INTVAL op_type;
+
+
+ GETATTR_InstrumentRuncore_instrument(interp, runcore, instrument);
+
+ op_type = Parrot_pmc_get_type_str(interp, CONST_STRING(interp, "InstrumentOp"));
+ op = Parrot_pmc_new_init(interp, op_type, instrument);
+
+ VTABLE_set_pointer(interp, op, pc);
+
+ return fire_callbacks(interp, callbacks, op, instrument);
+}
+
+/*
+
+=item C<void runcore_runcore_setup(PARROT_INTERP, PMC *runcore)>
+
+Changes the supervised interpreter's runcore entry to the
+Instrument runcore.
+
+For internal use only.
+
+=cut
+
+*/
+
+void runcore_runcore_setup(PARROT_INTERP, PMC *runcore) {
+ PMC *instrument;
+ Parrot_Interp supervised;
+ instrument_runcore_t *core;
+
+ GETATTR_InstrumentRuncore_instrument(interp, runcore, instrument);
+ GETATTR_Instrument_supervised(interp, instrument, supervised);
+
+ core = mem_gc_allocate_zeroed_typed(interp, instrument_runcore_t);
+
+ Parrot_set_run_core(interp, PARROT_SLOW_CORE);
+ mem_copy_n_typed(core, supervised->run_core, 1, Parrot_runcore_t);
+
+ core->instrument_rc = runcore;
+ core->supervisor_interp = interp;
+ core->has_ended = 0;
+ core->name = CONST_STRING(supervised, "instrument");
+ core->runops = runcore_runcore_runops;
+ core->prepare_run = NULL;
+ core->destroy = NULL;
+
+ PARROT_RUNCORE_FUNC_TABLE_SET((Parrot_runcore_t *) core);
+ Parrot_runcore_register(supervised, (Parrot_runcore_t *) core);
+ Parrot_runcore_switch(supervised, core->name);
+}
+
+/*
+
+=item C<opcode_t* runcore_runcore_runops(PARROT_INTERP, Parrot_runcore_t *core_ptr, opcode_t *pc)>
+
+Executes the op starting from the op pointed to by pc.
+As each op executes, run the op hooks as necessary.
+
+For internal use only.
+
+=cut
+
+*/
+
+opcode_t* runcore_runcore_runops(PARROT_INTERP, Parrot_runcore_t *core_ptr, opcode_t *pc) {
+ instrument_runcore_t *core;
+ Parrot_Interp supervisor;
+ PMC *runcore;
+ Parrot_runloop exc_handler;
+
+ core = (instrument_runcore_t *) core_ptr;
+ runcore = core->instrument_rc;
+ supervisor = core->supervisor_interp;
+
+ runcore_library_update(supervisor, runcore);
+
+ /* Setup exception handler to handle exits and unhandled exceptions. */
+ if(setjmp(exc_handler.resume)) {
+ /* Return if the exit op is called. */
+ if(*pc == enum_ops_exit_i
+ || *pc == enum_ops_exit_ic) {
+ core->has_ended = 1;
+ return pc;
+ }
+
+ /* Rethrow otherwise. */
+ Parrot_ex_rethrow_from_c(interp, exc_handler.exception);
+ }
+ Parrot_ex_add_c_handler(interp, &exc_handler);
+
+ /* Runloop */
+ while (pc && !(core->has_ended)) {
+ probe_list_t *callbacks, *recalls, *ignore;
+ opcode_t *pc_copy = pc;
+
+ Parrot_pcc_set_pc(interp, CURRENT_CONTEXT(interp), pc);
+
+ /* Get the list of callbacks to call and execute the op. */
+ callbacks = runcore_probes_get_probes(supervisor, runcore, *pc);
+ recalls = runcore_probes_fire_probes(supervisor, runcore, pc, callbacks);
+ DO_OP(pc, interp);
+ ignore = runcore_probes_fire_probes(supervisor, runcore, pc_copy, recalls);
+ probe_list_delete_list(supervisor, ignore);
+
+ /* On loading a dynlib or bytecode, we need to update a few things. */
+ if (runcore_does_loading(pc_copy)) {
+ runcore_library_update(supervisor, runcore);
+ }
+
+ /* Force events */
+ Parrot_cx_handle_tasks(interp, interp->scheduler);
+ Parrot_cx_handle_tasks(supervisor, supervisor->scheduler);
+ }
+
+ return pc;
+}
+
+/*
+
+=item C<void runcore_library_update(PARROT_INTERP, PMC *runcore)>
+
+Keeps track of the dynamic libraries loaded by the supervised interpreter.
+Upon detection of a newly loaded library, raises an Internal::loadlib::libname
+event.
+
+For internal use only.
+
+=cut
+
+*/
+
+void runcore_library_update(PARROT_INTERP, PMC *runcore) {
+ PMC *instrument;
+ Parrot_Interp supervised;
+ PMC *cur_dynlibs, *old_dynlibs;
+ INTVAL cur_count, old_count;
+
+ STRING *refresh = CONST_STRING(interp, "refresh_probes");
+
+ GETATTR_InstrumentRuncore_instrument(interp, runcore, instrument);
+ GETATTR_InstrumentRuncore_dynlibs(interp, runcore, old_dynlibs);
+ GETATTR_Instrument_supervised(interp, instrument, supervised);
+
+ cur_dynlibs = VTABLE_get_pmc_keyed_int(supervised, supervised->iglobals, IGLOBALS_DYN_LIBS);
+
+ /* Check for new dynlibs by comparing the counts. */
+ old_count = VTABLE_get_integer(interp, old_dynlibs);
+ cur_count = VTABLE_get_integer(supervised, cur_dynlibs);
+
+ runcore_optable_fixup(interp, runcore);
+ runcore_vtable_fixup(interp, runcore);
+
+ if (old_count != cur_count) {
+ PMC *iter;
+
+ /* Look for the new dynlibs and raise an event about them. */
+ iter = VTABLE_get_iter(supervised, cur_dynlibs);
+ while (VTABLE_get_bool(supervised, iter)) {
+ PMC *key;
+
+ key = VTABLE_shift_pmc(supervised, iter);
+
+ if (!VTABLE_exists_keyed(interp, old_dynlibs, key)) {
+ /* New lib detected. */
+ PMC *lib, *task_data, *recall;
+ STRING *event;
+
+ lib = VTABLE_get_pmc_keyed(supervised, cur_dynlibs, key);
+ task_data = Parrot_pmc_new(interp, enum_class_Hash);
+
+ VTABLE_set_pmc_keyed_str(interp, task_data, CONST_STRING(interp, "library"), lib);
+ event = Parrot_sprintf_c(interp, "Internal::loadlib::%Ss",
+ VTABLE_name(supervised, lib));
+
+ /* Fire the event and discard the list returned. */
+ Parrot_pcc_invoke_method_from_c_args(interp, instrument,
+ CONST_STRING(interp, "raise_event"),
+ "SP->P", event, task_data, &recall);
+ probe_list_delete_list(interp, (probe_list_t *) VTABLE_get_pointer(interp, recall));
+
+ /* Add lib to the old dynlib hash */
+ VTABLE_set_pmc_keyed(interp, old_dynlibs, key, lib);
+ }
+ }
+ }
+
+ /* Refresh the probes. */
+ Parrot_pcc_invoke_method_from_c_args(interp, instrument, refresh, "->");
+}
+
+/*
+
+=item C<void runcore_vtable_fixup(PARROT_INTERP, PMC *runcore) >
+
+Keep the vtables in the child and parent in sync.
+
+For internal use only.
+
+=cut
+
+*/
+
+void runcore_vtable_fixup(PARROT_INTERP, PMC *runcore) {
+ INTVAL i;
+ PMC *instrument;
+ Parrot_Interp supervised, dest, src;
+
+ GETATTR_InstrumentRuncore_instrument(interp, runcore, instrument);
+ GETATTR_Instrument_supervised(interp, instrument, supervised);
+
+ /* Dest is the one with the smaller vtable. */
+ if (interp->n_vtable_max > supervised->n_vtable_max) {
+ dest = supervised;
+ src = interp;
+ }
+ else {
+ dest = interp;
+ src = supervised;
+ }
+
+ /* Extend dest's vtable if needed. */
+ if (dest->n_vtable_alloced < src->n_vtable_max) {
+ INTVAL new_size;
+ new_size = src->n_vtable_max + 16;
+ dest->vtables = mem_gc_realloc_n_typed_zeroed(dest, dest->vtables,
+ new_size, dest->n_vtable_alloced,
+ VTABLE *);
+ dest->n_vtable_alloced = new_size;
+ }
+
+ /* Copy over the new vtable entries. */
+ for (i = dest->n_vtable_max; i < src->n_vtable_max; i++) {
+ dest->vtables[i] = src->vtables[i];
+ }
+
+ dest->n_vtable_max = src->n_vtable_max;
+}
+
+/*
+
+=item C<void runcore_optable_fixup(PARROT_INTERP, PMC *runcore) >
+
+Whenever a dynop library is loaded, the op table references
+are highly likely to change. Detect these changes and update
+the op table references in the supervising interpreter.
+
+For internal use only.
+
+=cut
+
+*/
+
+void runcore_optable_fixup(PARROT_INTERP, PMC *runcore) {
+ op_lib_t *core_lib;
+
+ /* Reset interp's optables if needed. */
+ core_lib = interp->run_core->opinit(interp, 1);
+ if (interp->op_count != core_lib->op_count) {
+ interp->op_count = core_lib->op_count;
+ interp->op_info_table = core_lib->op_info_table;
+ interp->op_func_table = core_lib->op_func_table;
+
+ /* Remove dest's evc_func_table */
+ if (interp->evc_func_table != NULL) {
+ mem_gc_free(interp, interp->evc_func_table);
+
+ interp->evc_func_table = NULL;
+ interp->save_func_table = NULL;
+
+ Parrot_setup_event_func_ptrs(interp);
+ }
+
+ /* Refresh the op_hook tables */
+ runcore_probes_refresh_tables(interp, runcore);
+ }
+}
+
+/*
+
+=item C<INTVAL runcore_does_loading(opcode_t *pc) >
+
+Returns true if the op pointed to by pc is one that
+either loads a dynlib or bytecode.
+
+For internal use only.
+
+=cut
+
+*/
+
+INTVAL runcore_does_loading(opcode_t *pc) {
+ return (*pc == enum_ops_loadlib_p_s
+ || *pc == enum_ops_loadlib_p_sc
+ || *pc == enum_ops_loadlib_p_s_p
+ || *pc == enum_ops_loadlib_p_sc_p
+ || *pc == enum_ops_loadlib_p_s_pc
+ || *pc == enum_ops_loadlib_p_sc_pc
+ || *pc == enum_ops_load_bytecode_s
+ || *pc == enum_ops_load_bytecode_sc);
+}
+
+/*
+
+=back
+
+*/
+
+
+/*
+ * Local variables:
+ * c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */
More information about the parrot-commits
mailing list