[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