[jboss-svn-commits] JBL Code SVN: r25494 - in labs/jbosstm/workspace/adinn/orchestration: docs and 2 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Wed Mar 4 11:38:01 EST 2009
Author: adinn
Date: 2009-03-04 11:38:01 -0500 (Wed, 04 Mar 2009)
New Revision: 25494
Added:
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ExitCheckAdapter.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ExitTriggerAdapter.java
Modified:
labs/jbosstm/workspace/adinn/orchestration/README
labs/jbosstm/workspace/adinn/orchestration/docs/ProgrammersGuide.odt
labs/jbosstm/workspace/adinn/orchestration/docs/ProgrammersGuide.pdf
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Location.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/LocationType.java
Log:
added support for AT EXIT (equyivalently AT RETURN) trigger location and documented it
Modified: labs/jbosstm/workspace/adinn/orchestration/README
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/README 2009-03-04 14:29:14 UTC (rev 25493)
+++ labs/jbosstm/workspace/adinn/orchestration/README 2009-03-04 16:38:01 UTC (rev 25494)
@@ -149,9 +149,11 @@
located. The simplest location specification is AT ENTRY which locates
the triggerpoint at the first executable instruction in a the atrget
method's bytecode (or the first instruction following the superclass
-constructor if the target method is a constructor). Other qualifiers
-include
+constructor if the target method is a constructor). The full list of
+qualifiers is
+AT ENTRY
+AT EXIT
AT LINE <number>
AT READ <fieldname> [<count>]
AT WRITE <fieldname> [<count>]
Modified: labs/jbosstm/workspace/adinn/orchestration/docs/ProgrammersGuide.odt
===================================================================
(Binary files differ)
Modified: labs/jbosstm/workspace/adinn/orchestration/docs/ProgrammersGuide.pdf
===================================================================
(Binary files differ)
Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Location.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Location.java 2009-03-04 14:29:14 UTC (rev 25493)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/Location.java 2009-03-04 16:38:01 UTC (rev 25494)
@@ -42,6 +42,8 @@
return SynchronizeLocation.create(parameters, true);
case THROW:
return ThrowLocation.create(parameters);
+ case EXIT:
+ return ExitLocation.create(parameters);
}
return null;
@@ -652,4 +654,49 @@
return text;
}
}
+ /**
+ * location identifying a method exit trigger point
+ */
+ private static class ExitLocation extends Location
+ {
+ /**
+ * create a location identifying a method entry trigger point
+ * @param parameters the text of the parameters appended to the location specifier
+ * @return a method entry location or null if the parameters is not a blank String
+ */
+ protected static Location create(String parameters) {
+ if (!parameters.trim().equals("")) {
+ // hmm, not expecting any parameters here
+ return null;
+ }
+ return new ExitLocation();
+ }
+
+ /**
+ * return an adapter which can be used to check whether a method contains a trigger point whose position
+ * matches this location
+ * @return the required adapter
+ */
+ public RuleCheckAdapter getRuleCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod) {
+ // a line check adapter with line -1 will do the job
+
+ return new ExitCheckAdapter(cv, targetClass, targetMethod);
+ }
+
+ /**
+ * return an adapter which can be used to insert a trigger call in a method containing a trigger point whose
+ * position matches this location
+ * @return the required adapter
+ */
+ public RuleTriggerAdapter getRuleAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod) {
+ // a line adapter with line -1 will do the job
+
+ return new ExitTriggerAdapter(cv, rule, targetClass, targetMethod);
+ }
+
+ public String toString() {
+ return "AT EXIT";
+ }
+ }
+
}
Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/LocationType.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/LocationType.java 2009-03-04 14:29:14 UTC (rev 25493)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/LocationType.java 2009-03-04 16:38:01 UTC (rev 25494)
@@ -61,8 +61,6 @@
* script syntax : 'AFTER' 'INVOKE' [<typename> '.' ] <methodname> ['(' <argtypes> ')' [ <count> ]
*/
INVOKE_COMPLETED,
- // this is tricky so we exclude it for now
- // EXIT,
/**
* specifies a location for trigger insertion by identifying a synchronize operation or the nth such
* operation if a count is supplied.
@@ -84,8 +82,14 @@
* script syntax : 'AT' 'THROW' [<typename>] [ <count> ]
* n.b. exception typename parsed but not yet implemented
*/
- THROW;
+ THROW,
+ /**
+ * specifies a location for trigger insertion at return from the trigger method
+ * script syntax : 'AT' 'RETURN'
+ */
+ EXIT;
+
public String specifierText()
{
for (int i = 0; i < specifiers.length; i++) {
@@ -136,9 +140,11 @@
"AT SYNCHRONIZE",
"AFTER SYNCHRONIZE",
"AT THROW",
+ "AT EXIT",
"LINE", // for compatibility
"AT CALL", // for ambiguity :-)
- "AFTER CALL" // for ambiguity :-)
+ "AFTER CALL", // for ambiguity :-)
+ "AT RETURN" // for ambiguity :-)
};
private static LocationType[] types = {
@@ -153,8 +159,10 @@
SYNCHRONIZE,
SYNCHRONIZE_COMPLETED,
THROW,
+ EXIT,
LINE,
INVOKE,
- INVOKE_COMPLETED
+ INVOKE_COMPLETED,
+ EXIT
};
}
Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ExitCheckAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ExitCheckAdapter.java (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ExitCheckAdapter.java 2009-03-04 16:38:01 UTC (rev 25494)
@@ -0,0 +1,15 @@
+package org.jboss.jbossts.orchestration.agent.adapter;
+
+import org.objectweb.asm.*;
+
+/**
+ * asm Adapter class used to check that the target method for a rule exists in a class
+ */
+public class ExitCheckAdapter extends RuleCheckAdapter
+{
+ public ExitCheckAdapter(ClassVisitor cv, String targetClass, String targetMethod) {
+ super(cv, targetClass, targetMethod);
+ // all methods return at some point so we always insert a trigger somewhere
+ setVisitOk();
+ }
+}
Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ExitTriggerAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ExitTriggerAdapter.java (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ExitTriggerAdapter.java 2009-03-04 16:38:01 UTC (rev 25494)
@@ -0,0 +1,238 @@
+package org.jboss.jbossts.orchestration.agent.adapter;
+
+import org.objectweb.asm.*;
+import org.objectweb.asm.commons.Method;
+import org.objectweb.asm.commons.GeneratorAdapter;
+import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
+import org.jboss.jbossts.orchestration.agent.Transformer;
+
+import java.util.Vector;
+
+/**
+ * asm Adapter class used to add a rule event trigger call to a method of some given class
+ */
+public class ExitTriggerAdapter extends RuleTriggerAdapter
+{
+ /**
+ * table used to track which returns have been added because of exception handling code
+ */
+
+ private Vector<Label> earlyReturnHandlers;
+
+ public ExitTriggerAdapter(ClassVisitor cv, Rule rule, String targetClass, String targetMethod) {
+ super(cv, rule, targetClass, targetMethod);
+ this.earlyReturnHandlers = new Vector<Label>();
+ }
+
+ public MethodVisitor visitMethod(
+ final int access,
+ final String name,
+ final String desc,
+ final String signature,
+ final String[] exceptions)
+ {
+ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+ if (matchTargetMethod(name, desc)) {
+ return new ExitTriggerMethodAdapter(mv, access, name, desc, signature, exceptions);
+ }
+
+ return mv;
+ }
+
+ /**
+ * a method visitor used to add a rule event trigger call to a method
+ */
+
+ private class ExitTriggerMethodAdapter extends GeneratorAdapter
+ {
+ private int access;
+ private String name;
+ private String descriptor;
+ private String signature;
+ private String[] exceptions;
+ private Vector<Label> startLabels;
+ private Vector<Label> endLabels;
+
+ ExitTriggerMethodAdapter(MethodVisitor mv, int access, String name, String descriptor, String signature, String[] exceptions)
+ {
+ super(mv, access, name, descriptor);
+ this.access = access;
+ this.name = name;
+ this.descriptor = descriptor;
+ this.signature = signature;
+ this.exceptions = exceptions;
+ startLabels = new Vector<Label>();
+ endLabels = new Vector<Label>();
+ }
+
+ /**
+ * Visits a try catch block and records the label of the handler start if the
+ * exception type EarlyReturnException so we can later avoid inserting a rule
+ * trigger.
+ *
+ * @param start beginning of the exception handler's scope (inclusive).
+ * @param end end of the exception handler's scope (exclusive).
+ * @param handler beginning of the exception handler's code.
+ * @param type internal name of the type of exceptions handled by the
+ * handler, or <tt>null</tt> to catch any exceptions (for "finally"
+ * blocks).
+ * @throws IllegalArgumentException if one of the labels has already been
+ * visited by this visitor (by the {@link #visitLabel visitLabel}
+ * method).
+ */
+ public void visitTryCatchBlock(Label start, Label end, Label handler, String type)
+ {
+ // check whether type is one of ours and if so add the labels to the
+ // return table
+
+ if (type.equals("org/jboss/jbossts/orchestration/rule/exception/EarlyReturnException")) {
+ earlyReturnHandlers.add(handler);
+ }
+ super.visitTryCatchBlock(start, end, handler, type);
+ }
+
+ /**
+ * each time we visit a label we set or clear flag inhibit depending upon whether the label
+ * identifies an EarlyReturnException block or not in order to avoid inserting triggers
+ * for returns added by our own exception handling code
+ *
+ * @param label
+ */
+ public void visitLabel(Label label)
+ {
+ if (earlyReturnHandlers.contains(label)) {
+ inhibit = true;
+ } else {
+ inhibit = false;
+ }
+
+ super.visitLabel(label);
+ }
+
+ /**
+ * we need to identify return instructions which are inserted because of other rules
+ *
+ * @param opcode
+ */
+ public void visitInsn(final int opcode) {
+ switch (opcode) {
+ case Opcodes.RETURN: // empty stack
+ case Opcodes.IRETURN: // 1 before n/a after
+ case Opcodes.FRETURN: // 1 before n/a after
+ case Opcodes.ARETURN: // 1 before n/a after
+ case Opcodes.LRETURN: // 2 before n/a after
+ case Opcodes.DRETURN: // 2 before n/a after
+ {
+ if (!inhibit) {
+ // ok to insert a rule trigger as this is not one of our inserted return instructions
+ rule.setTypeInfo(targetClass, access, name, descriptor, exceptions);
+ String key = rule.getKey();
+ Type ruleType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.Rule"));
+ Method method = Method.getMethod("void execute(String, Object, Object[])");
+ // we are at the relevant line in the method -- so add a trigger call here
+ if (Transformer.isVerbose()) {
+ System.out.println("ThrowTriggerMethodAdapter.visitInsn : inserting trigger for " + rule.getName());
+ }
+ Label startLabel = super.newLabel();
+ Label endLabel = super.newLabel();
+ startLabels.add(startLabel);
+ endLabels.add(endLabel);
+ super.visitLabel(startLabel);
+ super.push(key);
+ if ((access & Opcodes.ACC_STATIC) == 0) {
+ super.loadThis();
+ } else {
+ super.push((Type)null);
+ }
+ super.loadArgArray();
+ super.invokeStatic(ruleType, method);
+ super.visitLabel(endLabel);
+ }
+ }
+ break;
+ }
+
+ super.visitInsn(opcode);
+ }
+
+ public void visitEnd()
+ {
+ /*
+ * unfortunately, if we generate the handler code here it comes too late for the stack size
+ * computation to take account of it. the handler code uses 4 stack slots so this causes and
+ * error when the method body uses less than 4. we can patch this by generating the handler
+ * code when visitMaxs is called
+ *
+ Type exceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
+ Type earlyReturnExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
+ Type returnType = Type.getReturnType(descriptor);
+ int count = startLabels.size();
+ int idx;
+ for (idx = 0; idx < count; idx++) {
+ Label startLabel = startLabels.get(idx);
+ Label endLabel = endLabels.get(idx);
+ // add exception handling code subclass first
+ super.catchException(startLabel, endLabel, earlyReturnExceptionType);
+ if (returnType == Type.VOID_TYPE) {
+ // drop exception and just return
+ super.pop();
+ super.visitInsn(Opcodes.RETURN);
+ } else {
+ // fetch value from exception, unbox if needed and return value
+ Method getReturnValueMethod = Method.getMethod("Object getReturnValue()");
+ super.invokeVirtual(earlyReturnExceptionType, getReturnValueMethod);
+ super.unbox(returnType);
+ super.returnValue();
+ }
+ super.catchException(startLabel, endLabel, exceptionType);
+ super.throwException(exceptionType, rule.getName() + " execution exception ");
+ }
+ */
+
+ super.visitEnd();
+ }
+
+ public void visitMaxs(int maxStack, int maxLocals) {
+ /*
+ * this really ought to be in visitEnd but see above for why we do it here
+ */
+ Type exceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
+ Type earlyReturnExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
+ Type throwExceptionType = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ThrowException"));
+ Type throwableType = Type.getType(TypeHelper.externalizeType("java.lang.Throwable"));
+ Type returnType = Type.getReturnType(descriptor);
+ int count = startLabels.size();
+ int idx;
+ for (idx = 0; idx < count; idx++) {
+ Label startLabel = startLabels.get(idx);
+ Label endLabel = endLabels.get(idx);
+ // add exception handling code subclass first
+ super.catchException(startLabel, endLabel, earlyReturnExceptionType);
+ if (returnType == Type.VOID_TYPE) {
+ // drop exception and just return
+ super.pop();
+ super.visitInsn(Opcodes.RETURN);
+ } else {
+ // fetch value from exception, unbox if needed and return value
+ Method getReturnValueMethod = Method.getMethod("Object getReturnValue()");
+ super.invokeVirtual(earlyReturnExceptionType, getReturnValueMethod);
+ super.unbox(returnType);
+ super.returnValue();
+ }
+ super.catchException(startLabel, endLabel, throwExceptionType);
+ // fetch value from exception, unbox if needed and return value
+ Method getThrowableMethod = Method.getMethod("Throwable getThrowable()");
+ super.invokeVirtual(throwExceptionType, getThrowableMethod);
+ super.throwException();
+
+ super.catchException(startLabel, endLabel, exceptionType);
+ super.throwException(exceptionType, rule.getName() + " execution exception ");
+ }
+ // ok now recompute the stack size
+ super.visitMaxs(maxStack, maxLocals);
+ }
+
+ private boolean inhibit;
+ }
+}
More information about the jboss-svn-commits
mailing list