Thursday 24 June 2010

Byteman 1.3.0 Available Now

Byteman 1.3.0 has been released and is now available at the project download page and the JBoss maven repository. The release contains several new features and about a dozen bug fixes. It also includes the first byteman user contrib package, dtest.

New User Package

dtest is a tool contributed by JBossTS project lead Jonathan Halliday which uses Byteman to instrument and validate execution of distributed test programs. It has been used to test the JTA/XTS transaction bridge crash recovery code running in a JBoss AS container started by a stand-alone test client.

New Features

The following is a summary of the new features added in release 1.3.0. Full details are provided in the programmer guide.

Lifecycle events
1.3.0 introduces lifecycle events for rules and helper classes. If a rule helper class implements specific lifecycle methods then Byteman will ensure these methods are invoked as rules which employ the helper are loaded into or removed from the JVM.
  • static method activate is invoked immediately after the first rule mentioning a helper is injected into a trigger method and compiled
  • static method deactivate is invoked just before the last rule mentioning the helper is removed from a trigger method at unload
  • static method install is called immediately after an individual rule mentioning the helper is injected into a trigger method and compiled.
  • static method deinstall is called just before an individual rule mentioning the helper is removed from a trigger method at unload
The samples distributed with the release includes a simple example script and helper class which rely on lifecycle events to generate periodic statistics on JVM execution. The rules use the counter built-ins to count JVM events such as thread starts and exits, file opens and closes etc.

When the rules are loaded into the JVM the rule helper is activated and it spawns a thread which periodically calls method periodicTrigger. A rule attached to this method collects and resets the counters used by the other rules then dumps the statistics to System.out.

The spawned thread sleeps for a fixed interval before looping and calling periodicTrigger again. The example script uses an AT RETURN rule attached to method getPeriod to redefine this interval.

When the rules are unloaded the helper is deactivated and it shuts down the thread returning the JVM to the state it was in before the rules were loaded.

Special variables
Several new special variables have been added to provide access to more trigger method state
  • $^ available in AT THROW rules bound to the Throwable on the stack at the point where the rule is triggered
  • $* bound to an Object[] containing this at index 0 (or null if the trigger method is static) and the trigger method arguments at index 1 . . .
  • $# bound to the number of trigger method arguments
  • $@ available in AT INVOKE rules bound to an Object[] containing the invoked method target at index 0 (or null if the invoked method is static) and the invoked method arguments at index 1 . . .
AT ALL Locations
Locations which previously employed a count to identify which of several trigger points should be selected now also support the ALL keyword to request injection at every occurence. For example, specifying location AT READ name ALL will cause the rule to be injected at every place in the target method where field name is read.

Overriding the default HELPER
If a rule does not specify a HELPER clause in its body (between the RULE and ENDRULE clauses) it inherits the default HELPER class org.jboss.byteman.helper.rule.Helper. Rule scripts can now include HELPER clauses at the start or between rules to reset the default helper class. This will be used for all subsequent rules in the script which do not specify their own helper until another HELPER clause resets the class again or an empty HELPER clause reverts to the usual default HELPER.

New Helper methods
Several of the methods provided in the sample library have now been migrated to the default helper class and supplemented with related functionality. In particular, this includes methods which support checking the call stack, and formatting and printing stack traces.

Call stack checking is very useful in rule conditions to ensure that rules are only fired when the trigger method is called from certain code paths. For example, a rule attached to String.append() can use condition IF callerEquals("MyClass.myMethod", true) to ensure that the rule only fires when it is called from method myMethod of class MyClass.

bytemancheck package parameters
The target class for a rule specified in the CLASS clause may omit the package qualifier. Byteman responds by injecting the rule into any class loaded during application execution whose unqualified name matches the supplied value. This causes a problem for the offline type checker tool bytemancheck. It cannot identify which classes to load in order to check the rule without loading and running the application. bytemancheck now accepts one or more optional -p package name arguments. These package names are prefixed to unqualified target class names until a loadable class is found which can be used to typecheck the rule.