[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