[svn:parrot] r48181 - in branches/gsoc_instrument: . src/dynpmc t/dynpmc
khairul at svn.parrot.org
khairul at svn.parrot.org
Tue Jul 27 03:13:48 UTC 2010
Author: khairul
Date: Tue Jul 27 03:13:47 2010
New Revision: 48181
URL: https://trac.parrot.org/parrot/changeset/48181
Log:
Added test for InstrumentClass.pmc
Added:
branches/gsoc_instrument/t/dynpmc/instrumentclass.t
Modified:
branches/gsoc_instrument/MANIFEST
branches/gsoc_instrument/src/dynpmc/instrumentclass.pmc
branches/gsoc_instrument/src/dynpmc/instrumentobject.pmc
branches/gsoc_instrument/src/dynpmc/instrumentstubbase.pmc
branches/gsoc_instrument/src/dynpmc/instrumentvtable.pmc
Modified: branches/gsoc_instrument/MANIFEST
==============================================================================
--- branches/gsoc_instrument/MANIFEST Mon Jul 26 17:57:00 2010 (r48180)
+++ branches/gsoc_instrument/MANIFEST Tue Jul 27 03:13:47 2010 (r48181)
@@ -1688,7 +1688,9 @@
t/dynpmc/foo2.t [test]
t/dynpmc/gziphandle.t [test]
t/dynpmc/instrument.t [test]
+t/dynpmc/instrumentclass.t [test]
t/dynpmc/instrumentgc.t [test]
+t/dynpmc/instrumentobject.t [test]
t/dynpmc/instrumentop.t [test]
t/dynpmc/instrumentvtable.t [test]
t/dynpmc/os.t [test]
Modified: branches/gsoc_instrument/src/dynpmc/instrumentclass.pmc
==============================================================================
--- branches/gsoc_instrument/src/dynpmc/instrumentclass.pmc Mon Jul 26 17:57:00 2010 (r48180)
+++ branches/gsoc_instrument/src/dynpmc/instrumentclass.pmc Tue Jul 27 03:13:47 2010 (r48181)
@@ -130,9 +130,7 @@
/* Add an entry into the rename_hash attribute so that when an event
is raised, the event properly named. */
- rename = Parrot_pmc_new(INTERP, enum_class_ResizableStringArray);
- VTABLE_push_string(INTERP, rename , CONST_STRING(INTERP, "Class"));
- VTABLE_push_string(INTERP, rename , attr->class_name);
+ rename = VTABLE_clone(INTERP, attr->event_prefix);
VTABLE_push_string(INTERP, rename , CONST_STRING(INTERP, "method"));
VTABLE_push_string(INTERP, rename , method);
@@ -180,6 +178,9 @@
count = VTABLE_get_integer_keyed_str(INTERP, attr->instrumented_methods, method);
if (count == 0) {
/* Not instrumented before. */
+ Parrot_ex_throw_from_c_args(INTERP, NULL, 1,
+ "%Ss : No hook for method '%Ss' to remove.",
+ VTABLE_name(INTERP, SELF), method);
}
else if (count == 1) {
/* Remove the instrumentation. */
Modified: branches/gsoc_instrument/src/dynpmc/instrumentobject.pmc
==============================================================================
--- branches/gsoc_instrument/src/dynpmc/instrumentobject.pmc Mon Jul 26 17:57:00 2010 (r48180)
+++ branches/gsoc_instrument/src/dynpmc/instrumentobject.pmc Tue Jul 27 03:13:47 2010 (r48181)
@@ -58,6 +58,7 @@
METHOD attach_to_object(PMC *object) {
Parrot_InstrumentObject_attributes * const attr = PARROT_INSTRUMENTOBJECT(SELF);
Parrot_Interp supervised;
+ STRING *addr;
GETATTR_Instrument_supervised(INTERP, attr->instrument, supervised);
@@ -72,9 +73,56 @@
setup_vtable_individual_hashes(INTERP, attr->name_original, attr->name_offset,
(_vtable *) attr->original_struct,
(_vtable *) attr->instrumented_struct);
+
+ /* Update the event_prefix attribute. */
+ (STRING *addr) = PCCINVOKE(INTERP, SELF, "get_address");
+ VTABLE_push_string(INTERP, attr->event_prefix, CONST_STRING(INTERP, "Object"));
+ VTABLE_push_string(INTERP, attr->event_prefix, addr);
+ }
+
+ METHOD get_address() {
+ STRING *addr;
+ addr = Parrot_sprintf_c(INTERP, "%p", SELF);
+ RETURN(STRING *addr);
}
}
+static
+opcode_t *
+stub_object_invoke(PARROT_INTERP, PMC *pmc, opcode_t *dest) {
+ PMC *instr_vt, *data;
+ void *orig_vtable;
+ Parrot_Interp supervisor;
+ PMC *temp;
+ PMC *params;
+ opcode_t* ret;
+
+ instr_vt = (PMC *) parrot_hash_get(interp, vtable_registry, pmc->vtable);
+
+ GETATTR_InstrumentVtable_original_struct(interp, instr_vt, orig_vtable);
+ GETATTR_InstrumentVtable_supervisor(interp, instr_vt, supervisor);
+
+ params = Parrot_pmc_new(supervisor, enum_class_ResizablePMCArray);
+ VTABLE_push_pmc(supervisor, params, pmc);
+ temp = Parrot_pmc_new(supervisor, enum_class_Pointer);
+ VTABLE_set_pointer(supervisor, temp, next);
+ VTABLE_push_pmc(supervisor, params, temp);
+
+
+ data = Parrot_pmc_new(supervisor, enum_class_Hash);
+ VTABLE_set_pmc_keyed_str(supervisor, data,
+ CONST_STRING(supervisor, "parameters"),
+ params);
+
+ raise_vtable_event(supervisor, interp, instr_vt, pmc, data,
+ CONST_STRING(supervisor, "main"),
+ CONST_STRING(supervisor, "invoke"));
+
+
+ ret = ((_vtable *)orig_vtable)->invoke(interp, pmc, next);
+ return ret;
+}
+
/*
=back
Modified: branches/gsoc_instrument/src/dynpmc/instrumentstubbase.pmc
==============================================================================
--- branches/gsoc_instrument/src/dynpmc/instrumentstubbase.pmc Mon Jul 26 17:57:00 2010 (r48180)
+++ branches/gsoc_instrument/src/dynpmc/instrumentstubbase.pmc Tue Jul 27 03:13:47 2010 (r48181)
@@ -24,6 +24,7 @@
pmclass InstrumentStubBase auto_attrs dynpmc group instrument_group {
ATTR PMC *instrument; /* Reference to the Instrument object, for various purposes. */
ATTR PMC *hook_count; /* Keeps track of hook requests for a particular entry. */
+ ATTR PMC *event_prefix; /* Prefix to put in front of the event. */
ATTR Hash *name_stubs; /* Mapping item name with the corresponding stub entry. */
ATTR Hash *name_original; /* Mapping item name with the original item entry. */
ATTR Hash *name_offset; /* Mapping item name with the pointer address in the struct. */
@@ -73,6 +74,7 @@
attr->item_groups = NULL;
attr->original_struct = NULL;
attr->instrumented_struct = NULL;
+ attr->event_prefix = Parrot_pmc_new(INTERP, enum_class_ResizableStringArray);
/* Set custom mark and destroy. */
PObj_custom_mark_destroy_SETALL(SELF);
@@ -92,6 +94,7 @@
Parrot_InstrumentStubBase_attributes * const attr = PARROT_INSTRUMENTSTUBBASE(SELF);
Parrot_gc_mark_PMC_alive_fun(INTERP, attr->hook_count);
+ Parrot_gc_mark_PMC_alive_fun(INTERP, attr->event_prefix);
parrot_mark_hash(INTERP, attr->group_items);
parrot_mark_hash(INTERP, attr->item_groups);
Modified: branches/gsoc_instrument/src/dynpmc/instrumentvtable.pmc
==============================================================================
--- branches/gsoc_instrument/src/dynpmc/instrumentvtable.pmc Mon Jul 26 17:57:00 2010 (r48180)
+++ branches/gsoc_instrument/src/dynpmc/instrumentvtable.pmc Tue Jul 27 03:13:47 2010 (r48181)
@@ -142,6 +142,10 @@
setup_vtable_individual_hashes(INTERP, attr->name_original, attr->name_offset,
(_vtable *) attr->original_struct,
(_vtable *) attr->instrumented_struct);
+
+ /* Update the event_prefix attribute. */
+ VTABLE_push_string(INTERP, attr->event_prefix, CONST_STRING(INTERP, "Class"));
+ VTABLE_push_string(INTERP, attr->event_prefix, classname);
}
/*
@@ -212,9 +216,7 @@
/* Add an entry into the rename_hash attribute so that when an event
is raised, the event properly named. */
group = (PMC *) parrot_hash_get(INTERP, attr->item_groups, name);
- rename = Parrot_pmc_new(INTERP, enum_class_ResizableStringArray);
- VTABLE_push_string(INTERP, rename , CONST_STRING(INTERP, "Class"));
- VTABLE_push_string(INTERP, rename , attr->class_name);
+ rename = VTABLE_clone(INTERP, attr->event_prefix);
VTABLE_push_string(INTERP, rename , CONST_STRING(INTERP, "vtable"));
VTABLE_push_string(INTERP, rename ,
VTABLE_get_string_keyed_int(INTERP, group, 0));
@@ -334,9 +336,11 @@
event_arr = VTABLE_get_pmc_keyed_str(interp, rename_hash, type);
}
else {
- event_arr = Parrot_pmc_new(interp, enum_class_ResizableStringArray);
- VTABLE_push_string(interp, event_arr, CONST_STRING(interp, "Class"));
- VTABLE_push_string(interp, event_arr, pmc->vtable->whoami);
+ PMC *prefix;
+
+ GETATTR_InstrumentVtable_event_prefix(interp, pmc, prefix);
+
+ event_arr = VTABLE_clone(interp, prefix);
VTABLE_push_string(interp, event_arr, CONST_STRING(interp, "vtable"));
VTABLE_push_string(interp, event_arr, group);
VTABLE_push_string(interp, event_arr, type);
Added: branches/gsoc_instrument/t/dynpmc/instrumentclass.t
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ branches/gsoc_instrument/t/dynpmc/instrumentclass.t Tue Jul 27 03:13:47 2010 (r48181)
@@ -0,0 +1,327 @@
+#!./parrot
+# Copyright (C) 2010, Parrot Foundation.
+# $Id: instrumentvtable.t 48171 2010-07-24 16:24:39Z khairul $
+
+=head1 NAME
+
+t/dynpmc/instrumentclass.t - test the InstrumentClass dynpmc
+
+=head1 SYNOPSIS
+
+ % prove t/dynpmc/instrumentvtable.t
+
+=head1 DESCRIPTION
+
+Tests the method notification interface provided by the InstrumentClass pmc.
+InstrumentClass inherits from InstrumentVtable, so we would only be
+testing method-related methods of InstrumentClass.
+
+=cut
+
+.include 'call_bits.pasm'
+.loadlib 'os'
+
+.sub main :main
+ .include 'test_more.pir'
+
+ # Load the Instrument library.
+ load_bytecode 'Instrument/InstrumentLib.pbc'
+
+ plan(13)
+
+ setup()
+ test_insertion()
+ test_removal()
+ test_notification()
+ cleanup()
+
+ .return()
+.end
+
+
+.sub setup
+ # Create a simple program to test that events are raised.
+ .local string program
+ program = <<'PROG'
+.sub main :main
+ $P0 = new ['TestClass']
+ $P0.'test'()
+.end
+
+.namespace ['TestClass']
+.sub '' :anon :init :load
+ $P0 = newclass ['TestClass']
+.end
+
+# Test methods.
+.sub test :method
+ # Do nothing.
+.end
+
+PROG
+
+ # Write to file.
+ .local pmc fh
+ fh = new ['FileHandle']
+ fh.'open'('t/dynpmc/instrumentclass-test1.pir', 'w')
+ fh.'puts'(program)
+ fh.'close'()
+.end
+
+.sub cleanup
+ # Remove the test program.
+ .local pmc os
+ os = new ['OS']
+ os.'rm'('t/dynpmc/instrumentclass-test1.pir')
+.end
+
+.sub test_insertion
+ # Test insertion a method hook.
+ # ResizablePMCArray has a push method.
+ # Check:
+ # 1. We can insert a hook for the method.
+ # 2. Inserting on a non-existent method raises an exception.
+ $P0 = new ['Instrument']
+
+ ## Scenario 1: Insert a method hook.
+ $P1 = $P0.'instrument_class'('ResizablePMCArray')
+
+ $P1.'insert_method_hook'('push')
+ $P2 = $P1.'get_instrumented_method_list'()
+
+ $I0 = $P2
+ $S0 = $P2[0]
+ is($I0, 1, 'Insert: 1: Count ok.')
+ is($S0, 'push', 'Insert: 1: Name ok.')
+
+ ## Scenario 2: Insert a non-existent hook.
+ $P3 = new ['ExceptionHandler']
+ set_addr $P3, INSERT_OK
+ push_eh $P3
+
+ $P1.'insert_method_hook'('pusha')
+
+ ok(0, 'Insert: 2: Inserting a hook to a non-existent method did not throw exception.')
+
+ goto INSERT_END
+
+ INSERT_OK:
+ ok(1, 'Insert: 2: Inserting a hook to a non-existent method threw exception.')
+ INSERT_END:
+.end
+
+.sub test_removal
+ # Test removing a method hook.
+ # Check:
+ # 1. Removal is ok.
+ # 2. Insert twice and remove once the hook is still in place.
+ # 3. Insert once and remove twice throws an exception.
+ # 4. Try to remove a non-existent hook throws exception.
+ $P0 = new ['Instrument']
+ $P1 = $P0.'instrument_class'('ResizablePMCArray')
+
+ ## Scenario 1: Insert once and remove once.
+ $P1.'insert_method_hook'('push')
+ $P1.'remove_method_hook'('push')
+
+ $P2 = $P1.'get_instrumented_method_list'()
+
+ $I0 = $P2
+ is($I0, 0, 'Remove: 1: Count ok.')
+
+ ## Scenario 2: Insert twice and remove once.
+ $P1.'insert_method_hook'('push')
+ $P1.'insert_method_hook'('push')
+ $P1.'remove_method_hook'('push')
+
+ $P2 = $P1.'get_instrumented_method_list'()
+
+ $I0 = $P2
+ $S0 = $P2[0]
+ is($I0, 1, 'Remove: 2: Count ok.')
+ is($S0, 'push', 'Remove: 2: Name ok.')
+
+ # Cleanup, remove the existing hook.
+ $P1.'remove_method_hook'('push')
+
+ ## Scenario 3: Insert once and remove twice.
+ $P3 = new ['ExceptionHandler']
+ set_addr $P3, TOO_MANY_OK
+ push_eh $P3
+
+ $P1.'insert_method_hook'('push')
+ $P1.'remove_method_hook'('push')
+ $P1.'remove_method_hook'('push')
+
+ ok(0, 'Remove: 3: Removing a hook too many times did not throw an exception.')
+
+ goto TOO_MANY_END
+
+ TOO_MANY_OK:
+ ok(1, 'Remove: 3: Removing a hook too many times threw an exception.')
+ TOO_MANY_END:
+
+ ## Scenario 4: Remove a non-existing hook.
+ $P3 = new ['ExceptionHandler']
+ set_addr $P3, NON_EXIST_OK
+ push_eh $P3
+
+ $P1.'remove_method_hook'('pusha')
+
+ ok(0, 'Remove: 4: Removing a non-existing hook did not throw an exception.')
+
+ goto NON_EXIST_END
+
+ NON_EXIST_OK:
+ ok(1, 'Remove: 4: Removing a non-existing hook threw an exception.')
+ NON_EXIST_END:
+.end
+
+.sub test_notification
+ # Test if notification is raised after a method is instrumented.
+ # Check:
+ # 1. Event is raised.
+ # 2. The event is of type Class::Class_Name::method::Method_Name
+ $P0 = new ['Instrument']
+
+ $P1 = get_hll_global ['Instrument';'Event'], 'Class'
+ $P2 = $P1.'new'()
+
+ $P2.'inspect_class'('TestClass')
+ $P2.'inspect_method'('test')
+ $P2.'callback'('test_notification_cb')
+
+ $P0.'attach'($P2)
+
+ $P3 = new ['ResizableStringArray']
+ push $P3, 't/dynpmc/instrumentclass-test1.pir'
+ $S0 = $P3[0]
+
+ # Prepare the globals.
+ $P4 = new ['Hash']
+ set_global '%notification', $P4
+
+ $P0.'run'($S0, $P3)
+
+ # Check that the callback was called.
+ # Check that the event was fired.
+ $P9 = get_global '%notification'
+
+ # Event fired.
+ $I0 = $P9['called']
+ is($I0, 1, 'Event: Event fired.')
+
+ # Test line.
+ $I0 = $P9['line']
+ is($I0, 3, 'Event: Line ok.')
+
+ # Test file.
+ $S0 = $P9['file']
+ is($S0, 't/dynpmc/instrumentclass-test1.pir', 'Event: File ok.')
+
+ # Test sub.
+ $S0 = $P9['sub']
+ is($S0, 'main', 'Event: Sub ok.')
+
+ # Test event.
+ $P10 = $P9['event']
+ $S0 = join '::', $P10
+ is($S0, 'Class::TestClass::method::test', 'Event: Event ok')
+
+.end
+
+.sub test_notification_cb
+ .param pmc data
+
+ $P0 = get_global '%notification'
+
+ $P0['called'] = 1
+
+ $P1 = data['event']
+ $P0['event'] = $P1
+
+ $I0 = data['line']
+ $P0['line'] = $I0
+
+ $S0 = data['file']
+ $P0['file'] = $S0
+
+ $S0 = data['sub']
+ $P0['sub'] = $S0
+.end
+
+
+## Helper: Find an item in the list.
+.sub find_in_list
+ .param pmc list
+ .param pmc item
+
+ $I0 = list
+
+ TOP:
+ dec $I0
+ unless $I0 >= 0 goto END
+
+ $P0 = list[$I0]
+ if $P0 == item goto FOUND
+
+ goto TOP
+ END:
+
+ # Not found.
+ .return(0)
+
+ FOUND:
+ .return(1)
+.end
+
+# Helper sub: Check if 2 sets with unique items are the same.
+.sub is_same_set
+ .param pmc arr1
+ .param pmc arr2
+ .local pmc hash
+
+ $I0 = arr1
+ $I1 = arr2
+ if $I0 != $I1 goto NO
+
+ hash = new ['Hash']
+
+ # Build the comparison hash
+ $I3 = 0
+ INSERT_LOOP:
+ if $I3 >= $I0 goto END_INSERT_LOOP
+
+ $S0 = arr1[$I3]
+ hash[$S0] = 1
+
+ inc $I3
+ goto INSERT_LOOP
+ END_INSERT_LOOP:
+
+ # Check the contents of arr2
+ $I3 = 0
+ CHECK_LOOP:
+ if $I3 >= $I0 goto END_CHECK_LOOP
+
+ $S0 = arr2[$I3]
+ $I4 = exists hash[$S0]
+
+ if $I4 == 0 goto NO
+
+ inc $I3
+ goto CHECK_LOOP
+ END_CHECK_LOOP:
+
+ YES:
+ .return(1)
+
+ NO:
+ .return(0)
+.end
+
+# Local Variables:
+# mode: pir
+# fill-column: 100
+# End:
+# vim: expandtab shiftwidth=4 ft=pir:
More information about the parrot-commits
mailing list