[jboss-svn-commits] JBL Code SVN: r26809 - in labs/jbosstm/workspace/adinn/orchestration: src/org/jboss/jbossts/orchestration/agent/adapter and 9 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Wed Jun 3 06:48:41 EDT 2009
Author: adinn
Date: 2009-06-03 06:48:41 -0400 (Wed, 03 Jun 2009)
New Revision: 26809
Added:
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/OpcodesHelper.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleGeneratorAdapter.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/BBlock.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/CFG.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/CodeLocation.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/InstructionSequence.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/Link.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/TriggerDetails.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/TryCatchDetails.java
Modified:
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/adapter/AccessTriggerAdapter.java
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/InvokeTriggerAdapter.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineTriggerAdapter.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleMethodAdapter.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleTriggerMethodAdapter.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/SynchronizeTriggerAdapter.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ThrowTriggerAdapter.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/RuleElement.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ReturnExpression.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/helper/Helper.java
labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/synchronization/Waiter.java
labs/jbosstm/workspace/adinn/orchestration/tests/build.xml
labs/jbosstm/workspace/adinn/orchestration/tests/dd/scripts/location/TestCall.txt
labs/jbosstm/workspace/adinn/orchestration/tests/dd/scripts/location/TestThrow.txt
labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/auxiliary/TestCallThrowSynchAuxiliary.java
labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/location/TestCall.java
labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/location/TestSynch.java
labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/location/TestThrow.java
Log:
major reworking of trigger injection code to deal with complications when triggers are inserted inside synchronized blocks -- includes revision of test code
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/adapter/AccessTriggerAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/AccessTriggerAdapter.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/AccessTriggerAdapter.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -97,9 +97,6 @@
latched = false;
}
- // somewhere we need to add a catch exception block
- // super.catchException(startLabel, endLabel, new Type("org.jboss.jbossts.orchestration.rule.exception.ExecuteException")));
-
public void visitFieldInsn(
final int opcode,
final String owner,
@@ -122,18 +119,18 @@
if (Transformer.isVerbose()) {
System.out.println("AccessTriggerMethodAdapter.visitFieldInsn : inserting trigger for " + rule.getName());
}
- startLabel = super.newLabel();
- endLabel = super.newLabel();
- super.visitLabel(startLabel);
- super.push(key);
+ startLabel = newLabel();
+ endLabel = newLabel();
+ visitTriggerStart(startLabel);
+ push(key);
if ((access & Opcodes.ACC_STATIC) == 0) {
- super.loadThis();
+ loadThis();
} else {
- super.push((Type)null);
+ push((Type)null);
}
doArgLoad();
- super.invokeStatic(ruleType, method);
- super.visitLabel(endLabel);
+ invokeStatic(ruleType, method);
+ visitTriggerEnd(endLabel);
}
}
if (!whenComplete) {
@@ -142,69 +139,6 @@
}
}
- 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);
- // 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);
- // 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 matchCall(int opcode, String owner, String name, String desc)
{
if (!fieldName.equals(name)) {
Modified: 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 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ExitTriggerAdapter.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -134,20 +134,20 @@
if (Transformer.isVerbose()) {
System.out.println("ExitTriggerMethodAdapter.visitInsn : inserting trigger for " + rule.getName());
}
- Label startLabel = super.newLabel();
- Label endLabel = super.newLabel();
+ Label startLabel = newLabel();
+ Label endLabel = newLabel();
startLabels.add(startLabel);
endLabels.add(endLabel);
- super.visitLabel(startLabel);
- super.push(key);
+ visitTriggerStart(startLabel);
+ push(key);
if ((access & Opcodes.ACC_STATIC) == 0) {
- super.loadThis();
+ loadThis();
} else {
- super.push((Type)null);
+ push((Type)null);
}
doArgLoad();
- super.invokeStatic(ruleType, method);
- super.visitLabel(endLabel);
+ invokeStatic(ruleType, method);
+ visitTriggerEnd(endLabel);
}
}
break;
@@ -156,83 +156,6 @@
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;
}
}
Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/InvokeTriggerAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/InvokeTriggerAdapter.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/InvokeTriggerAdapter.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -122,18 +122,18 @@
if (Transformer.isVerbose()) {
System.out.println("AccessTriggerMethodAdapter.visitMethodInsn : inserting trigger for " + rule.getName());
}
- startLabel = super.newLabel();
- endLabel = super.newLabel();
- super.visitLabel(startLabel);
- super.push(key);
+ startLabel = newLabel();
+ endLabel = newLabel();
+ visitTriggerStart(startLabel);
+ push(key);
if ((access & Opcodes.ACC_STATIC) == 0) {
- super.loadThis();
+ loadThis();
} else {
- super.push((Type)null);
+ push((Type)null);
}
doArgLoad();
- super.invokeStatic(ruleType, method);
- super.visitLabel(endLabel);
+ invokeStatic(ruleType, method);
+ visitTriggerEnd(endLabel);
}
}
if (!whenComplete) {
@@ -142,69 +142,6 @@
}
}
- 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);
- // 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);
- // 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 matchCall(String owner, String name, String desc)
{
if (!calledMethodName.equals(name)) {
Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineTriggerAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineTriggerAdapter.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/LineTriggerAdapter.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -101,86 +101,22 @@
if (Transformer.isVerbose()) {
System.out.println("AccessTriggerMethodAdapter.visitLineNumber : inserting trigger for " + rule.getName());
}
- startLabel = super.newLabel();
- endLabel = super.newLabel();
- super.visitLabel(startLabel);
- super.push(key);
+ startLabel = newLabel();
+ endLabel = newLabel();
+ visitTriggerStart(startLabel);
+ push(key);
if ((access & Opcodes.ACC_STATIC) == 0) {
- super.loadThis();
+ loadThis();
} else {
- super.push((Type)null);
+ push((Type)null);
}
doArgLoad();
- super.invokeStatic(ruleType, method);
- super.visitLabel(endLabel);
+ invokeStatic(ruleType, method);
+ visitTriggerEnd(endLabel);
visitedLine = true;
}
super.visitLineNumber(line, start);
}
-
- 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);
- // 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);
- // 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);
- }
-
}
/**
Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/OpcodesHelper.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/OpcodesHelper.java (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/OpcodesHelper.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -0,0 +1,504 @@
+package org.jboss.jbossts.orchestration.agent.adapter;
+
+import org.objectweb.asm.Opcodes;
+
+public class OpcodesHelper implements Opcodes
+{
+/**
+ * instruction type for visitInsn opcodes
+ */
+ public final static int INSN_NONE = 0;
+/**
+ * instruction type for visitIntInsn opcodes
+ */
+ public final static int INSN_INT = 1;
+/**
+ * instruction type for visitLdcInsn opcodes
+ */
+ public final static int INSN_LDC = 2;
+/**
+ * instruction type for visitVarInsn opcodes
+ */
+ public final static int INSN_VAR = 3;
+/**
+ * instruction type for visitIIncInsn opcodes
+ */
+ public final static int INSN_IINC = 4;
+/**
+ * instruction type for visitJumpInsn opcodes
+ */
+ public final static int INSN_JUMP = 5;
+/**
+ * instruction type for visitTableSwitchInsn opcodes
+ */
+ public final static int INSN_TSWITCH = 6;
+/**
+ * instruction type for visitTableLookupInsn opcodes
+ */
+ public final static int INSN_LOOKUP = 7;
+/**
+ * instruction type for visitFieldInsn opcodes
+ */
+ public final static int INSN_FIELD = 8;
+/**
+ * instruction type for visitMethodInsn opcodes
+ */
+ public final static int INSN_METHOD = 9;
+/**
+ * instruction type for visitInsn opcodes
+ */
+ public final static int INSN_TYPE = 10;
+/**
+ * instruction type for visitMultiANewArrayInsn opcodes
+ */
+ public final static int INSN_MULTIANEWARRAY = 11;
+/**
+ * instruction type for unused opcodes
+ */
+ public final static int INSN_UNUSED = 99;
+
+/**
+ * lookup table to derive instruction type from instruction
+ */
+ private static int[] insnType = new int[256];
+
+/**
+ * lookup table to derive instruction name from instruction
+ */
+ private static String[] insnName = new String[256];
+
+/**
+ * initializer block for insnType and insnName lookup tables
+ */
+
+ static {
+ insnType[Opcodes.NOP] = INSN_NONE;
+ insnType[Opcodes.ACONST_NULL] = INSN_NONE;
+ insnType[Opcodes.ICONST_M1] = INSN_NONE;
+ insnType[Opcodes.ICONST_0] = INSN_NONE;
+ insnType[Opcodes.ICONST_1] = INSN_NONE;
+ insnType[Opcodes.ICONST_2] = INSN_NONE;
+ insnType[Opcodes.ICONST_3] = INSN_NONE;
+ insnType[Opcodes.ICONST_4] = INSN_NONE;
+ insnType[Opcodes.ICONST_5] = INSN_NONE;
+ insnType[Opcodes.LCONST_0] = INSN_NONE;
+ insnType[Opcodes.LCONST_1] = INSN_NONE;
+ insnType[Opcodes.FCONST_0] = INSN_NONE;
+ insnType[Opcodes.FCONST_1] = INSN_NONE;
+ insnType[Opcodes.FCONST_2] = INSN_NONE;
+ insnType[Opcodes.DCONST_0] = INSN_NONE;
+ insnType[Opcodes.DCONST_1] = INSN_NONE;
+ insnType[Opcodes.BIPUSH] = INSN_INT;
+ insnType[Opcodes.SIPUSH] = INSN_INT;
+ for (int i = 0; i < Opcodes.ILOAD - Opcodes.LDC; i++) {
+ insnType[Opcodes.LDC + i] = INSN_LDC;
+ }
+ // insnType[Opcodes.LDC_W] = XXX;
+ // insnType[Opcodes.LDC2_W] = XXX;
+ insnType[Opcodes.ILOAD] = INSN_VAR;
+ insnType[Opcodes.LLOAD] = INSN_VAR;
+ insnType[Opcodes.FLOAD] = INSN_VAR;
+ insnType[Opcodes.DLOAD] = INSN_VAR;
+ for (int i = 0; i < Opcodes.IALOAD - Opcodes.ALOAD; i++) {
+ insnType[Opcodes.ALOAD + i] = INSN_VAR;
+ }
+ // insnType[Opcodes.ILOAD_0] = INSN_VAR;
+ // insnType[Opcodes.ILOAD_1] = INSN_VAR;
+ // insnType[Opcodes.ILOAD_2] = INSN_VAR;
+ // insnType[Opcodes.ILOAD_3] = INSN_VAR;
+ // insnType[Opcodes.LLOAD_0] = INSN_VAR;
+ // insnType[Opcodes.LLOAD_1] = INSN_VAR;
+ // insnType[Opcodes.LLOAD_2] = INSN_VAR;
+ // insnType[Opcodes.LLOAD_3] = INSN_VAR;
+ // insnType[Opcodes.FLOAD_0] = INSN_VAR;
+ // insnType[Opcodes.FLOAD_1] = INSN_VAR;
+ // insnType[Opcodes.FLOAD_2] = INSN_VAR;
+ // insnType[Opcodes.FLOAD_3] = INSN_VAR;
+ // insnType[Opcodes.DLOAD_0] = INSN_VAR;
+ // insnType[Opcodes.DLOAD_1] = INSN_VAR;
+ // insnType[Opcodes.DLOAD_2] = INSN_VAR;
+ // insnType[Opcodes.DLOAD_3] = INSN_VAR;
+ // insnType[Opcodes.ALOAD_0] = INSN_VAR;
+ // insnType[Opcodes.ALOAD_1] = INSN_VAR;
+ // insnType[Opcodes.ALOAD_2] = INSN_VAR;
+ // insnType[Opcodes.ALOAD_3] = INSN_VAR;
+ insnType[Opcodes.IALOAD] = INSN_NONE;
+ insnType[Opcodes.LALOAD] = INSN_NONE;
+ insnType[Opcodes.FALOAD] = INSN_NONE;
+ insnType[Opcodes.DALOAD] = INSN_NONE;
+ insnType[Opcodes.AALOAD] = INSN_NONE;
+ insnType[Opcodes.BALOAD] = INSN_NONE;
+ insnType[Opcodes.CALOAD] = INSN_NONE;
+ insnType[Opcodes.SALOAD] = INSN_NONE;
+ insnType[Opcodes.ISTORE] = INSN_VAR;
+ insnType[Opcodes.LSTORE] = INSN_VAR;
+ insnType[Opcodes.FSTORE] = INSN_VAR;
+ insnType[Opcodes.DSTORE] = INSN_VAR;
+ for (int i = 0; i < Opcodes.IASTORE - Opcodes.ASTORE; i++) {
+ insnType[Opcodes.ASTORE + i] = INSN_VAR;
+ }
+ // insnType[Opcodes.ISTORE_0] = INSN_VAR;
+ // insnType[Opcodes.ISTORE_1] = INSN_VAR;
+ // insnType[Opcodes.ISTORE_2] = INSN_VAR;
+ // insnType[Opcodes.ISTORE_3] = INSN_VAR;
+ // insnType[Opcodes.LSTORE_0] = INSN_VAR;
+ // insnType[Opcodes.LSTORE_1] = INSN_VAR;
+ // insnType[Opcodes.LSTORE_2] = INSN_VAR;
+ // insnType[Opcodes.LSTORE_3] = INSN_VAR;
+ // insnType[Opcodes.FSTORE_0] = INSN_VAR;
+ // insnType[Opcodes.FSTORE_1] = INSN_VAR;
+ // insnType[Opcodes.FSTORE_2] = INSN_VAR;
+ // insnType[Opcodes.FSTORE_3] = INSN_VAR;
+ // insnType[Opcodes.DSTORE_0] = INSN_VAR;
+ // insnType[Opcodes.DSTORE_1] = INSN_VAR;
+ // insnType[Opcodes.DSTORE_2] = INSN_VAR;
+ // insnType[Opcodes.DSTORE_3] = INSN_VAR;
+ // insnType[Opcodes.ASTORE_0] = INSN_VAR;
+ // insnType[Opcodes.ASTORE_1] = INSN_VAR;
+ // insnType[Opcodes.ASTORE_2] = INSN_VAR;
+ // insnType[Opcodes.ASTORE_3] = INSN_VAR;
+ insnType[Opcodes.IASTORE] = INSN_NONE;
+ insnType[Opcodes.LASTORE] = INSN_NONE;
+ insnType[Opcodes.FASTORE] = INSN_NONE;
+ insnType[Opcodes.DASTORE] = INSN_NONE;
+ insnType[Opcodes.AASTORE] = INSN_NONE;
+ insnType[Opcodes.BASTORE] = INSN_NONE;
+ insnType[Opcodes.CASTORE] = INSN_NONE;
+ insnType[Opcodes.SASTORE] = INSN_NONE;
+ insnType[Opcodes.POP] = INSN_NONE;
+ insnType[Opcodes.POP2] = INSN_NONE;
+ insnType[Opcodes.DUP] = INSN_NONE;
+ insnType[Opcodes.DUP_X1] = INSN_NONE;
+ insnType[Opcodes.DUP_X2] = INSN_NONE;
+ insnType[Opcodes.DUP2] = INSN_NONE;
+ insnType[Opcodes.DUP2_X1] = INSN_NONE;
+ insnType[Opcodes.DUP2_X2] = INSN_NONE;
+ insnType[Opcodes.SWAP] = INSN_NONE;
+ insnType[Opcodes.IADD] = INSN_NONE;
+ insnType[Opcodes.LADD] = INSN_NONE;
+ insnType[Opcodes.FADD] = INSN_NONE;
+ insnType[Opcodes.DADD] = INSN_NONE;
+ insnType[Opcodes.ISUB] = INSN_NONE;
+ insnType[Opcodes.LSUB] = INSN_NONE;
+ insnType[Opcodes.FSUB] = INSN_NONE;
+ insnType[Opcodes.DSUB] = INSN_NONE;
+ insnType[Opcodes.IMUL] = INSN_NONE;
+ insnType[Opcodes.LMUL] = INSN_NONE;
+ insnType[Opcodes.FMUL] = INSN_NONE;
+ insnType[Opcodes.DMUL] = INSN_NONE;
+ insnType[Opcodes.IDIV] = INSN_NONE;
+ insnType[Opcodes.LDIV] = INSN_NONE;
+ insnType[Opcodes.FDIV] = INSN_NONE;
+ insnType[Opcodes.DDIV] = INSN_NONE;
+ insnType[Opcodes.IREM] = INSN_NONE;
+ insnType[Opcodes.LREM] = INSN_NONE;
+ insnType[Opcodes.FREM] = INSN_NONE;
+ insnType[Opcodes.DREM] = INSN_NONE;
+ insnType[Opcodes.INEG] = INSN_NONE;
+ insnType[Opcodes.LNEG] = INSN_NONE;
+ insnType[Opcodes.FNEG] = INSN_NONE;
+ insnType[Opcodes.DNEG] = INSN_NONE;
+ insnType[Opcodes.ISHL] = INSN_NONE;
+ insnType[Opcodes.LSHL] = INSN_NONE;
+ insnType[Opcodes.ISHR] = INSN_NONE;
+ insnType[Opcodes.LSHR] = INSN_NONE;
+ insnType[Opcodes.IUSHR] = INSN_NONE;
+ insnType[Opcodes.LUSHR] = INSN_NONE;
+ insnType[Opcodes.IAND] = INSN_NONE;
+ insnType[Opcodes.LAND] = INSN_NONE;
+ insnType[Opcodes.IOR] = INSN_NONE;
+ insnType[Opcodes.LOR] = INSN_NONE;
+ insnType[Opcodes.IXOR] = INSN_NONE;
+ insnType[Opcodes.LXOR] = INSN_NONE;
+ insnType[Opcodes.IINC] = INSN_IINC;
+ insnType[Opcodes.I2L] = INSN_NONE;
+ insnType[Opcodes.I2F] = INSN_NONE;
+ insnType[Opcodes.I2D] = INSN_NONE;
+ insnType[Opcodes.L2I] = INSN_NONE;
+ insnType[Opcodes.L2F] = INSN_NONE;
+ insnType[Opcodes.L2D] = INSN_NONE;
+ insnType[Opcodes.F2I] = INSN_NONE;
+ insnType[Opcodes.F2L] = INSN_NONE;
+ insnType[Opcodes.F2D] = INSN_NONE;
+ insnType[Opcodes.D2I] = INSN_NONE;
+ insnType[Opcodes.D2L] = INSN_NONE;
+ insnType[Opcodes.D2F] = INSN_NONE;
+ insnType[Opcodes.I2B] = INSN_NONE;
+ insnType[Opcodes.I2C] = INSN_NONE;
+ insnType[Opcodes.I2S] = INSN_NONE;
+ insnType[Opcodes.LCMP] = INSN_NONE;
+ insnType[Opcodes.FCMPL] = INSN_NONE;
+ insnType[Opcodes.FCMPG] = INSN_NONE;
+ insnType[Opcodes.DCMPL] = INSN_NONE;
+ insnType[Opcodes.DCMPG] = INSN_NONE;
+ insnType[Opcodes.IFEQ] = INSN_JUMP;
+ insnType[Opcodes.IFNE] = INSN_JUMP;
+ insnType[Opcodes.IFLT] = INSN_JUMP;
+ insnType[Opcodes.IFGE] = INSN_JUMP;
+ insnType[Opcodes.IFGT] = INSN_JUMP;
+ insnType[Opcodes.IFLE] = INSN_JUMP;
+ insnType[Opcodes.IF_ICMPEQ] = INSN_JUMP;
+ insnType[Opcodes.IF_ICMPNE] = INSN_JUMP;
+ insnType[Opcodes.IF_ICMPLT] = INSN_JUMP;
+ insnType[Opcodes.IF_ICMPGE] = INSN_JUMP;
+ insnType[Opcodes.IF_ICMPGT] = INSN_JUMP;
+ insnType[Opcodes.IF_ICMPLE] = INSN_JUMP;
+ insnType[Opcodes.IF_ACMPEQ] = INSN_JUMP;
+ insnType[Opcodes.IF_ACMPNE] = INSN_JUMP;
+ insnType[Opcodes.GOTO] = INSN_JUMP;
+ insnType[Opcodes.JSR] = INSN_JUMP;
+ insnType[Opcodes.RET] = INSN_VAR;
+ insnType[Opcodes.TABLESWITCH] = INSN_TSWITCH;
+ insnType[Opcodes.LOOKUPSWITCH] = INSN_LOOKUP;
+ insnType[Opcodes.IRETURN] = INSN_NONE;
+ insnType[Opcodes.LRETURN] = INSN_NONE;
+ insnType[Opcodes.FRETURN] = INSN_NONE;
+ insnType[Opcodes.DRETURN] = INSN_NONE;
+ insnType[Opcodes.ARETURN] = INSN_NONE;
+ insnType[Opcodes.RETURN] = INSN_NONE;
+ insnType[Opcodes.GETSTATIC] = INSN_FIELD;
+ insnType[Opcodes.PUTSTATIC] = INSN_FIELD;
+ insnType[Opcodes.GETFIELD] = INSN_FIELD;
+ insnType[Opcodes.PUTFIELD] = INSN_FIELD;
+ insnType[Opcodes.INVOKEVIRTUAL] = INSN_METHOD;
+ insnType[Opcodes.INVOKESPECIAL] = INSN_METHOD;
+ insnType[Opcodes.INVOKESTATIC] = INSN_METHOD;
+ insnType[Opcodes.INVOKEINTERFACE] = INSN_METHOD;
+ insnType[Opcodes.INVOKEINTERFACE + 1] = INSN_UNUSED;
+ // insnType[Opcodes.UNUSED] = INSN_UNUSED;
+ insnType[Opcodes.NEW] = INSN_TYPE;
+ insnType[Opcodes.NEWARRAY] = INSN_INT;
+ insnType[Opcodes.ANEWARRAY] = INSN_TYPE;
+ insnType[Opcodes.ARRAYLENGTH] = INSN_NONE;
+ insnType[Opcodes.ATHROW] = INSN_NONE;
+ insnType[Opcodes.CHECKCAST] = INSN_TYPE;
+ insnType[Opcodes.INSTANCEOF] = INSN_TYPE;
+ insnType[Opcodes.MONITORENTER] = INSN_NONE;
+ insnType[Opcodes.MONITOREXIT] = INSN_NONE;
+ insnType[Opcodes.MONITOREXIT + 1] = INSN_UNUSED;
+ // insnType[Opcodes.WIDE] = INSN_UNUSED;
+ insnType[Opcodes.MULTIANEWARRAY] = INSN_MULTIANEWARRAY;
+ insnType[Opcodes.IFNULL] = INSN_JUMP;
+ for (int i = 0; i < 3; i++) {
+ insnType[Opcodes.IFNONNULL + i] = INSN_JUMP;
+ }
+ // insnType[Opcodes.GOTO_W] = INSN_JUMP;
+ // insnType[Opcodes.JSR_W] = INSN_JUMP;
+
+
+ insnName[Opcodes.NOP] = "NOP";
+ insnName[Opcodes.ACONST_NULL] = "aconst_null";
+ insnName[Opcodes.ICONST_M1] = "iconst_m1";
+ insnName[Opcodes.ICONST_0] = "iconst_0";
+ insnName[Opcodes.ICONST_1] = "iconst_1";
+ insnName[Opcodes.ICONST_2] = "iconst_2";
+ insnName[Opcodes.ICONST_3] = "iconst_3";
+ insnName[Opcodes.ICONST_4] = "iconst_4";
+ insnName[Opcodes.ICONST_5] = "iconst_5";
+ insnName[Opcodes.LCONST_0] = "lconst_0";
+ insnName[Opcodes.LCONST_1] = "lconst_1";
+ insnName[Opcodes.FCONST_0] = "fconst_0";
+ insnName[Opcodes.FCONST_1] = "fconst_1";
+ insnName[Opcodes.FCONST_2] = "fconst_2";
+ insnName[Opcodes.DCONST_0] = "dconst_0";
+ insnName[Opcodes.DCONST_1] = "dconst_1";
+ insnName[Opcodes.BIPUSH] = "bipush";
+ insnName[Opcodes.SIPUSH] = "sipush";
+ insnName[Opcodes.LDC] = "ldc";
+ insnName[Opcodes.LDC + 1] = "ldc_w";
+ insnName[Opcodes.LDC + 2] = "ldc2_w";
+ insnName[Opcodes.ILOAD] = "iload";
+ insnName[Opcodes.LLOAD] = "lload";
+ insnName[Opcodes.FLOAD] = "fload";
+ insnName[Opcodes.DLOAD] = "dload";
+ insnName[Opcodes.ALOAD] = "aload";
+ insnName[Opcodes.ALOAD + 1] = "iload_0";
+ insnName[Opcodes.ALOAD + 2] = "iload_1";
+ insnName[Opcodes.ALOAD + 3] = "iload_2";
+ insnName[Opcodes.ALOAD + 4] = "iload_3";
+ insnName[Opcodes.ALOAD + 5] = "lload_0";
+ insnName[Opcodes.ALOAD + 6] = "lload_1";
+ insnName[Opcodes.ALOAD + 7] = "lload_2";
+ insnName[Opcodes.ALOAD + 8] = "lload_3";
+ insnName[Opcodes.ALOAD + 9] = "fload_0";
+ insnName[Opcodes.ALOAD + 10] = "fload_1";
+ insnName[Opcodes.ALOAD + 11] = "fload_2";
+ insnName[Opcodes.ALOAD + 12] = "fload_3";
+ insnName[Opcodes.ALOAD + 13] = "dload_0";
+ insnName[Opcodes.ALOAD + 14] = "dload_1";
+ insnName[Opcodes.ALOAD + 15] = "dload_2";
+ insnName[Opcodes.ALOAD + 16] = "dload_3";
+ insnName[Opcodes.ALOAD + 17] = "aload_0";
+ insnName[Opcodes.ALOAD + 18] = "aload_1";
+ insnName[Opcodes.ALOAD + 19] = "aload_2";
+ insnName[Opcodes.ALOAD + 20] = "aload_3";
+ insnName[Opcodes.IALOAD] = "iaload";
+ insnName[Opcodes.LALOAD] = "laload";
+ insnName[Opcodes.FALOAD] = "faload";
+ insnName[Opcodes.DALOAD] = "daload";
+ insnName[Opcodes.AALOAD] = "aaload";
+ insnName[Opcodes.BALOAD] = "baload";
+ insnName[Opcodes.CALOAD] = "caload";
+ insnName[Opcodes.SALOAD] = "saload";
+ insnName[Opcodes.ISTORE] = "istore";
+ insnName[Opcodes.LSTORE] = "lstore";
+ insnName[Opcodes.FSTORE] = "fstore";
+ insnName[Opcodes.DSTORE] = "dstore";
+ insnName[Opcodes.ASTORE] = "astore";
+ insnName[Opcodes.ASTORE + 1] = "istore_0";
+ insnName[Opcodes.ASTORE + 2] = "istore_1";
+ insnName[Opcodes.ASTORE + 3] = "istore_2";
+ insnName[Opcodes.ASTORE + 4] = "istore_3";
+ insnName[Opcodes.ASTORE + 5] = "lstore_0";
+ insnName[Opcodes.ASTORE + 6] = "lstore_1";
+ insnName[Opcodes.ASTORE + 7] = "lstore_2";
+ insnName[Opcodes.ASTORE + 8] = "lstore_3";
+ insnName[Opcodes.ASTORE + 9] = "fstore_0";
+ insnName[Opcodes.ASTORE + 10] = "fstore_1";
+ insnName[Opcodes.ASTORE + 11] = "fstore_2";
+ insnName[Opcodes.ASTORE + 12] = "fstore_3";
+ insnName[Opcodes.ASTORE + 13] = "dstore_0";
+ insnName[Opcodes.ASTORE + 14] = "dstore_1";
+ insnName[Opcodes.ASTORE + 15] = "dstore_2";
+ insnName[Opcodes.ASTORE + 16] = "dstore_3";
+ insnName[Opcodes.ASTORE + 17] = "astore_0";
+ insnName[Opcodes.ASTORE + 18] = "astore_1";
+ insnName[Opcodes.ASTORE + 19] = "astore_2";
+ insnName[Opcodes.ASTORE + 20] = "astore_3";
+ insnName[Opcodes.IASTORE] = "iastore";
+ insnName[Opcodes.LASTORE] = "lastore";
+ insnName[Opcodes.FASTORE] = "fastore";
+ insnName[Opcodes.DASTORE] = "dastore";
+ insnName[Opcodes.AASTORE] = "aastore";
+ insnName[Opcodes.BASTORE] = "bastore";
+ insnName[Opcodes.CASTORE] = "castore";
+ insnName[Opcodes.SASTORE] = "sastore";
+ insnName[Opcodes.POP] = "pop";
+ insnName[Opcodes.POP2] = "pop2";
+ insnName[Opcodes.DUP] = "dup";
+ insnName[Opcodes.DUP_X1] = "dup_x1";
+ insnName[Opcodes.DUP_X2] = "dup_x2";
+ insnName[Opcodes.DUP2] = "dup2";
+ insnName[Opcodes.DUP2_X1] = "dup2_x1";
+ insnName[Opcodes.DUP2_X2] = "dup2_X2";
+ insnName[Opcodes.SWAP] = "swap";
+ insnName[Opcodes.IADD] = "iadd";
+ insnName[Opcodes.LADD] = "ladd";
+ insnName[Opcodes.FADD] = "fadd";
+ insnName[Opcodes.DADD] = "dadd";
+ insnName[Opcodes.ISUB] = "isub";
+ insnName[Opcodes.LSUB] = "lsub";
+ insnName[Opcodes.FSUB] = "fsub";
+ insnName[Opcodes.DSUB] = "dsub";
+ insnName[Opcodes.IMUL] = "imul";
+ insnName[Opcodes.LMUL] = "lmul";
+ insnName[Opcodes.FMUL] = "fmul";
+ insnName[Opcodes.DMUL] = "dmul";
+ insnName[Opcodes.IDIV] = "idiv";
+ insnName[Opcodes.LDIV] = "ldiv";
+ insnName[Opcodes.FDIV] = "fdiv";
+ insnName[Opcodes.DDIV] = "ddiv";
+ insnName[Opcodes.IREM] = "irem";
+ insnName[Opcodes.LREM] = "lrem";
+ insnName[Opcodes.FREM] = "frem";
+ insnName[Opcodes.DREM] = "drem";
+ insnName[Opcodes.INEG] = "ineg";
+ insnName[Opcodes.LNEG] = "lneg";
+ insnName[Opcodes.FNEG] = "fneg";
+ insnName[Opcodes.DNEG] = "dneg";
+ insnName[Opcodes.ISHL] = "ishl";
+ insnName[Opcodes.LSHL] = "lshl";
+ insnName[Opcodes.ISHR] = "ishr";
+ insnName[Opcodes.LSHR] = "lshr";
+ insnName[Opcodes.IUSHR] = "iushr";
+ insnName[Opcodes.LUSHR] = "lushr";
+ insnName[Opcodes.IAND] = "iand";
+ insnName[Opcodes.LAND] = "land";
+ insnName[Opcodes.IOR] = "ior";
+ insnName[Opcodes.LOR] = "lor";
+ insnName[Opcodes.IXOR] = "ixor";
+ insnName[Opcodes.LXOR] = "lxor";
+ insnName[Opcodes.IINC] = "iinc";
+ insnName[Opcodes.I2L] = "i2l";
+ insnName[Opcodes.I2F] = "i2f";
+ insnName[Opcodes.I2D] = "i2d";
+ insnName[Opcodes.L2I] = "l2i";
+ insnName[Opcodes.L2F] = "l2f";
+ insnName[Opcodes.L2D] = "l2d";
+ insnName[Opcodes.F2I] = "f2i";
+ insnName[Opcodes.F2L] = "f2l";
+ insnName[Opcodes.F2D] = "f2d";
+ insnName[Opcodes.D2I] = "d2i";
+ insnName[Opcodes.D2L] = "d2l";
+ insnName[Opcodes.D2F] = "d2f";
+ insnName[Opcodes.I2B] = "i2b";
+ insnName[Opcodes.I2C] = "i2c";
+ insnName[Opcodes.I2S] = "i2s";
+ insnName[Opcodes.LCMP] = "lcmp";
+ insnName[Opcodes.FCMPL] = "fcmpl";
+ insnName[Opcodes.FCMPG] = "fcmpg";
+ insnName[Opcodes.DCMPL] = "dcmpl";
+ insnName[Opcodes.DCMPG] = "dcmpg";
+ insnName[Opcodes.IFEQ] = "ifeq";
+ insnName[Opcodes.IFNE] = "ifne";
+ insnName[Opcodes.IFLT] = "iflt";
+ insnName[Opcodes.IFGE] = "ifge";
+ insnName[Opcodes.IFGT] = "ifgt";
+ insnName[Opcodes.IFLE] = "ifle";
+ insnName[Opcodes.IF_ICMPEQ] = "if_icmpeq";
+ insnName[Opcodes.IF_ICMPNE] = "if_icmpne";
+ insnName[Opcodes.IF_ICMPLT] = "if_icmplt";
+ insnName[Opcodes.IF_ICMPGE] = "if_icmpge";
+ insnName[Opcodes.IF_ICMPGT] = "if_icmpgt";
+ insnName[Opcodes.IF_ICMPLE] = "if_icmple";
+ insnName[Opcodes.IF_ACMPEQ] = "if_acmpeq";
+ insnName[Opcodes.IF_ACMPNE] = "if_acmpne";
+ insnName[Opcodes.GOTO] = "goto";
+ insnName[Opcodes.JSR] = "jsr";
+ insnName[Opcodes.RET] = "ret";
+ insnName[Opcodes.TABLESWITCH] = "tableswitch";
+ insnName[Opcodes.LOOKUPSWITCH] = "lookupswitch";
+ insnName[Opcodes.IRETURN] = "ireturn";
+ insnName[Opcodes.LRETURN] = "lreturn";
+ insnName[Opcodes.FRETURN] = "freturn";
+ insnName[Opcodes.DRETURN] = "dreturn";
+ insnName[Opcodes.ARETURN] = "areturn";
+ insnName[Opcodes.RETURN] = "return";
+ insnName[Opcodes.GETSTATIC] = "getstatic";
+ insnName[Opcodes.PUTSTATIC] = "putstatic";
+ insnName[Opcodes.GETFIELD] = "getfield";
+ insnName[Opcodes.PUTFIELD] = "putfield";
+ insnName[Opcodes.INVOKEVIRTUAL] = "invokevirtual";
+ insnName[Opcodes.INVOKESPECIAL] = "invokespecial";
+ insnName[Opcodes.INVOKESTATIC] = "invokestatic";
+ insnName[Opcodes.INVOKEINTERFACE] = "invokeinterface";
+ insnName[Opcodes.INVOKEINTERFACE + 1] = "unused";
+ // insnName[Opcodes.UNUSED] = "unused";
+ insnName[Opcodes.NEW] = "new";
+ insnName[Opcodes.NEWARRAY] = "newarray";
+ insnName[Opcodes.ANEWARRAY] = "anewarray";
+ insnName[Opcodes.ARRAYLENGTH] = "arraylength";
+ insnName[Opcodes.ATHROW] = "athrow";
+ insnName[Opcodes.CHECKCAST] = "checkcast";
+ insnName[Opcodes.INSTANCEOF] = "instanceof";
+ insnName[Opcodes.MONITORENTER] = "monitorenter";
+ insnName[Opcodes.MONITOREXIT] = "monitorexit";
+ insnName[Opcodes.MONITOREXIT + 1] = "wide";
+ // insnName[Opcodes.WIDE] = "wide";
+ insnName[Opcodes.MULTIANEWARRAY] = "multianewarray";
+ insnName[Opcodes.IFNULL] = "ifnull";
+ insnName[Opcodes.IFNONNULL] = "ifnonnull";
+ insnName[Opcodes.IFNONNULL + 1] = "goto_w";
+ insnName[Opcodes.IFNONNULL + 2] = "jsr_w";
+ }
+
+ static public int insnType(int opcode)
+ {
+ return insnType[opcode];
+ }
+
+ static public String insnName(int opcode)
+ {
+ return insnName[opcode];
+ }
+}
Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleGeneratorAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleGeneratorAdapter.java (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleGeneratorAdapter.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -0,0 +1,1411 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2005 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.jboss.jbossts.orchestration.agent.adapter;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.LocalVariablesSorter;
+import org.objectweb.asm.commons.Method;
+import org.objectweb.asm.commons.TableSwitchGenerator;
+
+/**
+ * A modified version of the asm GeneratorAdapter class which dispatches calls to methods of
+ * MethodVisitor to this rather than to the encapsulated MethodVisitor instance in field mv.
+ * Doing so gives the current instance a chance to observe all visit operations. Without it
+ * the current instane only sees visit operations invoked directly by previous visitors in
+ * the chain. This is necessary in order for the RuleTriggerAdapter to build a complete CFG
+ * for the method being visited.
+ *
+ * @author Andrew Dinn
+ * @author Juozas Baliuka
+ * @author Chris Nokleberg
+ * @author Eric Bruneton
+ */
+public class RuleGeneratorAdapter extends LocalVariablesSorter {
+
+ private final static Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");
+
+ private final static Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");
+
+ private final static Type SHORT_TYPE = Type.getObjectType("java/lang/Short");
+
+ private final static Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character");
+
+ private final static Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer");
+
+ private final static Type FLOAT_TYPE = Type.getObjectType("java/lang/Float");
+
+ private final static Type LONG_TYPE = Type.getObjectType("java/lang/Long");
+
+ private final static Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double");
+
+ private final static Type NUMBER_TYPE = Type.getObjectType("java/lang/Number");
+
+ private final static Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");
+
+ private final static Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()");
+
+ private final static Method CHAR_VALUE = Method.getMethod("char charValue()");
+
+ private final static Method INT_VALUE = Method.getMethod("int intValue()");
+
+ private final static Method FLOAT_VALUE = Method.getMethod("float floatValue()");
+
+ private final static Method LONG_VALUE = Method.getMethod("long longValue()");
+
+ private final static Method DOUBLE_VALUE = Method.getMethod("double doubleValue()");
+
+ /**
+ * Constant for the {@link #math math} method.
+ */
+ public final static int ADD = Opcodes.IADD;
+
+ /**
+ * Constant for the {@link #math math} method.
+ */
+ public final static int SUB = Opcodes.ISUB;
+
+ /**
+ * Constant for the {@link #math math} method.
+ */
+ public final static int MUL = Opcodes.IMUL;
+
+ /**
+ * Constant for the {@link #math math} method.
+ */
+ public final static int DIV = Opcodes.IDIV;
+
+ /**
+ * Constant for the {@link #math math} method.
+ */
+ public final static int REM = Opcodes.IREM;
+
+ /**
+ * Constant for the {@link #math math} method.
+ */
+ public final static int NEG = Opcodes.INEG;
+
+ /**
+ * Constant for the {@link #math math} method.
+ */
+ public final static int SHL = Opcodes.ISHL;
+
+ /**
+ * Constant for the {@link #math math} method.
+ */
+ public final static int SHR = Opcodes.ISHR;
+
+ /**
+ * Constant for the {@link #math math} method.
+ */
+ public final static int USHR = Opcodes.IUSHR;
+
+ /**
+ * Constant for the {@link #math math} method.
+ */
+ public final static int AND = Opcodes.IAND;
+
+ /**
+ * Constant for the {@link #math math} method.
+ */
+ public final static int OR = Opcodes.IOR;
+
+ /**
+ * Constant for the {@link #math math} method.
+ */
+ public final static int XOR = Opcodes.IXOR;
+
+ /**
+ * Constant for the {@link #ifCmp ifCmp} method.
+ */
+ public final static int EQ = Opcodes.IFEQ;
+
+ /**
+ * Constant for the {@link #ifCmp ifCmp} method.
+ */
+ public final static int NE = Opcodes.IFNE;
+
+ /**
+ * Constant for the {@link #ifCmp ifCmp} method.
+ */
+ public final static int LT = Opcodes.IFLT;
+
+ /**
+ * Constant for the {@link #ifCmp ifCmp} method.
+ */
+ public final static int GE = Opcodes.IFGE;
+
+ /**
+ * Constant for the {@link #ifCmp ifCmp} method.
+ */
+ public final static int GT = Opcodes.IFGT;
+
+ /**
+ * Constant for the {@link #ifCmp ifCmp} method.
+ */
+ public final static int LE = Opcodes.IFLE;
+
+ /**
+ * Access flags of the method visited by this adapter.
+ */
+ private final int access;
+
+ /**
+ * Return type of the method visited by this adapter.
+ */
+ private final Type returnType;
+
+ /**
+ * Argument types of the method visited by this adapter.
+ */
+ private final Type[] argumentTypes;
+
+ /**
+ * Types of the local variables of the method visited by this adapter.
+ */
+ private final List localTypes = new ArrayList();
+
+ /**
+ * Creates a new {@link RuleGeneratorAdapter}.
+ *
+ * @param mv the method visitor to which this adapter delegates calls.
+ * @param access the method's access flags (see {@link org.objectweb.asm.Opcodes}).
+ * @param name the method's name.
+ * @param desc the method's descriptor (see {@link org.objectweb.asm.Type Type}).
+ */
+ public RuleGeneratorAdapter(
+ final MethodVisitor mv,
+ final int access,
+ final String name,
+ final String desc)
+ {
+ super(access, desc, mv);
+ this.access = access;
+ this.returnType = Type.getReturnType(desc);
+ this.argumentTypes = Type.getArgumentTypes(desc);
+ }
+
+ /**
+ * Creates a new {@link RuleGeneratorAdapter}.
+ *
+ * @param access access flags of the adapted method.
+ * @param method the adapted method.
+ * @param mv the method visitor to which this adapter delegates calls.
+ */
+ public RuleGeneratorAdapter(
+ final int access,
+ final Method method,
+ final MethodVisitor mv)
+ {
+ super(access, method.getDescriptor(), mv);
+ this.access = access;
+ this.returnType = method.getReturnType();
+ this.argumentTypes = method.getArgumentTypes();
+ }
+
+ /**
+ * Creates a new {@link RuleGeneratorAdapter}.
+ *
+ * @param access access flags of the adapted method.
+ * @param method the adapted method.
+ * @param signature the signature of the adapted method (may be
+ * <tt>null</tt>).
+ * @param exceptions the exceptions thrown by the adapted method (may be
+ * <tt>null</tt>).
+ * @param cv the class visitor to which this adapter delegates calls.
+ */
+ public RuleGeneratorAdapter(
+ final int access,
+ final Method method,
+ final String signature,
+ final Type[] exceptions,
+ final ClassVisitor cv)
+ {
+ this(access, method, cv.visitMethod(access,
+ method.getName(),
+ method.getDescriptor(),
+ signature,
+ getInternalNames(exceptions)));
+ }
+
+ /**
+ * Returns the internal names of the given types.
+ *
+ * @param types a set of types.
+ * @return the internal names of the given types.
+ */
+ private static String[] getInternalNames(final Type[] types) {
+ if (types == null) {
+ return null;
+ }
+ String[] names = new String[types.length];
+ for (int i = 0; i < names.length; ++i) {
+ names[i] = types[i].getInternalName();
+ }
+ return names;
+ }
+
+ // ------------------------------------------------------------------------
+ // Instructions to push constants on the stack
+ // ------------------------------------------------------------------------
+
+ /**
+ * Generates the instruction to push the given value on the stack.
+ *
+ * @param value the value to be pushed on the stack.
+ */
+ public void push(final boolean value) {
+ push(value ? 1 : 0);
+ }
+
+ /**
+ * Generates the instruction to push the given value on the stack.
+ *
+ * @param value the value to be pushed on the stack.
+ */
+ public void push(final int value) {
+ if (value >= -1 && value <= 5) {
+ visitInsn(Opcodes.ICONST_0 + value);
+ } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
+ visitIntInsn(Opcodes.BIPUSH, value);
+ } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
+ visitIntInsn(Opcodes.SIPUSH, value);
+ } else {
+ visitLdcInsn(new Integer(value));
+ }
+ }
+
+ /**
+ * Generates the instruction to push the given value on the stack.
+ *
+ * @param value the value to be pushed on the stack.
+ */
+ public void push(final long value) {
+ if (value == 0L || value == 1L) {
+ visitInsn(Opcodes.LCONST_0 + (int) value);
+ } else {
+ visitLdcInsn(new Long(value));
+ }
+ }
+
+ /**
+ * Generates the instruction to push the given value on the stack.
+ *
+ * @param value the value to be pushed on the stack.
+ */
+ public void push(final float value) {
+ int bits = Float.floatToIntBits(value);
+ if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
+ visitInsn(Opcodes.FCONST_0 + (int) value);
+ } else {
+ visitLdcInsn(new Float(value));
+ }
+ }
+
+ /**
+ * Generates the instruction to push the given value on the stack.
+ *
+ * @param value the value to be pushed on the stack.
+ */
+ public void push(final double value) {
+ long bits = Double.doubleToLongBits(value);
+ if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
+ visitInsn(Opcodes.DCONST_0 + (int) value);
+ } else {
+ visitLdcInsn(new Double(value));
+ }
+ }
+
+ /**
+ * Generates the instruction to push the given value on the stack.
+ *
+ * @param value the value to be pushed on the stack. May be <tt>null</tt>.
+ */
+ public void push(final String value) {
+ if (value == null) {
+ visitInsn(Opcodes.ACONST_NULL);
+ } else {
+ visitLdcInsn(value);
+ }
+ }
+
+ /**
+ * Generates the instruction to push the given value on the stack.
+ *
+ * @param value the value to be pushed on the stack.
+ */
+ public void push(final Type value) {
+ if (value == null) {
+ visitInsn(Opcodes.ACONST_NULL);
+ } else {
+ visitLdcInsn(value);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Instructions to load and store method arguments
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the index of the given method argument in the frame's local
+ * variables array.
+ *
+ * @param arg the index of a method argument.
+ * @return the index of the given method argument in the frame's local
+ * variables array.
+ */
+ private int getArgIndex(final int arg) {
+ int index = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
+ for (int i = 0; i < arg; i++) {
+ index += argumentTypes[i].getSize();
+ }
+ return index;
+ }
+
+ /**
+ * Generates the instruction to push a local variable on the stack.
+ *
+ * @param type the type of the local variable to be loaded.
+ * @param index an index in the frame's local variables array.
+ */
+ private void loadInsn(final Type type, final int index) {
+ visitVarInsn(type.getOpcode(Opcodes.ILOAD), index);
+ }
+
+ /**
+ * Generates the instruction to store the top stack value in a local
+ * variable.
+ *
+ * @param type the type of the local variable to be stored.
+ * @param index an index in the frame's local variables array.
+ */
+ private void storeInsn(final Type type, final int index) {
+ visitVarInsn(type.getOpcode(Opcodes.ISTORE), index);
+ }
+
+ /**
+ * Generates the instruction to load 'this' on the stack.
+ */
+ public void loadThis() {
+ if ((access & Opcodes.ACC_STATIC) != 0) {
+ throw new IllegalStateException("no 'this' pointer within static method");
+ }
+ visitVarInsn(Opcodes.ALOAD, 0);
+ }
+
+ /**
+ * Generates the instruction to load the given method argument on the stack.
+ *
+ * @param arg the index of a method argument.
+ */
+ public void loadArg(final int arg) {
+ loadInsn(argumentTypes[arg], getArgIndex(arg));
+ }
+
+ /**
+ * Generates the instructions to load the given method arguments on the
+ * stack.
+ *
+ * @param arg the index of the first method argument to be loaded.
+ * @param count the number of method arguments to be loaded.
+ */
+ public void loadArgs(final int arg, final int count) {
+ int index = getArgIndex(arg);
+ for (int i = 0; i < count; ++i) {
+ Type t = argumentTypes[arg + i];
+ loadInsn(t, index);
+ index += t.getSize();
+ }
+ }
+
+ /**
+ * Generates the instructions to load all the method arguments on the stack.
+ */
+ public void loadArgs() {
+ loadArgs(0, argumentTypes.length);
+ }
+
+ /**
+ * Generates the instructions to load all the method arguments on the stack,
+ * as a single object array.
+ */
+ public void loadArgArray() {
+ push(argumentTypes.length);
+ newArray(OBJECT_TYPE);
+ for (int i = 0; i < argumentTypes.length; i++) {
+ dup();
+ push(i);
+ loadArg(i);
+ box(argumentTypes[i]);
+ arrayStore(OBJECT_TYPE);
+ }
+ }
+
+ /**
+ * Generates the instruction to store the top stack value in the given
+ * method argument.
+ *
+ * @param arg the index of a method argument.
+ */
+ public void storeArg(final int arg) {
+ storeInsn(argumentTypes[arg], getArgIndex(arg));
+ }
+
+ // ------------------------------------------------------------------------
+ // Instructions to load and store local variables
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the type of the given local variable.
+ *
+ * @param local a local variable identifier, as returned by
+ * {@link org.objectweb.asm.commons.LocalVariablesSorter#newLocal(org.objectweb.asm.Type) newLocal()}.
+ * @return the type of the given local variable.
+ */
+ public Type getLocalType(final int local) {
+ return (Type) localTypes.get(local - firstLocal);
+ }
+
+ protected void setLocalType(final int local, final Type type) {
+ int index = local - firstLocal;
+ while (localTypes.size() < index + 1) {
+ localTypes.add(null);
+ }
+ localTypes.set(index, type);
+ }
+
+ /**
+ * Generates the instruction to load the given local variable on the stack.
+ *
+ * @param local a local variable identifier, as returned by
+ * {@link org.objectweb.asm.commons.LocalVariablesSorter#newLocal(org.objectweb.asm.Type) newLocal()}.
+ */
+ public void loadLocal(final int local) {
+ loadInsn(getLocalType(local), local);
+ }
+
+ /**
+ * Generates the instruction to load the given local variable on the stack.
+ *
+ * @param local a local variable identifier, as returned by
+ * {@link org.objectweb.asm.commons.LocalVariablesSorter#newLocal(org.objectweb.asm.Type) newLocal()}.
+ * @param type the type of this local variable.
+ */
+ public void loadLocal(final int local, final Type type) {
+ setLocalType(local, type);
+ loadInsn(type, local);
+ }
+
+ /**
+ * Generates the instruction to store the top stack value in the given local
+ * variable.
+ *
+ * @param local a local variable identifier, as returned by
+ * {@link org.objectweb.asm.commons.LocalVariablesSorter#newLocal(org.objectweb.asm.Type) newLocal()}.
+ */
+ public void storeLocal(final int local) {
+ storeInsn(getLocalType(local), local);
+ }
+
+ /**
+ * Generates the instruction to store the top stack value in the given local
+ * variable.
+ *
+ * @param local a local variable identifier, as returned by
+ * {@link org.objectweb.asm.commons.LocalVariablesSorter#newLocal(org.objectweb.asm.Type) newLocal()}.
+ * @param type the type of this local variable.
+ */
+ public void storeLocal(final int local, final Type type) {
+ setLocalType(local, type);
+ storeInsn(type, local);
+ }
+
+ /**
+ * Generates the instruction to load an element from an array.
+ *
+ * @param type the type of the array element to be loaded.
+ */
+ public void arrayLoad(final Type type) {
+ visitInsn(type.getOpcode(Opcodes.IALOAD));
+ }
+
+ /**
+ * Generates the instruction to store an element in an array.
+ *
+ * @param type the type of the array element to be stored.
+ */
+ public void arrayStore(final Type type) {
+ visitInsn(type.getOpcode(Opcodes.IASTORE));
+ }
+
+ // ------------------------------------------------------------------------
+ // Instructions to manage the stack
+ // ------------------------------------------------------------------------
+
+ /**
+ * Generates a POP instruction.
+ */
+ public void pop() {
+ visitInsn(Opcodes.POP);
+ }
+
+ /**
+ * Generates a POP2 instruction.
+ */
+ public void pop2() {
+ visitInsn(Opcodes.POP2);
+ }
+
+ /**
+ * Generates a DUP instruction.
+ */
+ public void dup() {
+ visitInsn(Opcodes.DUP);
+ }
+
+ /**
+ * Generates a DUP2 instruction.
+ */
+ public void dup2() {
+ visitInsn(Opcodes.DUP2);
+ }
+
+ /**
+ * Generates a DUP_X1 instruction.
+ */
+ public void dupX1() {
+ visitInsn(Opcodes.DUP_X1);
+ }
+
+ /**
+ * Generates a DUP_X2 instruction.
+ */
+ public void dupX2() {
+ visitInsn(Opcodes.DUP_X2);
+ }
+
+ /**
+ * Generates a DUP2_X1 instruction.
+ */
+ public void dup2X1() {
+ visitInsn(Opcodes.DUP2_X1);
+ }
+
+ /**
+ * Generates a DUP2_X2 instruction.
+ */
+ public void dup2X2() {
+ visitInsn(Opcodes.DUP2_X2);
+ }
+
+ /**
+ * Generates a SWAP instruction.
+ */
+ public void swap() {
+ visitInsn(Opcodes.SWAP);
+ }
+
+ /**
+ * Generates the instructions to swap the top two stack values.
+ *
+ * @param prev type of the top - 1 stack value.
+ * @param type type of the top stack value.
+ */
+ public void swap(final Type prev, final Type type) {
+ if (type.getSize() == 1) {
+ if (prev.getSize() == 1) {
+ swap(); // same as dupX1(), pop();
+ } else {
+ dupX2();
+ pop();
+ }
+ } else {
+ if (prev.getSize() == 1) {
+ dup2X1();
+ pop2();
+ } else {
+ dup2X2();
+ pop2();
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Instructions to do mathematical and logical operations
+ // ------------------------------------------------------------------------
+
+ /**
+ * Generates the instruction to do the specified mathematical or logical
+ * operation.
+ *
+ * @param op a mathematical or logical operation. Must be one of ADD, SUB,
+ * MUL, DIV, REM, NEG, SHL, SHR, USHR, AND, OR, XOR.
+ * @param type the type of the operand(s) for this operation.
+ */
+ public void math(final int op, final Type type) {
+ visitInsn(type.getOpcode(op));
+ }
+
+ /**
+ * Generates the instructions to compute the bitwise negation of the top
+ * stack value.
+ */
+ public void not() {
+ visitInsn(Opcodes.ICONST_1);
+ visitInsn(Opcodes.IXOR);
+ }
+
+ /**
+ * Generates the instruction to increment the given local variable.
+ *
+ * @param local the local variable to be incremented.
+ * @param amount the amount by which the local variable must be incremented.
+ */
+ public void iinc(final int local, final int amount) {
+ visitIincInsn(local, amount);
+ }
+
+ /**
+ * Generates the instructions to cast a numerical value from one type to
+ * another.
+ *
+ * @param from the type of the top stack value
+ * @param to the type into which this value must be cast.
+ */
+ public void cast(final Type from, final Type to) {
+ if (from != to) {
+ if (from == Type.DOUBLE_TYPE) {
+ if (to == Type.FLOAT_TYPE) {
+ visitInsn(Opcodes.D2F);
+ } else if (to == Type.LONG_TYPE) {
+ visitInsn(Opcodes.D2L);
+ } else {
+ visitInsn(Opcodes.D2I);
+ cast(Type.INT_TYPE, to);
+ }
+ } else if (from == Type.FLOAT_TYPE) {
+ if (to == Type.DOUBLE_TYPE) {
+ visitInsn(Opcodes.F2D);
+ } else if (to == Type.LONG_TYPE) {
+ visitInsn(Opcodes.F2L);
+ } else {
+ visitInsn(Opcodes.F2I);
+ cast(Type.INT_TYPE, to);
+ }
+ } else if (from == Type.LONG_TYPE) {
+ if (to == Type.DOUBLE_TYPE) {
+ visitInsn(Opcodes.L2D);
+ } else if (to == Type.FLOAT_TYPE) {
+ visitInsn(Opcodes.L2F);
+ } else {
+ visitInsn(Opcodes.L2I);
+ cast(Type.INT_TYPE, to);
+ }
+ } else {
+ if (to == Type.BYTE_TYPE) {
+ visitInsn(Opcodes.I2B);
+ } else if (to == Type.CHAR_TYPE) {
+ visitInsn(Opcodes.I2C);
+ } else if (to == Type.DOUBLE_TYPE) {
+ visitInsn(Opcodes.I2D);
+ } else if (to == Type.FLOAT_TYPE) {
+ visitInsn(Opcodes.I2F);
+ } else if (to == Type.LONG_TYPE) {
+ visitInsn(Opcodes.I2L);
+ } else if (to == Type.SHORT_TYPE) {
+ visitInsn(Opcodes.I2S);
+ }
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Instructions to do boxing and unboxing operations
+ // ------------------------------------------------------------------------
+
+ /**
+ * Generates the instructions to box the top stack value. This value is
+ * replaced by its boxed equivalent on top of the stack.
+ *
+ * @param type the type of the top stack value.
+ */
+ public void box(final Type type) {
+ if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
+ return;
+ }
+ if (type == Type.VOID_TYPE) {
+ push((String) null);
+ } else {
+ Type boxed = type;
+ switch (type.getSort()) {
+ case Type.BYTE:
+ boxed = BYTE_TYPE;
+ break;
+ case Type.BOOLEAN:
+ boxed = BOOLEAN_TYPE;
+ break;
+ case Type.SHORT:
+ boxed = SHORT_TYPE;
+ break;
+ case Type.CHAR:
+ boxed = CHARACTER_TYPE;
+ break;
+ case Type.INT:
+ boxed = INTEGER_TYPE;
+ break;
+ case Type.FLOAT:
+ boxed = FLOAT_TYPE;
+ break;
+ case Type.LONG:
+ boxed = LONG_TYPE;
+ break;
+ case Type.DOUBLE:
+ boxed = DOUBLE_TYPE;
+ break;
+ }
+ newInstance(boxed);
+ if (type.getSize() == 2) {
+ // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
+ dupX2();
+ dupX2();
+ pop();
+ } else {
+ // p -> po -> opo -> oop -> o
+ dupX1();
+ swap();
+ }
+ invokeConstructor(boxed, new Method("<init>",
+ Type.VOID_TYPE,
+ new Type[] { type }));
+ }
+ }
+
+ /**
+ * Generates the instructions to unbox the top stack value. This value is
+ * replaced by its unboxed equivalent on top of the stack.
+ *
+ * @param type the type of the top stack value.
+ */
+ public void unbox(final Type type) {
+ Type t = NUMBER_TYPE;
+ Method sig = null;
+ switch (type.getSort()) {
+ case Type.VOID:
+ return;
+ case Type.CHAR:
+ t = CHARACTER_TYPE;
+ sig = CHAR_VALUE;
+ break;
+ case Type.BOOLEAN:
+ t = BOOLEAN_TYPE;
+ sig = BOOLEAN_VALUE;
+ break;
+ case Type.DOUBLE:
+ sig = DOUBLE_VALUE;
+ break;
+ case Type.FLOAT:
+ sig = FLOAT_VALUE;
+ break;
+ case Type.LONG:
+ sig = LONG_VALUE;
+ break;
+ case Type.INT:
+ case Type.SHORT:
+ case Type.BYTE:
+ sig = INT_VALUE;
+ }
+ if (sig == null) {
+ checkCast(type);
+ } else {
+ checkCast(t);
+ invokeVirtual(t, sig);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Instructions to jump to other instructions
+ // ------------------------------------------------------------------------
+
+ /**
+ * Creates a new {@link org.objectweb.asm.Label}.
+ *
+ * @return a new {@link org.objectweb.asm.Label}.
+ */
+ public Label newLabel() {
+ return new Label();
+ }
+
+ /**
+ * Marks the current code position with the given label.
+ *
+ * @param label a label.
+ */
+ public void mark(final Label label) {
+ visitLabel(label);
+ }
+
+ /**
+ * Marks the current code position with a new label.
+ *
+ * @return the label that was created to mark the current code position.
+ */
+ public Label mark() {
+ Label label = new Label();
+ visitLabel(label);
+ return label;
+ }
+
+ /**
+ * Generates the instructions to jump to a label based on the comparison of
+ * the top two stack values.
+ *
+ * @param type the type of the top two stack values.
+ * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
+ * LE.
+ * @param label where to jump if the comparison result is <tt>true</tt>.
+ */
+ public void ifCmp(final Type type, final int mode, final Label label) {
+ int intOp = -1;
+ switch (type.getSort()) {
+ case Type.LONG:
+ visitInsn(Opcodes.LCMP);
+ break;
+ case Type.DOUBLE:
+ visitInsn(Opcodes.DCMPG);
+ break;
+ case Type.FLOAT:
+ visitInsn(Opcodes.FCMPG);
+ break;
+ case Type.ARRAY:
+ case Type.OBJECT:
+ switch (mode) {
+ case EQ:
+ visitJumpInsn(Opcodes.IF_ACMPEQ, label);
+ return;
+ case NE:
+ visitJumpInsn(Opcodes.IF_ACMPNE, label);
+ return;
+ }
+ throw new IllegalArgumentException("Bad comparison for type "
+ + type);
+ default:
+ switch (mode) {
+ case EQ:
+ intOp = Opcodes.IF_ICMPEQ;
+ break;
+ case NE:
+ intOp = Opcodes.IF_ICMPNE;
+ break;
+ case GE:
+ intOp = Opcodes.IF_ICMPGE;
+ break;
+ case LT:
+ intOp = Opcodes.IF_ICMPLT;
+ break;
+ case LE:
+ intOp = Opcodes.IF_ICMPLE;
+ break;
+ case GT:
+ intOp = Opcodes.IF_ICMPGT;
+ break;
+ }
+ visitJumpInsn(intOp, label);
+ return;
+ }
+ int jumpMode = mode;
+ switch (mode) {
+ case GE:
+ jumpMode = LT;
+ break;
+ case LE:
+ jumpMode = GT;
+ break;
+ }
+ visitJumpInsn(jumpMode, label);
+ }
+
+ /**
+ * Generates the instructions to jump to a label based on the comparison of
+ * the top two integer stack values.
+ *
+ * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
+ * LE.
+ * @param label where to jump if the comparison result is <tt>true</tt>.
+ */
+ public void ifICmp(final int mode, final Label label) {
+ ifCmp(Type.INT_TYPE, mode, label);
+ }
+
+ /**
+ * Generates the instructions to jump to a label based on the comparison of
+ * the top integer stack value with zero.
+ *
+ * @param mode how these values must be compared. One of EQ, NE, LT, GE, GT,
+ * LE.
+ * @param label where to jump if the comparison result is <tt>true</tt>.
+ */
+ public void ifZCmp(final int mode, final Label label) {
+ visitJumpInsn(mode, label);
+ }
+
+ /**
+ * Generates the instruction to jump to the given label if the top stack
+ * value is null.
+ *
+ * @param label where to jump if the condition is <tt>true</tt>.
+ */
+ public void ifNull(final Label label) {
+ visitJumpInsn(Opcodes.IFNULL, label);
+ }
+
+ /**
+ * Generates the instruction to jump to the given label if the top stack
+ * value is not null.
+ *
+ * @param label where to jump if the condition is <tt>true</tt>.
+ */
+ public void ifNonNull(final Label label) {
+ visitJumpInsn(Opcodes.IFNONNULL, label);
+ }
+
+ /**
+ * Generates the instruction to jump to the given label.
+ *
+ * @param label where to jump if the condition is <tt>true</tt>.
+ */
+ public void goTo(final Label label) {
+ visitJumpInsn(Opcodes.GOTO, label);
+ }
+
+ /**
+ * Generates a RET instruction.
+ *
+ * @param local a local variable identifier, as returned by
+ * {@link org.objectweb.asm.commons.LocalVariablesSorter#newLocal(org.objectweb.asm.Type) newLocal()}.
+ */
+ public void ret(final int local) {
+ visitVarInsn(Opcodes.RET, local);
+ }
+
+ /**
+ * Generates the instructions for a switch statement.
+ *
+ * @param keys the switch case keys.
+ * @param generator a generator to generate the code for the switch cases.
+ */
+ public void tableSwitch(
+ final int[] keys,
+ final TableSwitchGenerator generator)
+ {
+ float density;
+ if (keys.length == 0) {
+ density = 0;
+ } else {
+ density = (float) keys.length
+ / (keys[keys.length - 1] - keys[0] + 1);
+ }
+ tableSwitch(keys, generator, density >= 0.5f);
+ }
+
+ /**
+ * Generates the instructions for a switch statement.
+ *
+ * @param keys the switch case keys.
+ * @param generator a generator to generate the code for the switch cases.
+ * @param useTable <tt>true</tt> to use a TABLESWITCH instruction, or
+ * <tt>false</tt> to use a LOOKUPSWITCH instruction.
+ */
+ public void tableSwitch(
+ final int[] keys,
+ final TableSwitchGenerator generator,
+ final boolean useTable)
+ {
+ for (int i = 1; i < keys.length; ++i) {
+ if (keys[i] < keys[i - 1]) {
+ throw new IllegalArgumentException("keys must be sorted ascending");
+ }
+ }
+ Label def = newLabel();
+ Label end = newLabel();
+ if (keys.length > 0) {
+ int len = keys.length;
+ int min = keys[0];
+ int max = keys[len - 1];
+ int range = max - min + 1;
+ if (useTable) {
+ Label[] labels = new Label[range];
+ Arrays.fill(labels, def);
+ for (int i = 0; i < len; ++i) {
+ labels[keys[i] - min] = newLabel();
+ }
+ visitTableSwitchInsn(min, max, def, labels);
+ for (int i = 0; i < range; ++i) {
+ Label label = labels[i];
+ if (label != def) {
+ mark(label);
+ generator.generateCase(i + min, end);
+ }
+ }
+ } else {
+ Label[] labels = new Label[len];
+ for (int i = 0; i < len; ++i) {
+ labels[i] = newLabel();
+ }
+ visitLookupSwitchInsn(def, keys, labels);
+ for (int i = 0; i < len; ++i) {
+ mark(labels[i]);
+ generator.generateCase(keys[i], end);
+ }
+ }
+ }
+ mark(def);
+ generator.generateDefault();
+ mark(end);
+ }
+
+ /**
+ * Generates the instruction to return the top stack value to the caller.
+ */
+ public void returnValue() {
+ visitInsn(returnType.getOpcode(Opcodes.IRETURN));
+ }
+
+ // ------------------------------------------------------------------------
+ // Instructions to load and store fields
+ // ------------------------------------------------------------------------
+
+ /**
+ * Generates a get field or set field instruction.
+ *
+ * @param opcode the instruction's opcode.
+ * @param ownerType the class in which the field is defined.
+ * @param name the name of the field.
+ * @param fieldType the type of the field.
+ */
+ private void fieldInsn(
+ final int opcode,
+ final Type ownerType,
+ final String name,
+ final Type fieldType)
+ {
+ visitFieldInsn(opcode,
+ ownerType.getInternalName(),
+ name,
+ fieldType.getDescriptor());
+ }
+
+ /**
+ * Generates the instruction to push the value of a static field on the
+ * stack.
+ *
+ * @param owner the class in which the field is defined.
+ * @param name the name of the field.
+ * @param type the type of the field.
+ */
+ public void getStatic(final Type owner, final String name, final Type type)
+ {
+ fieldInsn(Opcodes.GETSTATIC, owner, name, type);
+ }
+
+ /**
+ * Generates the instruction to store the top stack value in a static field.
+ *
+ * @param owner the class in which the field is defined.
+ * @param name the name of the field.
+ * @param type the type of the field.
+ */
+ public void putStatic(final Type owner, final String name, final Type type)
+ {
+ fieldInsn(Opcodes.PUTSTATIC, owner, name, type);
+ }
+
+ /**
+ * Generates the instruction to push the value of a non static field on the
+ * stack.
+ *
+ * @param owner the class in which the field is defined.
+ * @param name the name of the field.
+ * @param type the type of the field.
+ */
+ public void getField(final Type owner, final String name, final Type type) {
+ fieldInsn(Opcodes.GETFIELD, owner, name, type);
+ }
+
+ /**
+ * Generates the instruction to store the top stack value in a non static
+ * field.
+ *
+ * @param owner the class in which the field is defined.
+ * @param name the name of the field.
+ * @param type the type of the field.
+ */
+ public void putField(final Type owner, final String name, final Type type) {
+ fieldInsn(Opcodes.PUTFIELD, owner, name, type);
+ }
+
+ // ------------------------------------------------------------------------
+ // Instructions to invoke methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Generates an invoke method instruction.
+ *
+ * @param opcode the instruction's opcode.
+ * @param type the class in which the method is defined.
+ * @param method the method to be invoked.
+ */
+ private void invokeInsn(
+ final int opcode,
+ final Type type,
+ final Method method)
+ {
+ String owner = type.getSort() == Type.ARRAY
+ ? type.getDescriptor()
+ : type.getInternalName();
+ visitMethodInsn(opcode,
+ owner,
+ method.getName(),
+ method.getDescriptor());
+ }
+
+ /**
+ * Generates the instruction to invoke a normal method.
+ *
+ * @param owner the class in which the method is defined.
+ * @param method the method to be invoked.
+ */
+ public void invokeVirtual(final Type owner, final Method method) {
+ invokeInsn(Opcodes.INVOKEVIRTUAL, owner, method);
+ }
+
+ /**
+ * Generates the instruction to invoke a constructor.
+ *
+ * @param type the class in which the constructor is defined.
+ * @param method the constructor to be invoked.
+ */
+ public void invokeConstructor(final Type type, final Method method) {
+ invokeInsn(Opcodes.INVOKESPECIAL, type, method);
+ }
+
+ /**
+ * Generates the instruction to invoke a static method.
+ *
+ * @param owner the class in which the method is defined.
+ * @param method the method to be invoked.
+ */
+ public void invokeStatic(final Type owner, final Method method) {
+ invokeInsn(Opcodes.INVOKESTATIC, owner, method);
+ }
+
+ /**
+ * Generates the instruction to invoke an interface method.
+ *
+ * @param owner the class in which the method is defined.
+ * @param method the method to be invoked.
+ */
+ public void invokeInterface(final Type owner, final Method method) {
+ invokeInsn(Opcodes.INVOKEINTERFACE, owner, method);
+ }
+
+ // ------------------------------------------------------------------------
+ // Instructions to create objects and arrays
+ // ------------------------------------------------------------------------
+
+ /**
+ * Generates a type dependent instruction.
+ *
+ * @param opcode the instruction's opcode.
+ * @param type the instruction's operand.
+ */
+ private void typeInsn(final int opcode, final Type type) {
+ String desc;
+ if (type.getSort() == Type.ARRAY) {
+ desc = type.getDescriptor();
+ } else {
+ desc = type.getInternalName();
+ }
+ visitTypeInsn(opcode, desc);
+ }
+
+ /**
+ * Generates the instruction to create a new object.
+ *
+ * @param type the class of the object to be created.
+ */
+ public void newInstance(final Type type) {
+ typeInsn(Opcodes.NEW, type);
+ }
+
+ /**
+ * Generates the instruction to create a new array.
+ *
+ * @param type the type of the array elements.
+ */
+ public void newArray(final Type type) {
+ int typ;
+ switch (type.getSort()) {
+ case Type.BOOLEAN:
+ typ = Opcodes.T_BOOLEAN;
+ break;
+ case Type.CHAR:
+ typ = Opcodes.T_CHAR;
+ break;
+ case Type.BYTE:
+ typ = Opcodes.T_BYTE;
+ break;
+ case Type.SHORT:
+ typ = Opcodes.T_SHORT;
+ break;
+ case Type.INT:
+ typ = Opcodes.T_INT;
+ break;
+ case Type.FLOAT:
+ typ = Opcodes.T_FLOAT;
+ break;
+ case Type.LONG:
+ typ = Opcodes.T_LONG;
+ break;
+ case Type.DOUBLE:
+ typ = Opcodes.T_DOUBLE;
+ break;
+ default:
+ typeInsn(Opcodes.ANEWARRAY, type);
+ return;
+ }
+ visitIntInsn(Opcodes.NEWARRAY, typ);
+ }
+
+ // ------------------------------------------------------------------------
+ // Miscelaneous instructions
+ // ------------------------------------------------------------------------
+
+ /**
+ * Generates the instruction to compute the length of an array.
+ */
+ public void arrayLength() {
+ visitInsn(Opcodes.ARRAYLENGTH);
+ }
+
+ /**
+ * Generates the instruction to throw an exception.
+ */
+ public void throwException() {
+ visitInsn(Opcodes.ATHROW);
+ }
+
+ /**
+ * Generates the instructions to create and throw an exception. The
+ * exception class must have a constructor with a single String argument.
+ *
+ * @param type the class of the exception to be thrown.
+ * @param msg the detailed message of the exception.
+ */
+ public void throwException(final Type type, final String msg) {
+ newInstance(type);
+ dup();
+ push(msg);
+ invokeConstructor(type, Method.getMethod("void <init> (String)"));
+ throwException();
+ }
+
+ /**
+ * Generates the instruction to check that the top stack value is of the
+ * given type.
+ *
+ * @param type a class or interface type.
+ */
+ public void checkCast(final Type type) {
+ if (!type.equals(OBJECT_TYPE)) {
+ typeInsn(Opcodes.CHECKCAST, type);
+ }
+ }
+
+ /**
+ * Generates the instruction to test if the top stack value is of the given
+ * type.
+ *
+ * @param type a class or interface type.
+ */
+ public void instanceOf(final Type type) {
+ typeInsn(Opcodes.INSTANCEOF, type);
+ }
+
+ /**
+ * Generates the instruction to get the monitor of the top stack value.
+ */
+ public void monitorEnter() {
+ visitInsn(Opcodes.MONITORENTER);
+ }
+
+ /**
+ * Generates the instruction to release the monitor of the top stack value.
+ */
+ public void monitorExit() {
+ visitInsn(Opcodes.MONITOREXIT);
+ }
+
+ // ------------------------------------------------------------------------
+ // Non instructions
+ // ------------------------------------------------------------------------
+
+ /**
+ * Marks the end of the visited method.
+ */
+ public void endMethod() {
+ if ((access & Opcodes.ACC_ABSTRACT) == 0) {
+ visitMaxs(0, 0);
+ }
+ visitEnd();
+ }
+
+ /**
+ * Marks the start of an exception handler.
+ *
+ * @param start beginning of the exception handler's scope (inclusive).
+ * @param end end of the exception handler's scope (exclusive).
+ * @param exception internal name of the type of exceptions handled by the
+ * handler.
+ */
+ public void catchException(
+ final Label start,
+ final Label end,
+ final Type exception)
+ {
+ visitTryCatchBlock(start, end, mark(), exception.getInternalName());
+ }
+}
\ No newline at end of file
Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleMethodAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleMethodAdapter.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleMethodAdapter.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -1,6 +1,7 @@
package org.jboss.jbossts.orchestration.agent.adapter;
import org.objectweb.asm.commons.GeneratorAdapter;
+import org.objectweb.asm.commons.LocalVariablesSorter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Label;
import org.jboss.jbossts.orchestration.rule.Rule;
@@ -14,7 +15,8 @@
* local variables
*/
-public class RuleMethodAdapter extends GeneratorAdapter {
+// public class RuleMethodAdapter extends GeneratorAdapter {
+public class RuleMethodAdapter extends RuleGeneratorAdapter {
public RuleMethodAdapter(final MethodVisitor mv, final Rule rule, final int access, final String name, final String desc) {
super(mv, access, name, desc);
this.name = name;
Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleTriggerMethodAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleTriggerMethodAdapter.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/RuleTriggerMethodAdapter.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -2,11 +2,18 @@
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.Method;
import org.jboss.jbossts.orchestration.rule.Rule;
+import org.jboss.jbossts.orchestration.rule.type.TypeHelper;
import org.jboss.jbossts.orchestration.rule.binding.Bindings;
import org.jboss.jbossts.orchestration.rule.binding.Binding;
+import org.jboss.jbossts.orchestration.agent.adapter.cfg.*;
+import org.jboss.jbossts.orchestration.agent.Transformer;
import java.util.*;
+import java.io.PrintStream;
/**
* class which provides base functionality extended by all the location-specific method trigger adapters
@@ -22,6 +29,7 @@
this.returnType = Type.getReturnType(descriptor);
this.argumentTypes = Type.getArgumentTypes(descriptor);
this.bindingsDone = false;
+ this.localTypes = new ArrayList();
}
private void setBindingIndices()
@@ -87,7 +95,7 @@
}
if (paramBindings.size() == 0) {
- super.push((org.objectweb.asm.Type)null);
+ push((org.objectweb.asm.Type)null);
return;
}
@@ -114,10 +122,454 @@
}
}
+ /**
+ * return true if the current block is handler which catches a thrown exception within the scope
+ * of a monitor enter in order to be able exit the monitor and rethrow the exception
+ * @return
+ */
+ protected boolean inRethrowHandler()
+ {
+ return cfg.inRethrowHandler();
+ }
+
private int access;
private String descriptor;
private Type returnType;
private Type[] argumentTypes;
private List<Binding> paramBindings;
private boolean bindingsDone;
-}
+ private final List localTypes;
+
+ private CFG cfg;
+
+ private final static Type EXECUTE_EXCEPTION_TYPE = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ExecuteException"));
+ private final static Type EARLY_RETURN_EXCEPTION_TYPE = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.EarlyReturnException"));
+ private final static Type THROW_EXCEPTION_TYPE = Type.getType(TypeHelper.externalizeType("org.jboss.jbossts.orchestration.rule.exception.ThrowException"));
+ private final static String EXECUTE_EXCEPTION_TYPE_NAME = EXECUTE_EXCEPTION_TYPE.getInternalName();
+ private final static String EARLY_RETURN_EXCEPTION_TYPE_NAME = EARLY_RETURN_EXCEPTION_TYPE.getInternalName();
+ private final static String THROW_EXCEPTION_TYPE_NAME = THROW_EXCEPTION_TYPE.getInternalName();
+
+ // methdos copied from GeneratorAdapter but modified so they invoke local MethodVisitor
+ // method implementations rather than delegating to the next MethodVisitor in line
+
+
+
+ // overridden methods from MethodVisitor
+
+ @Override
+ public void visitCode()
+ {
+ super.visitCode();
+ // create a control flow graph for the method
+ String methodName = this.rule.getTargetClass() + "." + this.name + this.descriptor;
+ Label newStart = super.newLabel();
+ this.cfg = new CFG(methodName, newStart);
+ visitLabel(newStart);
+ }
+
+ @Override
+ public void visitInsn(int opcode)
+ {
+ super.visitInsn(opcode);
+ // look for interesting instructions which need inserting into the CFG
+ switch(opcode)
+ {
+ case Opcodes.IRETURN:
+ case Opcodes.LRETURN:
+ case Opcodes.DRETURN:
+ case Opcodes.RETURN:
+ case Opcodes.ATHROW:
+ {
+ // add this instruction to the current block and then start a new current block
+ cfg.add(opcode);
+ Label newStart = super.newLabel();
+ // must call split before visiting the label
+ cfg.split(newStart);
+ visitLabel(newStart);
+ }
+ break;
+ case Opcodes.MONITORENTER:
+ case Opcodes.MONITOREXIT:
+ {
+ // just add this instruction to the current block
+ cfg.add(opcode);
+ }
+ break;
+ default:
+ {
+ cfg.add(opcode);
+ }
+ }
+ }
+
+ @Override
+ public void visitIincInsn(int var, int increment)
+ {
+ super.visitIincInsn(var, increment);
+ cfg.add(Opcodes.IINC, var, increment);
+ }
+
+ @Override
+ public void visitIntInsn(int opcode, int operand)
+ {
+ super.visitIntInsn(opcode, operand);
+ cfg.add(opcode, operand);
+ }
+
+ @Override
+ public void visitLdcInsn(Object cst)
+ {
+ super.visitLdcInsn(cst);
+ cfg.add(Opcodes.LDC, cst.toString());
+ }
+
+ @Override
+ public void visitVarInsn(int opcode, int var)
+ {
+ super.visitVarInsn(opcode, var);
+ cfg.add(opcode, var);
+ }
+
+ @Override
+ public void visitTypeInsn(int opcode, String desc)
+ {
+ super.visitTypeInsn(opcode, desc);
+ cfg.add(opcode, desc);
+ }
+
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String desc)
+ {
+ super.visitFieldInsn(opcode, owner, name, desc);
+ cfg.add(opcode, owner, name, desc);
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name, String desc)
+ {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ cfg.add(opcode, owner, name, desc);
+ }
+
+ @Override
+ public void visitJumpInsn(int opcode, Label label)
+ {
+ super.visitJumpInsn(opcode, label);
+ switch (opcode)
+ {
+ case Opcodes.IFEQ:
+ case Opcodes.IFNE:
+ case Opcodes.IFLT:
+ case Opcodes.IFGE:
+ case Opcodes.IFGT:
+ case Opcodes.IFLE:
+ case Opcodes.IF_ICMPEQ:
+ case Opcodes.IF_ICMPNE:
+ case Opcodes.IF_ICMPLT:
+ case Opcodes.IF_ICMPGE:
+ case Opcodes.IF_ICMPGT:
+ case Opcodes.IF_ICMPLE:
+ case Opcodes.IF_ACMPEQ:
+ case Opcodes.IF_ACMPNE:
+ {
+ // create a new current block and add the label supplied in the call as the
+ // first out of the old current block and the label of the new current block as
+ // the second out
+ cfg.add(opcode);
+ Label newStart = super.newLabel();
+ // must call split before visiting the label
+ cfg.split(newStart, label, newStart);
+ visitLabel(newStart);
+ }
+ break;
+ case Opcodes.GOTO:
+ {
+ // create a new current block and add the label supplied in the call as the
+ // first out of the old current block
+ cfg.add(opcode);
+ Label newStart = super.newLabel();
+ // must call split before visiting the label
+ cfg.split(newStart, label);
+ visitLabel(newStart);
+ }
+ break;
+ case Opcodes.JSR:
+ {
+ // create a new current block and add the label supplied in the call as the first out
+ // of the current block -- the new current block is a potential return point from the
+ // JSR but we cannot represent that statically
+ cfg.add(opcode);
+ Label newStart = super.newLabel();
+ // must call split before visiting the label
+ cfg.split(newStart, label, newStart);
+ visitLabel(newStart);
+ }
+ break;
+ case Opcodes.IFNULL:
+ case Opcodes.IFNONNULL:
+ {
+ // create a new current block and add the label supplied in the call as the
+ // first out of the old current block and the label of the new current block as
+ // the second out
+ cfg.add(opcode);
+ Label newStart = super.newLabel();
+ // must call split before visiting the label
+ cfg.split(newStart, label, newStart);
+ visitLabel(newStart);
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void visitLabel(Label label)
+ {
+ super.visitLabel(label);
+
+ // tell the CFG to visit this label
+
+ cfg.visitLabel(label);
+ // if this is a try catch block end then we need to visit the try catch block now
+ if (cfg.tryCatchEnd(label)) {
+ for (TryCatchDetails details : cfg.tryCatchEndDetails(label)) {
+ super.visitTryCatchBlock(details.getStart(), details.getEnd(), details.getHandler(), details.getType());
+ }
+ }
+ }
+
+ public void visitTriggerStart(Label label)
+ {
+ visitLabel(label);
+
+ // tell the CFG to visit this label
+
+ cfg.visitTriggerStart(label);
+ }
+
+ public void visitTriggerEnd(Label label)
+ {
+ visitLabel(label);
+
+ // tell the CFG to visit this label
+
+ cfg.visitTriggerEnd(label);
+
+ // ok, update the trigger details with labels for the handler blocks we are going to generate
+
+ TriggerDetails details = cfg.triggerEndDetails(label);
+
+ Label returnHandler = newLabel();
+ Label throwHandler = newLabel();
+ Label executeHandler = newLabel();
+
+ details.setEarlyReturnHandler(returnHandler);
+ details.setThrowHandler(throwHandler);
+ details.setExecuteHandler(executeHandler);
+
+ // ok now we set up try catch handlers for the triggger block
+ // n.b. we need to use a new label for the end because insertion of the handler is set off when
+ // its end label is visited
+
+ Label end = new Label();
+
+ visitTryCatchBlock(details.getStart(), end, returnHandler, EARLY_RETURN_EXCEPTION_TYPE_NAME);
+ visitTryCatchBlock(details.getStart(), end, throwHandler, THROW_EXCEPTION_TYPE_NAME);
+ visitTryCatchBlock(details.getStart(), end, executeHandler, EXECUTE_EXCEPTION_TYPE_NAME);
+
+ // ok this fixes the handler end label at the same pont as the trigger end label
+
+ visitLabel(end);
+ }
+
+ /*
+ @Override
+ public void visitLdcInsn(Object cst) {
+ super.visitLdcInsn(cst);
+ }
+ @Override
+ public void visitIincInsn(int var, int increment) {
+ super.visitIincInsn(var, increment);
+ }
+ */
+
+ @Override
+ public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels)
+ {
+ super.visitTableSwitchInsn(min, max, dflt, labels);
+ cfg.add(Opcodes.TABLESWITCH, min, max);
+ // create a new current block and then add the default lable and each of the switch labels as an
+ // outgoing path from the current block
+ Label newStart = super.newLabel();
+ // must call split before visiting the label
+ cfg.split(newStart, dflt, labels);
+ visitLabel(newStart);
+ }
+
+ @Override
+ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels)
+ {
+ super.visitLookupSwitchInsn(dflt, keys, labels);
+ cfg.add(Opcodes.TABLESWITCH, keys);
+ // create a new current block and then add the default lable and each of the switch labels as an
+ // outgoing path from the current block
+ Label newStart = super.newLabel();
+ // must call split before visiting the label
+ cfg.split(newStart, dflt, labels);
+ visitLabel(newStart);
+ }
+
+ @Override
+ public void visitMultiANewArrayInsn(String desc, int dims)
+ {
+ super.visitMultiANewArrayInsn(desc, dims);
+ cfg.add(Opcodes.MULTIANEWARRAY, desc, dims);
+ }
+
+ @Override
+ public void visitTryCatchBlock(Label start, Label end, Label handler, String type)
+ {
+ // don't notify this until we reach the end label so we can slip
+ // trigger sequence try catch blocks in.
+ // super.visitTryCatchBlock(start, end, handler, type);
+
+ // tell the cfg to visit this block
+
+ cfg.visitTryCatchBlock(start, end, handler, type);
+ }
+
+ @Override
+ public void visitMaxs(int maxStack, int maxLocals)
+ {
+ Type returnType = Type.getReturnType(descriptor);
+
+ // check whether there are outstanding monitor opens at the start of the trigger
+ // block and, if so, insert a handler which unlocks the monitor and then rethrows
+ // the exception.
+
+ Iterator<TriggerDetails> iterator = cfg.triggerDetails();
+ boolean noneLeft = true;
+
+ while (iterator.hasNext()) {
+ TriggerDetails details = iterator.next();
+ Label startLabel = details.getStart();
+ CodeLocation startLocation = cfg.getLocation(startLabel);
+ List<CodeLocation> openEnters = cfg.getOpenMonitors(startLocation);
+ if (openEnters != null) {
+ // add a handler here which unlocks each object and rethrows the
+ // saved exception then protect it with a try catch block and update
+ // the details so that it is the target of this block
+
+ Label newStart = newLabel();
+ Label newEnd = newLabel();
+ Label newExecute = newLabel();
+ Label newEarlyReturn = newLabel();
+ Label newThrow = newLabel();
+ // make the old exceptions arrive here
+ visitLabel(details.getExecuteHandler());
+ visitLabel(details.getEarlyReturnHandler());
+ visitLabel(details.getThrowHandler());
+ // now add a rethrow handler which exits the open monitors
+ visitLabel(newStart);
+ int listIdx = openEnters.size();
+ while (listIdx-- > 0) {
+ CodeLocation enterLocation = openEnters.get(listIdx);
+ int varIdx = cfg.getSavedMonitorIdx(enterLocation);
+ // call super method to avoid indexing these instructions
+ super.visitIntInsn(Opcodes.ALOAD, varIdx);
+ super.visitInsn(Opcodes.MONITOREXIT);
+ }
+ // throw must be in scope of the try catch
+ // call super method to avoid creating new blocks
+ super.visitInsn(Opcodes.ATHROW);
+ visitLabel(newEnd);
+ // now add try catch blocks for each of the exception types -- use super call to avoid
+ // normal inhibition of try catch generation
+ super.visitTryCatchBlock(newStart, newEnd, newEarlyReturn, EARLY_RETURN_EXCEPTION_TYPE_NAME);
+ super.visitTryCatchBlock(newStart, newEnd, newExecute, EXECUTE_EXCEPTION_TYPE_NAME);
+ // this comes last because it is the superclass of the previous two
+ super.visitTryCatchBlock(newStart, newEnd, newThrow, THROW_EXCEPTION_TYPE_NAME);
+ // and update the details so it will catch these exceptions
+ details.setStart(newStart);
+ details.setEnd(newEnd);
+ details.setExecuteHandler(newExecute);
+ details.setEarlyReturnHandler(newEarlyReturn);
+ details.setThrowHandler(newThrow);
+ }
+ }
+
+ // ok, so now we have to add the handler code for trigger block try catch handlers
+ // we only need to add the handler code once but we need to make sure it is the target of
+ // all the try catch blocks by visiting their handler label before we insert the code
+
+ iterator = cfg.triggerDetails();
+
+ while (iterator.hasNext()) {
+ TriggerDetails details = iterator.next();
+ visitLabel(details.getEarlyReturnHandler());
+ }
+
+ if (Transformer.isVerbose()) {
+ super.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class));
+ super.visitLdcInsn("caught ReturnException");
+ super.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println(String)"));
+ }
+ // add exception handling code subclass first
+ 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(EARLY_RETURN_EXCEPTION_TYPE, getReturnValueMethod);
+ super.unbox(returnType);
+ super.returnValue();
+ }
+
+ iterator = cfg.triggerDetails();
+
+ while (iterator.hasNext()) {
+ TriggerDetails details = iterator.next();
+ visitLabel(details.getThrowHandler());
+ }
+
+ if (Transformer.isVerbose()) {
+ super.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class));
+ super.visitLdcInsn("caught ThrowException");
+ super.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println(String)"));
+ }
+ // fetch value from exception, unbox if needed and return value
+ Method getThrowableMethod = Method.getMethod("Throwable getThrowable()");
+ super.invokeVirtual(THROW_EXCEPTION_TYPE, getThrowableMethod);
+ super.throwException();
+
+ // execute exception comes last because it is the super of the othher two classes
+
+ iterator = cfg.triggerDetails();
+
+ while (iterator.hasNext()) {
+ TriggerDetails details = iterator.next();
+ visitLabel(details.getExecuteHandler());
+ }
+
+ if (Transformer.isVerbose()) {
+ super.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class));
+ super.visitLdcInsn("caught ExecuteException");
+ super.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println(String)"));
+ }
+ // rethrow an execute exception
+ super.throwException(EXECUTE_EXCEPTION_TYPE, rule.getName() + " execution exception ");
+ super.visitMaxs(maxStack, maxLocals);
+
+ // hmm, don't think we need this
+ cfg.visitMaxs();
+ }
+
+ @Override
+ public void visitEnd()
+ {
+ super.visitEnd();
+ // trash the current label
+ cfg.visitEnd();
+ }
+}
\ No newline at end of file
Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/SynchronizeTriggerAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/SynchronizeTriggerAdapter.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/SynchronizeTriggerAdapter.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -108,87 +108,24 @@
if (Transformer.isVerbose()) {
System.out.println("SynchronizeTriggerMethodAdapter.visitMethodInsn : inserting trigger for " + rule.getName());
}
- startLabel = super.newLabel();
- endLabel = super.newLabel();
- super.visitLabel(startLabel);
- super.push(key);
+ startLabel = newLabel();
+ endLabel = newLabel();
+ visitTriggerStart(startLabel);
+ push(key);
if ((access & Opcodes.ACC_STATIC) == 0) {
- super.loadThis();
+ loadThis();
} else {
- super.push((Type)null);
+ push((Type)null);
}
doArgLoad();
- super.invokeStatic(ruleType, method);
- super.visitLabel(endLabel);
+ invokeStatic(ruleType, method);
+ visitTriggerEnd(endLabel);
}
}
if (!whenComplete) {
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);
- // 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);
- // 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 String calledClass;
Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ThrowTriggerAdapter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ThrowTriggerAdapter.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/ThrowTriggerAdapter.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -100,107 +100,41 @@
public void visitInsn(final int opcode) {
if (opcode == Opcodes.ATHROW) {
- // TODO -- this fails if exceptions or throws can occur inside monitor blocks
- // TODO -- because they get caught and rethrown at the end of the monitor block
- // TODO -- which means the wrong throws get counted
- // TODO -- so we need to track throw catch blocks and monitor enter/exits properly
-
// ok, we have hit a throw -- for now we just count any throw
// later we will try to match the exception class
if (visitedCount < count) {
// a relevant invocation occurs in the called method
- visitedCount++;
- if (!latched && visitedCount == count) {
- 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());
+ // check whether this is a real throw or a rethrow after a monitorexit
+ if (!inRethrowHandler()) {
+ visitedCount++;
+ if (!latched && visitedCount == count) {
+ 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());
+ }
+ startLabel = newLabel();
+ endLabel = newLabel();
+ visitTriggerStart(startLabel);
+ push(key);
+ if ((access & Opcodes.ACC_STATIC) == 0) {
+ loadThis();
+ } else {
+ push((Type)null);
+ }
+ doArgLoad();
+ invokeStatic(ruleType, method);
+ visitTriggerEnd(endLabel);
}
- startLabel = super.newLabel();
- endLabel = super.newLabel();
- super.visitLabel(startLabel);
- super.push(key);
- if ((access & Opcodes.ACC_STATIC) == 0) {
- super.loadThis();
- } else {
- super.push((Type)null);
- }
- doArgLoad();
- super.invokeStatic(ruleType, method);
- super.visitLabel(endLabel);
}
}
}
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);
- // 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);
- // 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);
- }
-
}
/**
Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/BBlock.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/BBlock.java (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/BBlock.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -0,0 +1,1040 @@
+package org.jboss.jbossts.orchestration.agent.adapter.cfg;
+
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.jboss.jbossts.orchestration.agent.adapter.OpcodesHelper;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Iterator;
+
+/**
+ * A Basic Block represents a segment of bytecode in a control flow graph. Basic blocks divide up the
+ * code at control flow branch points and hence there is not control flow internal to a block. Normal
+ * control flow will only transfer control from the end of one basic block to the start of another
+ * basic block or to the caller (via a return or throw). Exception control flow may transfer control
+ * from any point within a basic block to the the start of another basic block or to the caller.
+ */
+
+public class BBlock
+{
+ private CFG cfg;
+
+ /**
+ * the sequence of instructions contained in this basic block
+ */
+ private InstructionSequence instructions;
+ /*
+ * A collection of the outgoing links from this basic block to other basic blocks.
+ * Every block except the last one has at least one outgoing link because link 0
+ * identifies the linkage of blocks in the original bytecode ordering. Any subsequent
+ * links identify outgoing non-excepting control flow from the basic block. The number
+ * and significance of these subsequent links is determined by the type of the last
+ * instruction. As a consequence iterations over this collection should be 1-based, not 0-based.
+ *
+ * Blocks ending in RETURN or ATHROW are terminal so they have no extra links.
+ *
+ * Blocks ending in GOTO have on extra link, identifying the target of the GOTO instruction.
+ *
+ * Blocks ending in an IF_XXX instruction have two extra links, the target branch if the
+ * instruction computes to false followed by the target branch if the instruction computes to
+ * true.
+ */
+ private Link outGoing;
+
+ /**
+ * an index for the block allocated by the CFG starting from 0 in block order
+ */
+ private int blockIdx;
+
+ /**
+ * details of all try catch blocks which are active inside this block. n.b. this must omit try
+ * catch blocks which are open when the block is created then subsequently closed at offset 0.
+ */
+ private List<TryCatchDetails> activeTryStarts;
+ /**
+ * details of all try catch blocks which start in this block
+ */
+ private List<TryCatchDetails> tryStarts;
+ /**
+ * a list of all try catch blocks which end in this block
+ */
+ private List<TryCatchDetails> tryEnds;
+ /**
+ * a list of all try catch blocks whose handlers start in this block
+ */
+ private List<TryCatchDetails> tryHandlerStarts;
+
+ /**
+ * a list of the location of all monitor enter instructions contained in this block
+ */
+ private List<CodeLocation> monitorEnters;
+ /**
+ * a list of the location of all monitor exit instructions contained in this block
+ */
+ private List<CodeLocation> monitorExits;
+
+ /**
+ * construct a new basic block
+ * @param cfg the control flow graph it belongs to
+ * @param start the label for the start of the block
+ * @param blockIdx the index of the block which respects the order of the bytecode segments
+ * contained in each block.
+ */
+ public BBlock(CFG cfg, Label start, int blockIdx)
+ {
+ this.cfg = cfg;
+ this.instructions = new InstructionSequence();
+ this.outGoing = new Link(start);
+ this.blockIdx = blockIdx;
+ this.activeTryStarts = new LinkedList<TryCatchDetails>();
+ this.tryStarts = new LinkedList<TryCatchDetails>();
+ this.tryEnds = new LinkedList<TryCatchDetails>();
+ this.tryHandlerStarts = new LinkedList<TryCatchDetails>();
+ this.monitorEnters = new LinkedList<CodeLocation>();
+ this.monitorExits = new LinkedList<CodeLocation>();
+ }
+
+ /**
+ * obtain the control flow graph to which this block belongs
+ * @return
+ */
+ public CFG getCFG()
+ {
+ return cfg;
+ }
+
+ /**
+ * get the primary label which idenitfies tis block. It will be located in the block at offset 0.
+ * @return
+ */
+ public Label getLabel()
+ {
+ return outGoing.getFrom();
+ }
+
+ /**
+ * retrieve the index of this block in the block sequence.
+ * @return
+ */
+ public int getBlockIdx()
+ {
+ return blockIdx;
+ }
+
+ /**
+ * add an instruction to the sequence in the block
+ * @param instruction an Opcode
+ * @return the index of the newly added instruction
+ */
+ public int append(int instruction)
+ {
+ if (instruction == Opcodes.MONITORENTER) {
+ monitorEnters.add(new CodeLocation(this, instructions.size()));
+ } else if (instruction == Opcodes.MONITOREXIT) {
+ monitorExits.add(new CodeLocation(this, instructions.size()));
+ }
+ return instructions.add(instruction);
+ }
+
+ /**
+ * add an instruction with one int operand to thhe sequence in the block
+ * @param instruction an Opcode
+ * @param operand an int operand or the code for a String operand lcoated in the cfg name table
+ * @return the index of the newly added instruction
+ */
+ public int append(int instruction, int operand)
+ {
+ return instructions.add(instruction, operand);
+ }
+
+ /**
+ * add an instruction with two int operands to the sequence in the block
+ * @param instruction an Opcode
+ * @param operand1 an int operand or the code for a String operand lcoated in the cfg name table
+ * @param operand2 an int operand or the code for a String operand lcoated in the cfg name table
+ * @return the index of the newly added instruction
+ */
+ public int append(int instruction, int operand1, int operand2)
+ {
+ return instructions.add(instruction, operand1, operand2);
+ }
+
+ /**
+ * add an instruction with three int operands to thhe sequence in the block
+ * @param instruction an Opcode
+ * @param operand1 an int operand or the code for a String operand lcoated in the cfg name table
+ * @param operand2 an int operand or the code for a String operand lcoated in the cfg name table
+ * @param operand3 an int operand or the code for a String operand lcoated in the cfg name table
+ * @return the index of the newly added instruction
+ */
+ public int append(int instruction, int operand1, int operand2, int operand3)
+ {
+ return instructions.add(instruction, operand1, operand2, operand3);
+ }
+
+ /**
+ * add an instruction with an arbitrary number of int operands to thhe sequence in the block
+
+ * @param instruction an Opcode
+ * @param operands an array containing int operands or codes for String operands lcoated in the cfg name table
+ * @return the index of the newly added instruction
+ */
+ public int append(int instruction, int[] operands)
+ {
+ return instructions.add(instruction, operands);
+ }
+
+ /**
+ * record details of a try catch block which starts in this block
+ * @param details
+ */
+ public void addTryStarts(List<TryCatchDetails> details)
+ {
+ tryStarts.addAll(details);
+ activeTryStarts.addAll(details);
+ }
+
+ /**
+ * record details of a try catch block which ends in this block
+ * @param details
+ */
+ public void addTryEnds(List<TryCatchDetails> details)
+ {
+ tryEnds.addAll(details);
+ }
+
+ /**
+ * record details of a try catch block handler which starts in this block
+ * @param details
+ */
+ public void addTryHandlerStarts(List<TryCatchDetails> details)
+ {
+ tryHandlerStarts.addAll(details);
+ }
+
+ /**
+ * merge a list of previously active try catch blocks into the list of try starts which are active somewhere
+ * in this block.
+ * @param extra
+ */
+ public void updateActiveTryStarts(List<TryCatchDetails> extra)
+ {
+ activeTryStarts.addAll(extra);
+ }
+
+ /**
+ * merge the list of try catch blocks started in this block into the supplied carry froward list.
+ * @param carryList
+ */
+ public void carryTryStarts(List<TryCatchDetails> carryList)
+ {
+ carryList.addAll(tryStarts);
+ }
+
+ /**
+ * delete the list of try catch blocks ended in this block from the supplied carry forward list.
+ * @param carryList
+ */
+ public void removeTryEnds(List<TryCatchDetails> carryList)
+ {
+ carryList.removeAll(tryEnds);
+ }
+
+ /**
+ * retrieve details of all try catch blocks which start in this block
+ * @return
+ */
+ public Iterator<TryCatchDetails> getTryStarts()
+ {
+ return tryStarts.iterator();
+ }
+
+ /**
+ * retrieve details of all try catch blocks which end in this block
+ * @return
+ */
+ public Iterator<TryCatchDetails> getTryEnds()
+ {
+ return tryEnds.iterator();
+ }
+
+ /**
+ * retrieve details of all try catch block handlers whcih start in this block
+ * @return
+ */
+ public Iterator<TryCatchDetails> getTryHandlerStarts()
+ {
+ return tryHandlerStarts.iterator();
+ }
+
+ /**
+ * retrieve details of all try catch blocks which are capable of generating an exception in this block
+ * @return
+ */
+ public Iterator<TryCatchDetails> getActiveTryStarts()
+ {
+ return activeTryStarts.iterator();
+ }
+
+ /**
+ * retrieve a list of all monitor enter instruction locations occuringin this block
+ * @return
+ */
+ public Iterator<CodeLocation> getMonitorEnters()
+ {
+ return monitorEnters.iterator();
+ }
+
+ /**
+ * retrieve a list of all monitor exit instruction locations occuringin this block
+ * @return
+ */
+ public Iterator<CodeLocation> getMonitorExits()
+ {
+ return monitorExits.iterator();
+ }
+
+ /**
+ * retrieve a count of all monitor enter instruction locations occuring in this block
+ * @return
+ */
+ public int getMonitorEnterCount()
+ {
+ return monitorEnters.size();
+ }
+
+ /**
+ * retrieve a count of all monitor exit instruction locations occuring in this block
+ * @return
+ */
+ public int getMonitorExitCount()
+ {
+ return monitorExits.size();
+ }
+
+ /**
+ * return the number of instructions in the blocks instructuion sequence equivalent to the
+ * index of the next instruction added to the block.
+ * @return
+ */
+ public int getInstructionCount()
+ {
+ return instructions.size();
+ }
+
+ /**
+ * retirn the instruction at a given index.
+ * @param index
+ * @return
+ */
+ public int getInstruction(int index)
+ {
+ return instructions.get(index);
+ }
+
+ /**
+ * retrieve the integer operand or encoded name associated with a particular instruction
+ * @param index the index of the instruction in the block
+ * @param argIndex the index of the argument in the sequence of arguments presented when the instruction
+ * was inserted intot he block.
+ * @return
+ */
+ public int getInstructionArg(int index, int argIndex)
+ {
+ return instructions.getArg(index, argIndex);
+ }
+
+ /**
+ * install an outgoing normal control flow link
+ * @param label
+ */
+ public void append(Label label)
+ {
+ outGoing.append(label);
+ }
+
+ /**
+ * return the label of the next block in line in the block sequence in bytecode order.
+ * @return
+ */
+ public Label next()
+ {
+ return outGoing.getTo(0);
+ }
+
+ /**
+ * return the label of the first normal control flow link
+ * @return
+ */
+ public Label firstOut()
+ {
+ return outGoing.getTo(1);
+ }
+
+ /**
+ * return the label of the second normal control flow link
+ * @return
+ */
+ public Label secondOut()
+ {
+ return outGoing.getTo(2);
+ }
+
+ // n.b. index for out link is 1-based rather than 0-based as entry 0 is the next link
+ /**
+ * return the label of the nth normal control flow link
+ * @return
+ */
+ public Label nthOut(int n)
+ {
+ return outGoing.getTo(n);
+ }
+
+ /**
+ * return a count of the normal control flow links from this block.
+ * @return the number of outgoingnormalcontrol flow links. n.b. iterations over
+ * the links should count from 1 to nOuts() inclusive. this is the size of a 1-based
+ * collection
+ */
+ public int nOuts()
+ {
+ return outGoing.getToCount() - 1;
+ }
+
+ /**
+ * return a string represenattion of this block
+ * @return
+ */
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ printTo(buf);
+ return buf.toString();
+ }
+
+ /**
+ * write a string represenattion of this block to the buffer
+ * @param buf the buffer to be written to
+ * @return
+ */
+ void printTo(StringBuffer buf)
+ {
+ buf.append(this.getLabel().getOffset());
+ buf.append(": BB ");
+ buf.append(this.getBlockIdx());
+ buf.append("\n");
+ Link containsLink = cfg.getContains(this);
+ Iterator<Label> containsIter;
+ Label containedLabel;
+ int containedPosition;
+ if (containsLink != null) {
+ containsIter = containsLink.iterator();
+ if (containsIter.hasNext()) {
+ containedLabel = containsIter.next();
+ containedPosition = cfg.getBlockInstructionIdx(containedLabel);
+ } else {
+ containedLabel = null;
+ containedPosition = -1;
+ }
+ } else {
+ containsIter = null;
+ containedLabel = null;
+ containedPosition = -1;
+ }
+
+ int instructionCount = this.getInstructionCount();
+ for (int i = 0; i < instructionCount; i++) {
+ // we will never enter this if containedPosition is -1 which safeguards us when containsIter
+ // is null or containedLabel is null
+ while (containedPosition == i) {
+ buf.append(containedLabel.getOffset());
+ buf.append(": ");
+ buf.append(containedLabel);
+ buf.append(" +");
+ buf.append(containedPosition);
+ if (cfg.tryCatchStart(containedLabel)) {
+ List<TryCatchDetails> detailsList = cfg.tryCatchStartDetails(containedLabel);
+ int detailsCount = detailsList.size();
+ for (int j = 0; j < detailsCount; j++) {
+ TryCatchDetails details = detailsList.get(j);
+ Label handlerLabel = details.getHandler();
+ CodeLocation handlerLocation = cfg.getLocation(handlerLabel);
+ buf.append(" try ");
+ buf.append(details.getType());
+ buf.append(" ");
+ if (handlerLocation != null) {
+ buf.append(handlerLabel.getOffset());
+ } else {
+ buf.append("??");
+ }
+ buf.append(" ");
+ buf.append(handlerLabel);
+ }
+ }
+ if (cfg.tryCatchEnd(containedLabel)) {
+ List<TryCatchDetails> detailsList = cfg.tryCatchEndDetails(containedLabel);
+ int detailsCount = detailsList.size();
+ for (int j = 0; j < detailsCount; j++) {
+ TryCatchDetails details = detailsList.get(j);
+ Label handlerLabel = details.getHandler();
+ CodeLocation handlerLocation = cfg.getLocation(handlerLabel);
+ buf.append(" catch ");
+ buf.append(details.getType());
+ buf.append(" ");
+ if (handlerLocation != null) {
+ buf.append(handlerLabel.getOffset());
+ } else {
+ buf.append("??");
+ }
+ buf.append(" ");
+ buf.append(handlerLabel);
+ }
+ }
+ if (cfg.tryCatchHandlerStart(containedLabel)) {
+ List<TryCatchDetails> detailsList = cfg.tryCatchHandlerStartDetails(containedLabel);
+ int detailsCount = detailsList.size();
+ for (int j = 0; j < detailsCount; j++) {
+ TryCatchDetails details = detailsList.get(j);
+ buf.append(" handle ");
+ buf.append(details.getType());
+ buf.append(" ");
+ buf.append(details.getStart().getOffset());
+ buf.append(" ");
+ buf.append(details.getEnd().getOffset());
+ }
+ }
+ if (cfg.triggerStart(containedLabel)) {
+ buf.append(" trigger start");
+ TriggerDetails details = cfg.triggerStartDetails(containedLabel);
+ }
+ if (cfg.triggerEnd(containedLabel)) {
+ buf.append(" trigger end");
+ }
+ buf.append("\n");
+ List<CodeLocation> openEnters = cfg.getOpenMonitorEnters(containedLabel);
+ if (openEnters != null) {
+ int openCount = openEnters.size();
+ if (openCount > 0) {
+ buf.append("open monitors: ");
+ for (int j = 0; j < openCount; j++) {
+ CodeLocation l = openEnters.get(j);
+ buf.append(" BB");
+ buf.append(l.getBlock().getBlockIdx());
+ buf.append(".");
+ buf.append(l.getInstructionIdx());
+ }
+ buf.append('\n');
+ }
+ }
+ containedLabel = (containsIter.hasNext() ? containsIter.next() : null);
+ containedPosition = (containedLabel != null ? cfg.getBlockInstructionIdx(containedLabel) : -1);
+ }
+ buf.append(" ");
+ int opcode = this.getInstruction(i);
+ switch (OpcodesHelper.insnType(opcode)) {
+ case OpcodesHelper.INSN_NONE:
+ {
+ // just print the instruction name
+ buf.append(OpcodesHelper.insnName(opcode));
+ buf.append("\n");
+ }
+ break;
+ case OpcodesHelper.INSN_INT:
+ {
+ // just print the instruction name and one integer argument
+ int intValue = this.getInstructionArg(i, 0);
+ buf.append(OpcodesHelper.insnName(opcode));
+ buf.append(" ");
+ buf.append(intValue);
+ buf.append("\n");
+ }
+ break;
+ case OpcodesHelper.INSN_LDC:
+ {
+ // print the instruction and one constant argument
+ int nameIdx = this.getInstructionArg(i, 0);
+ String name = cfg.getName(nameIdx);
+ buf.append(OpcodesHelper.insnName(opcode));
+ buf.append(" ");
+ buf.append(name);
+ buf.append("\n");
+ }
+ break;
+ case OpcodesHelper.INSN_VAR:
+ {
+ // print the instruction and the var idx
+ int varIdx = this.getInstructionArg(i, 0);
+ buf.append(OpcodesHelper.insnName(opcode));
+ buf.append(" ");
+ buf.append(varIdx);
+ buf.append("\n");
+ }
+ break;
+ case OpcodesHelper.INSN_IINC:
+ {
+ // print the instruction and the var idx
+ int increment = this.getInstructionArg(i, 0);
+ buf.append(OpcodesHelper.insnName(opcode));
+ buf.append(" ");
+ buf.append(increment);
+ buf.append("\n");
+ }
+ break;
+ case OpcodesHelper.INSN_JUMP:
+ {
+ // note that we may not have generated the code for the jump target yet
+ Label targetLabel = this.firstOut();
+ CodeLocation targetLocation = cfg.getLocation(targetLabel);
+ int targetPos = (targetLocation != null ? targetLabel.getOffset() : -1);
+ switch (opcode) {
+ case Opcodes.IFEQ:
+ buf.append("IFEQ ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IFNE:
+ buf.append("IFNE ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IFLT:
+ buf.append("IFLT ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IFGE:
+ buf.append("IFGE ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IFGT:
+ buf.append("IFGT ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IFLE:
+ buf.append("IFLE ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IF_ICMPEQ:
+ buf.append("IF_ICMPEQ ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IF_ICMPNE:
+ buf.append("IF_ICMPNE ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IF_ICMPLT:
+ buf.append("IF_ICMPLT ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IF_ICMPGE:
+ buf.append("IF_ICMPGE ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IF_ICMPGT:
+ buf.append("IF_ICMPGT ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IF_ICMPLE:
+ buf.append("IF_ICMPLE ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IF_ACMPEQ:
+ buf.append("IF_ACMPEQ ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IF_ACMPNE:
+ buf.append("IF_ACMPNE ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.GOTO:
+ buf.append("GOTO ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.JSR:
+ buf.append("JSR ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IFNULL:
+ buf.append("IFNULL ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ case Opcodes.IFNONNULL:
+ buf.append("IFNONNULL ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ buf.append("\n");
+ break;
+ }
+ }
+ break;
+ case OpcodesHelper.INSN_TSWITCH:
+ {
+ Label targetLabel;
+ CodeLocation targetLocation;
+ int targetPos;
+ // print the instruction followed by the jump table discriminant min and max and then
+ // the jump labels
+ int min = this.getInstructionArg(i, 0);
+ int max = this.getInstructionArg(i, 1);
+ int count = (max + 1 - min);
+ buf.append(OpcodesHelper.insnName(opcode));
+ buf.append(" ");
+ buf.append(min);
+ buf.append(" ");
+ buf.append(max);
+ buf.append("\n");
+ for (int j = 1; j <= count; j++) {
+ // note that we may not have generated the code for the jump target yet
+ targetLabel = this.nthOut(j);
+ targetLocation = cfg.getLocation(targetLabel);
+ targetPos = (targetLocation != null ? targetLabel.getOffset() : -1);
+ buf.append(" ");
+ buf.append(min + j);
+ buf.append(" : ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ }
+ targetLabel = this.firstOut();
+ targetLocation = cfg.getLocation(targetLabel);
+ targetPos = (targetLocation != null ? targetLabel.getOffset() : -1);
+ buf.append(" dflt : ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ }
+ break;
+ case OpcodesHelper.INSN_LOOKUP:
+ {
+ Label targetLabel;
+ CodeLocation targetLocation;
+ int targetPos;
+ // print the instruction followed by each jump table discriminant and label
+ int count = this.getInstructionArg(i, 0);
+ buf.append(OpcodesHelper.insnName(opcode));
+ buf.append("\n");
+ for (int j = 1; j <= count; j++) {
+ // note that we may not have generated the code for the jump target yet
+ targetLabel = this.nthOut(j);
+ targetLocation = cfg.getLocation(targetLabel);
+ targetPos = (targetLocation != null ? targetLabel.getOffset() : -1);
+ buf.append(" ");
+ buf.append(this.getInstructionArg(i, j));
+ buf.append(" : ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ }
+ targetLabel = this.firstOut();
+ targetLocation = cfg.getLocation(targetLabel);
+ targetPos = (targetLocation != null ? targetLabel.getOffset() : -1);
+ buf.append(" dflt : ");
+ if (targetPos >= 0) {
+ buf.append(targetPos);
+ buf.append(" BB ");
+ buf.append(targetLocation.getBlock().getBlockIdx());
+ buf.append(" ");
+ buf.append(targetLabel);
+ } else {
+ buf.append("?? ");
+ buf.append(targetLabel);
+ }
+ }
+ break;
+ case OpcodesHelper.INSN_FIELD:
+ case OpcodesHelper.INSN_METHOD:
+ {
+ // print the instruction with the owner, name and descriptor
+ int idx1 = this.getInstructionArg(i, 0);
+ int idx2 = this.getInstructionArg(i, 1);
+ int idx3 = this.getInstructionArg(i, 2);
+ String owner = cfg.getName(idx1);
+ String name = cfg.getName(idx2);
+ String desc = cfg.getName(idx3);
+ buf.append(OpcodesHelper.insnName(opcode));
+ buf.append(" ");
+ buf.append(owner);
+ buf.append(" ");
+ buf.append(name);
+ buf.append(" ");
+ buf.append(desc);
+ buf.append("\n");
+ }
+ break;
+ case OpcodesHelper.INSN_TYPE:
+ {
+ // print the instruction with the type name
+ int idx = this.getInstructionArg(i, 0);
+ String name = cfg.getName(idx);
+ buf.append(OpcodesHelper.insnName(opcode));
+ buf.append(" ");
+ buf.append(name);
+ buf.append("\n");
+ }
+ break;
+ case OpcodesHelper.INSN_MULTIANEWARRAY:
+ {
+ // print the instruction with the typename and the dimension count
+ int idx = this.getInstructionArg(i, 0);
+ int dims = this.getInstructionArg(i, 1);
+ String name = cfg.getName(idx);
+ buf.append(OpcodesHelper.insnName(opcode));
+ buf.append(" ");
+ buf.append(name);
+ buf.append(" ");
+ buf.append(dims);
+ buf.append("\n");
+ }
+ break;
+ case OpcodesHelper.INSN_UNUSED:
+ {
+ // print the instruction
+ buf.append(OpcodesHelper.insnName(opcode));
+ buf.append("!!!\n");
+ }
+ break;
+ }
+ }
+ // print the active starts for this block
+ Iterator<TryCatchDetails> activeStarts = this.getActiveTryStarts();
+ while (activeStarts.hasNext()) {
+ TryCatchDetails details = activeStarts.next();
+ Label label = details.getStart();
+ BBlock block = cfg.getBlock(label);
+ buf.append("try: ");
+ if (block != null) {
+ buf.append(label.getOffset());
+ buf.append(" ");
+ buf.append(block.getBlockIdx());
+ buf.append(".");
+ buf.append(cfg.getBlockInstructionIdx(label));
+ } else {
+ buf.append(label);
+ }
+ buf.append(" catch: ");
+ label = details.getEnd();
+ block = cfg.getBlock(label);
+ if (block != null) {
+ buf.append(label.getOffset());
+ buf.append(" ");
+ buf.append(block.getBlockIdx());
+ buf.append(".");
+ buf.append(cfg.getBlockInstructionIdx(label));
+ } else {
+ buf.append(label);
+ }
+ buf.append(" handle: ");
+ label = details.getHandler();
+ block = cfg.getBlock(label);
+ if (block != null) {
+ buf.append(label.getOffset());
+ buf.append(" ");
+ buf.append(block.getBlockIdx());
+ buf.append(".");
+ buf.append(cfg.getBlockInstructionIdx(label));
+ } else {
+ buf.append(label);
+ }
+ buf.append(" ");
+ buf.append(details.getType());
+ buf.append("\n");
+ }
+ }
+}
Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/CFG.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/CFG.java (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/CFG.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -0,0 +1,1113 @@
+package org.jboss.jbossts.orchestration.agent.adapter.cfg;
+
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.jboss.jbossts.orchestration.agent.Transformer;
+
+import java.util.*;
+
+/**
+ * A control flow graph for use by the trigger adapter. the cfg maintains the current instruction sequence
+ * for the bytecode in encoded form as it is being generated. It segments the instructions into basic blocks,
+ * splitting them at control flow branch points. It also keeps track of the location of try catch blocks
+ * and their handlers and of monitor enter and exit instructions. In particular it allows the rule trigger
+ * insertion adapter to identify whether or not an inserted rule trigger call is within the scope of one
+ * or more synchronized blocks and hence protect the trigger call with try catch handlers which ensure that
+ * any pending monitor enters are roudned off with a corresponidng monitor exit. See RuleTriggerMethodAdapter
+ * for details of hos the methods provided by this class are used.
+ */
+public class CFG
+{
+ /**
+ * the name of the method for which this is a CFG
+ */
+ private String methodName;
+ /**
+ * the label of the first basic block in the code
+ */
+ private BBlock entry;
+ /**
+ * the current basic block
+ */
+ private BBlock current;
+ /**
+ * a counter used to number bblocks in code order
+ */
+ private int nextIdx;
+ /**
+ * a mapping from the start label of a basic block to the associated block
+ */
+ private Map<Label, BBlock> blocks;
+ /**
+ * a mapping from each label to its enclosing basic block and instruction offset
+ */
+ private Map<Label, CodeLocation> labelLocations;
+ /**
+ * a map identifying the containment relationship between a basic block and labels which identify
+ * instructions located within the block - the first entry is the block label itself
+ */
+ private Map<BBlock, Link> contains;
+ /**
+ * a list of names employed in the bytecode
+ */
+ private List<String> names;
+ /**
+ * a map from labels which identify the start of a code injection sequence to details of the labels
+ * which locate the sequence and its exception handlers
+ */
+ private Map<Label, TriggerDetails> triggerStarts;
+ /**
+ * a map from labels which identify the end of a code injection sequence to details of the labels
+ * which locate the sequence and its exception handlers
+ */
+ private Map<Label, TriggerDetails> triggerEnds;
+
+ /**
+ * details of the last trigger section encountered set when a trigger start label is notified
+ */
+ private TriggerDetails latestTrigger;
+ /**
+ * a map from try catch block start labels to the corresponding try catch block details -- the value
+ * is a list because the code reader will reuse teh same label when two try catch blocks start at the
+ * same bytecode
+ */
+ private Map<Label, List<TryCatchDetails>> tryCatchStarts;
+ /**
+ * a map from try catch block end labels to the corresponding try catch block details -- the value
+ * is a list because the code reader will reuse the same label when two try catch blocks end at the
+ * same bytecode
+ */
+ private Map<Label, List<TryCatchDetails>> tryCatchEnds;
+ /**
+ * a map from try catch block handler labels to the corresponding try catch block details -- the value
+ * is a list because the code reader will reuse the same label when two handler blocks start at the
+ * same bytecode
+ */
+ private Map<Label, List<TryCatchDetails>> tryCatchHandlers;
+ /**
+ * a list of all try catch blocks which were open at the start of the block identified by current. this
+ * is kept up to date by method carryForward as blocks are split at control branch points.
+ */
+ private List<TryCatchDetails> openTryCatchStarts;
+ /**
+ * a map from block labels to any unclosed monitor enter instructions outstanding when the block is entered.
+ * this is only valid for blocks which are arrived at via conventional control flow i.e. not direct targets
+ * of try catch handler exceptions.
+ */
+ private Map<Label, List<CodeLocation>> openMonitorEnters;
+ /**
+ * a map from monitor enter instructions to the monitor exit insructions which close them. this is a list
+ * because an enter may have corresponding exits in exception handler blocks as well as the exit which
+ * is executed via normal control flow. Note that the latter is always the first entry in the list.
+ */
+ private Map<CodeLocation, List<CodeLocation>> monitorPairs;
+ /**
+ * an inverse map from each monitor exit instruction to the monitor enter insructions it closes.
+ */
+ private Map<CodeLocation, CodeLocation> inverseMonitorPairs;
+
+ /**
+ * construct a CFG labelling the initial block with a given label
+ * @param methodName the name of the method fro which this is a CFG
+ * @param start a label for the entry block of the CFG
+ */
+ public CFG(String methodName, Label start)
+ {
+ this.methodName = methodName;
+ this.nextIdx = 0;
+ this.entry = this.current = new BBlock(this, start, nextIdx++);
+ blocks = new HashMap<Label, BBlock>();
+ contains = new HashMap<BBlock, Link>();
+ labelLocations = new HashMap<Label, CodeLocation>();
+ names = new ArrayList<String>();
+ triggerStarts = new HashMap<Label, TriggerDetails>();
+ triggerEnds = new HashMap<Label, TriggerDetails>();
+ latestTrigger = null;
+ tryCatchStarts = new HashMap<Label, List<TryCatchDetails>>();
+ tryCatchEnds = new HashMap<Label, List<TryCatchDetails>>();
+ tryCatchHandlers = new HashMap<Label, List<TryCatchDetails>>();
+ openMonitorEnters = new HashMap<Label, List<CodeLocation>>();
+ monitorPairs = new HashMap<CodeLocation, List<CodeLocation>>();
+ inverseMonitorPairs = new HashMap<CodeLocation, CodeLocation>();
+ blocks.put(start, current);
+ setLocation(start);
+ contains.put(current, new Link(start));
+ openMonitorEnters.put(start, new LinkedList<CodeLocation>());
+ openTryCatchStarts = new LinkedList<TryCatchDetails>();
+ }
+
+ /*
+ * routines for managing and querying the CFG structure
+ */
+
+ /**
+ * aopend an instruction to the current block
+ * @param instruction
+ */
+ public void add(int instruction)
+ {
+ current.append(instruction);
+ }
+
+ /**
+ * append an instruction with one operand to the current block
+ * @param instruction
+ * @param operand
+ */
+ public void add(int instruction, int operand)
+ {
+ current.append(instruction, operand);
+ }
+
+ /**
+ * append an instruction with two operands to the current block
+ * @param instruction
+ * @param operand1
+ * @param operand2
+ */
+ public void add(int instruction, int operand1, int operand2)
+ {
+ current.append(instruction, operand1, operand2);
+ }
+
+ /**
+ * append an operand with more than two operands ot the current block
+ * @param instruction
+ * @param operands
+ */
+ public void add(int instruction, int[] operands)
+ {
+ current.append(instruction, operands);
+ }
+
+ /**
+ * append an instruction with a String operand to the current block
+ * @param instruction
+ * @param name
+ */
+ public void add(int instruction, String name)
+ {
+ int idx = names.indexOf(name);
+ if (idx < 0) {
+ idx = names.size();
+ names.add(name);
+ }
+ current.append(instruction, idx);
+ }
+
+ /**
+ * append a multiarray create instruction to the current block
+ * @param instruction
+ * @param name the name of the array base type
+ * @param dims the number of array dimensions
+ */
+ public void add(int instruction, String name, int dims)
+ {
+ int idx = names.indexOf(name);
+ if (idx < 0) {
+ idx = names.size();
+ names.add(name);
+ }
+ current.append(instruction, idx, dims);
+ }
+
+ /**
+ * append a field or method instruction with 3 String operands to the current block
+ * @param instruction
+ * @param name
+ */
+ public void add(int instruction, String owner, String name, String desc)
+ {
+ int idx1 = names.indexOf(owner);
+ if (idx1 < 0) {
+ idx1 = names.size();
+ names.add(owner);
+ }
+ int idx2 = names.indexOf(name);
+ if (idx2 < 0) {
+ idx2 = names.size();
+ names.add(name);
+ }
+ int idx3 = names.indexOf(desc);
+ if (idx3 < 0) {
+ idx3 = names.size();
+ names.add(desc);
+ }
+ current.append(instruction, idx1, idx2, idx3);
+ }
+
+ /**
+ * set the location of a label to the next instruction offset in the current block
+ * @param label the label whose location is to be set
+ */
+ public CodeLocation setLocation(Label label)
+ {
+ CodeLocation location = nextLocation();
+ labelLocations.put(label, location);
+ return location;
+ }
+
+ /**
+ * return the location of the label if known or null if it has not yet been reached. note that if this
+ * returns non-null then the label's offset in the generated bytecode can be safely retrieved but if it
+ * returns null then attempting to retrieve the offset will generate an exception.
+ * @param label the label whose location is desired
+ * @return the label's location if it has been reached otherwise null
+ */
+
+ public CodeLocation getLocation(Label label)
+ {
+ return labelLocations.get(label);
+ }
+
+ /**
+ * test whether the location of a label is known yet
+ * @param label the label whose location is desired
+ * @return true if the label's location has been reached otherwise false
+ */
+
+ public boolean hasLocation(Label label)
+ {
+ return (labelLocations.get(label) != null);
+ }
+
+ /**
+ * return a location which will identify the next instruction added to the current block
+ * @return the location of the next instruction added to the current block
+ */
+
+ public CodeLocation nextLocation()
+ {
+ return new CodeLocation(current, current.getInstructionCount());
+ }
+
+ /**
+ * return the block containing a label if known
+ *
+ * @param label the label whose containing block is desired
+ * @return the label's location if it has been reached otherwise null
+ */
+
+ public BBlock getBlock(Label label)
+ {
+ CodeLocation location = labelLocations.get(label);
+ if (location == null) {
+ // may not have generated code for this label yet
+ return null;
+ }
+
+ return location.getBlock();
+ }
+
+
+ /**
+ * return a link object listing all the labels contained in a given block
+ * @param block the block whose labels are being sought
+ * @return the associated set of labels
+ */
+
+ public Link getContains(BBlock block)
+ {
+ return contains.get(block);
+ }
+
+ /**
+ * add a label to the list of labels contained in a given block
+ * @param block the block whose containslist is to be updated
+ * @param label the label to be added to the list
+ */
+ private void addContains(BBlock block, Label label)
+ {
+ Link containsLink = contains.get(block);
+ if (containsLink == null) {
+ containsLink = new Link(block.getLabel());
+ contains.put(block, containsLink);
+ }
+ containsLink.append(label);
+ }
+
+ /**
+ * retrieve the list of monitor enter locations open at the start of a given block
+ * @param label the label of the block
+ * @return the list of open monitor enter locations
+ */
+ public List<CodeLocation> getOpenMonitorEnters(Label label)
+ {
+ return openMonitorEnters.get(label);
+ }
+
+ /**
+ * retrieve the list of monitor enter locations open at the start of a given block
+ * @param block the block
+ * @return the list of open monitor enter locations
+ */
+ public List<CodeLocation> getOpenMonitorEnters(BBlock block)
+ {
+ List<CodeLocation> blockMonitorEnters = null;
+
+ // if this is a handler target block then the open list can be constructed by combining the
+ // lists attached to the try catch details. these can be looked up using the handler
+ // labels
+
+ // if this is a normal block then the open list will have been attached to a GOTO label
+ // for the block which will have offset 0
+
+ // so first check the block for handler labels -- they will have offset 0
+ Link link = getContains(block);
+ int count = link.getToCount();
+ for (int i = 0; i < count; i++) {
+ Label l = link.getTo(i);
+ CodeLocation loc = getLocation(l);
+ if (loc.getInstructionIdx() == 0) {
+ // see if this is a try catch label
+ List<TryCatchDetails> detailsList = tryCatchHandlerStartDetails(l);
+ if (detailsList != null) {
+ Iterator<TryCatchDetails> iterator = detailsList.iterator();
+ while (iterator.hasNext()) {
+ TryCatchDetails details = iterator.next();
+ if (blockMonitorEnters == null) {
+ blockMonitorEnters = new LinkedList<CodeLocation>();
+ }
+ details.addOpenLocations(blockMonitorEnters);
+ }
+ }
+ }
+ }
+
+ // if that failed then look fro a control flow label with the propagated information
+ // any of them will do since they all *must* have the same open monitor list
+
+ if (blockMonitorEnters == null) {
+ for (int i = 0; i < count; i++) {
+ Label l = link.getTo(i);
+ CodeLocation loc = getLocation(l);
+ if (loc.getInstructionIdx() > 0) {
+ // nothing open on entry to this block
+ break;
+ }
+ // see if we have an inherited list
+ blockMonitorEnters = getOpenMonitorEnters(l);
+ if (blockMonitorEnters != null) {
+ break;
+ }
+ }
+ }
+
+ return blockMonitorEnters;
+ }
+
+ /**
+ * retrieve the list of monitor enter locations open at a particular trigger start location. this is called
+ * when we are inserting try catch handlers for trigger locations to determine whetehr they need
+ * to perform any monitor exit operations before executing the normal trigger exception handling code.
+ * @param triggerLocation the location of the trigger start
+ * @return the list of locations for monitor enters open at the trigger start
+ */
+ public List<CodeLocation> getOpenMonitors(CodeLocation triggerLocation)
+ {
+ BBlock block = triggerLocation.getBlock();
+ List<CodeLocation> initialMonitors = getOpenMonitorEnters(block);
+ Iterator<CodeLocation> localMonitors = block.getMonitorEnters();
+ if ((initialMonitors == null || initialMonitors.size() == 0) && (!localMonitors.hasNext())) {
+ return null;
+ }
+ Iterator<CodeLocation> localExits = block.getMonitorExits();
+ List<CodeLocation> outStanding = new LinkedList<CodeLocation>();
+ int triggerIdx = triggerLocation.getInstructionIdx();
+ if (initialMonitors != null) {
+ outStanding.addAll(initialMonitors);
+ }
+ while (localMonitors.hasNext()) {
+ CodeLocation nextLocation = localMonitors.next();
+ int nextIdx = nextLocation.getInstructionIdx();
+ if (nextIdx <= triggerIdx) {
+ outStanding.add(nextLocation);
+ }
+ }
+ while (localExits.hasNext()) {
+ CodeLocation nextLocation = localExits.next();
+ CodeLocation enterLocation = getPairedEnter(nextLocation);
+ if (enterLocation != null) {
+ int nextIdx = nextLocation.getInstructionIdx();
+ if (nextIdx <= triggerIdx) {
+ outStanding.remove(nextLocation);
+ }
+ } else {
+ System.out.println("floating monitor exit " + nextLocation);
+ }
+ }
+ return outStanding;
+ }
+
+ /**
+ * pair a monitor enter instruction with an associated monitor exit instructions
+ * @param enter
+ * @param exit
+ */
+ private void addMonitorPair(CodeLocation enter, CodeLocation exit)
+ {
+ List<CodeLocation> paired = monitorPairs.get(enter);
+ if (paired == null) {
+ paired = new LinkedList<CodeLocation>();
+ monitorPairs.put(enter, paired);
+ }
+ paired.add(exit);
+ // we also need to be abel to query this relationship in reverse order
+ CodeLocation inverse = inverseMonitorPairs.put(exit, enter);
+ }
+
+ /**
+ * locate the first monitor exit instruction associated with a given monitor enter
+ * @param enter
+ */
+ private CodeLocation getPairedExit(CodeLocation enter)
+ {
+ List<CodeLocation> paired = monitorPairs.get(enter);
+ if (paired != null) {
+ return paired.get(0);
+ }
+
+ return null;
+ }
+
+ /**
+ * locate the monitor enter instruction associated with a given monitor exit
+ * @param exit
+ */
+ private CodeLocation getPairedEnter(CodeLocation exit)
+ {
+ return inverseMonitorPairs.get(exit);
+ }
+
+ /**
+ * return the index of the local var at which this monitorenter saved its lock object
+ */
+ public int getSavedMonitorIdx(CodeLocation open)
+ {
+ // this should identify a monitorexit instruction preceded by an aload N instruction
+ BBlock block = open.getBlock();
+ int instructionIdx = open.getInstructionIdx();
+ if (instructionIdx <= 0) {
+ System.out.println("getSavedMonitorIdx : unexpected! close pair has invalid index " + instructionIdx);
+ }
+ int instruction = block.getInstruction(instructionIdx);
+ if (instruction != Opcodes.MONITORENTER) {
+ System.out.println("getSavedMonitorIdx : unexpected! close pair instruction " + instruction + " is not MONITOREXIT");
+ }
+ instruction = block.getInstruction(instructionIdx - 1);
+ if (instruction != Opcodes.ASTORE) {
+ System.out.println("getSavedMonitorIdx : unexpected! close pair preceding instruction " + instruction + " is not ASTORE");
+ }
+ int varIdx = block.getInstructionArg(instructionIdx - 1, 0);
+ if (varIdx < 0) {
+ System.out.println("getSavedMonitorIdx : unexpected! close pair preceding ASTORE instruction has invalid index " + varIdx);
+ }
+ return varIdx;
+ }
+
+ /**
+ * forward details of open monitor and try catch block locations from the current
+ * block to its reachable labels. This is always called just before splitting the current block.
+ */
+ private void carryForward()
+ {
+ if (Transformer.isVerbose()) {
+ System.out.println("Carry forward for block " + current.getBlockIdx());
+ }
+
+ Label label = current.getLabel();
+ int nOuts = current.nOuts();
+
+ // the active try start list for the block is the list of all currently open starts
+ // minus those which are closed in the block at instruction index 0
+
+ Iterator<TryCatchDetails> starts = current.getTryStarts();
+ Iterator<TryCatchDetails> ends = current.getTryEnds();
+
+ while (ends.hasNext()) {
+ TryCatchDetails details = ends.next();
+ CodeLocation location = getLocation(details.getEnd());
+ if (location.getInstructionIdx() == 0) {
+ openTryCatchStarts.remove(details);
+ }
+ }
+
+ // any remaining starts are active somewhere in the block and hence indicate
+ // possible exception control flow
+
+ current.updateActiveTryStarts(openTryCatchStarts);
+
+ if (Transformer.isVerbose()) {
+ System.out.println(current);
+ }
+
+ // the new list of open starts is the old list plus any starts opened in the block
+ // minus any ends in the block
+
+ current.carryTryStarts(openTryCatchStarts);
+ current.removeTryEnds(openTryCatchStarts);
+
+ // now update the list of outstanding monitor enters calls
+
+ Iterator<CodeLocation> entersIter = current.getMonitorEnters();
+ Iterator<CodeLocation> exitsIter = current.getMonitorExits();
+ List<CodeLocation> openEnters = getOpenMonitorEnters(current);
+ Iterator<CodeLocation> openEntersIter = (openEnters != null ? openEnters.iterator() : null);
+
+ int openEntersCount = (openEnters == null ? 0 : openEnters.size());
+ int entersCount = current.getMonitorEnterCount();
+ int exitsCount = current.getMonitorExitCount();
+
+ if (Transformer.isVerbose()) {
+ System.out.print("Carry forward open monitors for " + current.getBlockIdx() +" ==>" );
+ for (int i = 0; i < openEntersCount; i++) {
+ System.out.print(" ");
+ System.out.print(openEnters.get(i));
+ }
+ System.out.println();
+ }
+
+ // pair off any new found exits with their respective enters
+
+ LinkedList<CodeLocation> reversed = new LinkedList<CodeLocation>();
+ while (entersIter.hasNext()) {
+ reversed.addFirst(entersIter.next());
+ }
+ entersIter = reversed.iterator();
+
+ while (exitsIter.hasNext() && entersIter.hasNext()) {
+ CodeLocation exit = exitsIter.next();
+ CodeLocation enter = entersIter.next();
+ addMonitorPair(enter, exit);
+ }
+
+ // if all is right then this test should not be needed
+ if (openEntersIter != null) {
+ reversed = new LinkedList<CodeLocation>();
+ while (openEntersIter.hasNext()) {
+ reversed.addFirst(openEntersIter.next());
+ }
+ openEntersIter = reversed.iterator();
+
+ while (exitsIter.hasNext() && openEntersIter.hasNext()) {
+ CodeLocation exit = exitsIter.next();
+ CodeLocation enter = openEntersIter.next();
+ addMonitorPair(enter, exit);
+ }
+ } else {
+ if (exitsIter.hasNext()) {
+ System.out.println("exits unaccounted for in block B" + current.getBlockIdx());
+ }
+ }
+
+ // any left over values are still open
+
+ List<CodeLocation> newOpenEnters = new LinkedList<CodeLocation>();
+
+ while (entersIter.hasNext()) {
+ newOpenEnters.add(entersIter.next());
+ }
+
+ if (openEntersIter != null) {
+ while (openEntersIter.hasNext()) {
+ newOpenEnters.add(openEntersIter.next());
+ }
+ }
+
+ int newOpenCount = newOpenEnters.size();
+
+ // ok, now attach the list to all reachable blocks
+
+ // first the blocks reachable via jump links
+
+ // n.b. link 0 is the next block in line, if it is reachable then it will also appear as a later link
+ // so we start the iteration from 1
+
+ for (int i = 1; i <= nOuts; i++) {
+ label = current.nthOut(i);
+ openEnters = openMonitorEnters.get(label);
+ if (openEnters == null) {
+ openMonitorEnters.put(label, newOpenEnters);
+ if (Transformer.isVerbose()) {
+ System.out.print("open monitors " + label + " ==>");
+ for (int j = 0; j < newOpenCount; j++) {
+ CodeLocation l = newOpenEnters.get(j);
+ System.out.print(" BB");
+ System.out.print(l.getBlock().getBlockIdx());
+ System.out.print(".");
+ System.out.print(l.getInstructionIdx());
+ }
+ System.out.println();
+ }
+ } else {
+ // sanity check
+ // this should contain the same locations as our current list!
+ if (openEnters.size() != newOpenCount) {
+ System.out.println("invalid open enters count for block " + label);
+ }
+ for (int j = 0; j < newOpenCount; j++) {
+ CodeLocation l1 = openEnters.get(j);
+ CodeLocation l2 = newOpenEnters.get(j);
+ if (l1.getBlock() != l2.getBlock()) {
+ System.out.println("invalid open enters block for block " + label + " at index " + j);
+ }
+ if (l1.getInstructionIdx() != l2.getInstructionIdx()) {
+ System.out.println("invalid open enters instruction index for block " + label + " at index " + j);
+ }
+ }
+ }
+ }
+
+ // now propagate open monitors to handler blocks reachable via thrown exceptions
+ // we need to be conservative here. a handler block may not actually be reachable because another
+ // try catch block with a generic exception type shadows it.
+
+ Iterator<CodeLocation> newOpenIter = newOpenEnters.iterator();
+
+ // for each open enter check if any of the currently open try catch blocks is enclosed by the
+ // enter and its first exit (n.b. the latter is inclusive). if so then attach the open
+ // to the try catch details. a pseudo handler should be found later which closes the monitor
+ // and rethrows
+
+ while (newOpenIter.hasNext()) {
+ CodeLocation enter = newOpenIter.next();
+ Iterator<TryCatchDetails> activeStarts = current.getActiveTryStarts();
+ while (activeStarts.hasNext()) {
+ TryCatchDetails details = activeStarts.next();
+ if (details.containsOpenEnter(enter)) {
+ // ignore
+ continue;
+ }
+ CodeLocation tryStart = getLocation(details.getStart());
+ if (enter.compareTo(tryStart) <= 0) {
+ // try start is after the enter -- now see where the corresponding exit is
+
+ CodeLocation exit = getPairedExit(enter);
+ if (exit != null && tryStart.compareTo(exit) <= 0) {
+ // open is in scope of try catch so attach it to the try start
+ details.addOpenEnter(enter);
+ }
+ }
+ }
+ }
+
+ // do the same for each enter opened in the current block
+
+ newOpenIter = current.getMonitorEnters();
+
+ while (newOpenIter.hasNext()) {
+ CodeLocation enter = newOpenIter.next();
+ Iterator<TryCatchDetails> activeStarts = current.getActiveTryStarts();
+ while (activeStarts.hasNext()) {
+ TryCatchDetails details = activeStarts.next();
+ if (details.containsOpenEnter(enter)) {
+ // ignore
+ continue;
+ }
+ CodeLocation tryStart = getLocation(details.getStart());
+ if (enter.compareTo(tryStart) <= 0) {
+ // try start is after the enter -- now see where the corresponding exit is
+
+ CodeLocation exit = getPairedExit(enter);
+ if (exit != null && tryStart.compareTo(exit) <= 0) {
+ // open is in scope of try catch so attach it to the try start
+ details.addOpenEnter(enter);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * split the graph at a control-flow dead-end using the label provided to identify the new current
+ * block. the caller is obliged to call visitLabel immediately after calling this method to ensure
+ * that the current block label is indexed appropriately.
+ *
+ * @param newStart the label to be used to identify the new current block
+ */
+ public void split(Label newStart)
+ {
+ current.append(newStart);
+ // carry forward any open monitor enter locations and update the open try start list
+ carryForward();
+ current = new BBlock(this, newStart, nextIdx++);
+ blocks.put(newStart, this.current);
+ }
+
+ /**
+ * split the graph at a control-flow goto point using the labels provided to identify the new current
+ * block and the goto target. the caller is obliged to call visitLabel immediately after calling this
+ * method to ensure that the current block label is indexed appropriately.
+ *
+ * @param newStart the label to be used to identify the new current block
+ * @param out the target of the GOTO
+ */
+ public void split(Label newStart, Label out)
+ {
+ current.append(newStart);
+ current.append(out);
+ // carry forward any open monitor enter locations and update the open try start list
+ carryForward();
+ current = new BBlock(this, newStart, nextIdx++);
+ blocks.put(newStart, this.current);
+ }
+
+ /**
+ * split the graph at a control-flow if branch point using the labels provided to identify the new current
+ * block the if branch target and the else branch target. the caller is obliged to call visitLabel
+ * immediately after calling this method to ensure that the current block label is indexed appropriately.
+ *
+ * @param newStart the label to be used to identify the new current block
+ * @param out the target of the if branch
+ * @param out2 the target of the else branch which probably ought to be the same label as passed for the
+ * current block (IF instructions assume drop-through)
+ */
+ public void split(Label newStart, Label out, Label out2)
+ {
+ current.append(newStart);
+ current.append(out);
+ current.append(out2);
+ // carry forward any open monitor enter locations and update the open try start list
+ carryForward();
+ current = new BBlock(this, newStart, nextIdx++);
+ blocks.put(newStart, current);
+ }
+
+ /**
+ * split the graph at a control-flow switch branch point using the labels provided to identify the new
+ * current block, the switch case default branch target and the rest of the switch case branch targets.
+ * the caller is obliged to call visitLabel immediately after calling this method to ensure that the
+ * current block label is indexed appropriately.
+ *
+ * @param newStart the label to be used to identify the new current block
+ * @param dflt the switch case default branch target
+ * @param labels the other switch case branch targets
+ */
+
+ public void split(Label newStart, Label dflt, Label[] labels)
+ {
+ current.append(newStart);
+ current.append(dflt);
+ for (int i = 0; i < labels.length ; i++) {
+ current.append(labels[i]);
+ }
+ // carry forward any open monitor enter locations and update the open try start list
+ carryForward();
+ current = new BBlock(this, newStart, nextIdx++);
+ blocks.put(newStart, this.current);
+ }
+
+ /**
+ * test if a label marks the start of a try catch block
+ * @param label the label to be tested
+ * @return true if the label marks the start of a try catch block otherwise false
+ */
+ public boolean tryCatchStart(Label label)
+ {
+ return tryCatchStarts.containsKey(label);
+ }
+
+ /**
+ * test if a label marks the end of a try catch block
+ * @param label the label to be tested
+ * @return true if the label marks the start of a try catch block otherwise false
+ */
+ public boolean tryCatchEnd(Label label)
+ {
+ return tryCatchEnds.containsKey(label);
+ }
+
+ /**
+ * test if a label marks the start of the handler for a try catch block
+ * @param label the label to be tested
+ * @return true if the label marks the start of a try catch block otherwise false
+ */
+ public boolean tryCatchHandlerStart(Label label)
+ {
+ return tryCatchHandlers.containsKey(label);
+ }
+
+ /**
+ * return the list of details of try catch blocks which start at this label
+ * @param label
+ * @return
+ */
+ public List<TryCatchDetails> tryCatchStartDetails(Label label)
+ {
+ return tryCatchStarts.get(label);
+ }
+
+ /**
+ * return the list of details of try catch blocks which end at this label
+ * @param label
+ * @return
+ */
+ public List<TryCatchDetails> tryCatchEndDetails(Label label)
+ {
+ return tryCatchEnds.get(label);
+ }
+
+ /**
+ * return the list of details of try catch blocks whose handler startsend at this label
+ * @param label
+ * @return
+ */
+ public List<TryCatchDetails> tryCatchHandlerStartDetails(Label label)
+ {
+ return tryCatchHandlers.get(label);
+ }
+
+ /**
+ * test if a label marks the start of a trigger block
+ * @param label the label to be tested
+ * @return true if the label marks the start of a trigger block otherwise false
+ */
+ public boolean triggerStart(Label label)
+ {
+ return triggerStarts.containsKey(label);
+ }
+
+ /**
+ * test if a label marks the end of a trigger block
+ * @param label the label to be tested
+ * @return true if the label marks the start of a trigger block otherwise false
+ */
+ public boolean triggerEnd(Label label)
+ {
+ return triggerEnds.containsKey(label);
+ }
+
+ /**
+ * return details of any trigger block which starts at this label
+ * @param label
+ * @return
+ */
+ public TriggerDetails triggerStartDetails(Label label)
+ {
+ return triggerStarts.get(label);
+ }
+
+ /**
+ * return the list of details of try catch blocks which end at this label
+ * @param label
+ * @return
+ */
+ public TriggerDetails triggerEndDetails(Label label)
+ {
+ return triggerEnds.get(label);
+ }
+
+ /**
+ * return an iterator ovver all known trigger detailsd
+ * @return
+ */
+ public Iterator<TriggerDetails> triggerDetails()
+ {
+ return triggerStarts.values().iterator();
+ }
+
+ /**
+ * notify the CFG that a label has been visited by the method visitor and hence its position will now
+ * be resolved
+ * @param label
+ */
+ public void visitLabel(Label label)
+ {
+ // record the label's location in the current block
+
+ addContains(current, label);
+
+ // now we need to add a block location for this label
+
+ CodeLocation location = setLocation(label);
+
+ // if this is a try catch block start, end or handler label then we need to update the list
+ // maintained in each block
+
+ List<TryCatchDetails> details = tryCatchStartDetails(label);
+
+ if (details != null) {
+ current.addTryStarts(details);
+ }
+
+ details = tryCatchEndDetails(label);
+
+ if (details != null) {
+ current.addTryEnds(details);
+ }
+
+ details = tryCatchHandlerStartDetails(label);
+
+ if (details != null) {
+ current.addTryHandlerStarts(details);
+ }
+ }
+
+ /**
+ * notify the CFG that a label which represents the start of a trigger injection sequence has just been visited
+ * by the method visitor.
+ * @param label
+ */
+ public void visitTriggerStart(Label label)
+ {
+ // we normally only see one trigger start for a given trigger adapter run but in the
+ // case of an AT EXIT trigger adapter we may see multiple trigger starts
+
+ latestTrigger = new TriggerDetails(this, label);
+ triggerStarts.put(label, latestTrigger);
+ }
+
+ /**
+ * notify the CFG that a label which represents the end of a trigger injection sequence has just been visited
+ * by the method visitor.
+ * @param label
+ */
+ public void visitTriggerEnd(Label label)
+ {
+ // we normally only see one trigger end for a given trigger adaoter run but in the
+ // case of an AT EXIT trigger adapter we may see multiple trigger ends
+
+ latestTrigger.setEnd(label);
+ triggerEnds.put(label, latestTrigger);
+ }
+
+ /**
+ * notify the CFG of the location of a try catch block. note that this does not mean that the code
+ * generator has been notified of this information. these are normally notified to the method visitor
+ * before visiting the code. this is problematic if we want to insert our trigger point try catch
+ * blocks because we need to order them before any enclosing try catch blocks with wider scope. so the
+ * method visitor calls this routine up front but only notifies the try catch block to its super when
+ * the end label for the try catch block is reached.
+ *
+ * @param start
+ * @param end
+ * @param handler
+ * @param type
+ */
+ public void visitTryCatchBlock(Label start, Label end, Label handler, String type)
+ {
+ // hmm, we need to store this info so we can track it later
+ boolean isTriggerHandler = triggerStarts.containsKey(start);
+ TryCatchDetails details = new TryCatchDetails(this, start, end, handler, type, isTriggerHandler);
+
+ // each label should only ever correspond to a single code location but we may see the same label
+ // associated with more than one tryCatchBlock notification so the index links are 1:m
+ List<TryCatchDetails> detailsList = tryCatchStarts.get(start);
+ if (detailsList == null) {
+ detailsList = new LinkedList<TryCatchDetails>();
+ tryCatchStarts.put(start, detailsList);
+ }
+ detailsList.add(details);
+
+ detailsList = tryCatchEnds.get(end);
+ if (detailsList == null) {
+ detailsList = new LinkedList<TryCatchDetails>();
+ tryCatchEnds.put(end, detailsList);
+ }
+ detailsList.add(details);
+
+ detailsList = tryCatchHandlers.get(handler);
+ if (detailsList == null) {
+ detailsList = new LinkedList<TryCatchDetails>();
+ tryCatchHandlers.put(handler, detailsList);
+ }
+ detailsList.add(details);
+ }
+
+ /**
+ * return true if the current block is a rethrow handler i.e. one which was created to close a monitor
+ * exit instruction and then rethrow an exception. n.b. this must only be called when the next instruction
+ * to be added to the byetcode sequence is an ATHROW
+ * @return
+ */
+ public boolean inRethrowHandler()
+ {
+ int nextIdx = current.getInstructionCount();
+ // a compiler generated rethrow block always has the same format
+ // astore N1
+ // aload N2
+ // monitorexit
+ // aload N1
+ // athrow
+ if ((nextIdx >= 4) &&
+ current.getInstruction(nextIdx - 1) == Opcodes.ALOAD &&
+ current.getInstruction(nextIdx - 2) == Opcodes.MONITOREXIT &&
+ current.getInstruction(nextIdx - 3) == Opcodes.ALOAD &&
+ current.getInstruction(nextIdx - 4) == Opcodes.ASTORE &&
+ current.getInstructionArg(nextIdx - 1, 0) == current.getInstructionArg(nextIdx - 4, 0)) {
+ return true;
+ }
+
+ // a rethrow block generated by byteman has the simpler format
+ // aload N1
+ // monitorexit
+ // athrow
+ if ((nextIdx >= 2) &&
+ current.getInstruction(nextIdx - 1) == Opcodes.MONITOREXIT &&
+ current.getInstruction(nextIdx - 2) == Opcodes.ALOAD) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * this can be called when the code generator call visiMaxs but it does nothing just now
+ */
+ public void visitMaxs()
+ {
+ // nothing to do just here
+ }
+
+ public void visitEnd()
+ {
+ // we don't need to do anything here to but for now just dump the CFG if we are verbose
+
+ if (Transformer.isVerbose()) {
+ System.out.println(this);
+ }
+ }
+
+ /**
+ * generate a string representation of the CFG
+ * @return
+ */
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append("Control Flow Graph for ");
+ buf.append(methodName);
+ buf.append("\n");
+ BBlock next = entry;
+ while (next != null) {
+ next.printTo(buf);
+ next = blocks.get(next.next());
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * return the index of the label in its enclosing block's instruction sequence of -1 if the
+ * label has not yet been visited. the index can be used to lookup the insruction following
+ * the label.
+ * @param label
+ * @return
+ */
+ public int getBlockInstructionIdx(Label label)
+ {
+ CodeLocation location = labelLocations.get(label);
+ if (location == null) {
+ // may not have generated code for this label yet
+ return -1;
+ }
+
+ return location.getInstructionIdx();
+ }
+
+ public String getName(int nameIdx)
+ {
+ return names.get(nameIdx);
+ }
+}
+
Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/CodeLocation.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/CodeLocation.java (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/CodeLocation.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -0,0 +1,65 @@
+package org.jboss.jbossts.orchestration.agent.adapter.cfg;
+
+/**
+ * a reference to a specific instruction location in a given BBlock
+ */
+public class CodeLocation implements Comparable<CodeLocation>
+{
+ /**
+ * the basic block containing the instruction
+ */
+ private BBlock block;
+ /**
+ * the index of the instruction in the basic block's instruction sequence
+ */
+ private int instructionIdx;
+
+ public CodeLocation(BBlock block, int instructionIdx)
+ {
+ this.block = block;
+ this.instructionIdx = instructionIdx;
+ }
+
+ public BBlock getBlock()
+ {
+ return block;
+ }
+
+ public int getInstructionIdx()
+ {
+ return instructionIdx;
+ }
+
+ public String toString()
+ {
+ return "B" + block.getBlockIdx() + "." + getInstructionIdx();
+ }
+
+ public int compareTo(CodeLocation loc)
+ {
+ int blockIdx = block.getBlockIdx();
+ int otherBlockIdx = loc.block.getBlockIdx();
+ if (blockIdx < otherBlockIdx) {
+ return -1;
+ } else if (blockIdx > otherBlockIdx) {
+ return 1;
+ } else {
+ if (instructionIdx < loc.instructionIdx) {
+ return -1;
+ } else if (instructionIdx > loc.instructionIdx) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o instanceof CodeLocation) {
+ return (compareTo((CodeLocation) o) == 0);
+ } else {
+ return false;
+ }
+ }
+}
Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/InstructionSequence.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/InstructionSequence.java (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/InstructionSequence.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -0,0 +1,218 @@
+package org.jboss.jbossts.orchestration.agent.adapter.cfg;
+
+import org.jboss.jbossts.orchestration.agent.adapter.OpcodesHelper;
+
+/**
+ * Class used to hold a sequence of instructions within a basic block
+ */
+public class InstructionSequence
+{
+ /**
+ * since instructions are encoded with their operands we need an offsets array to identify
+ * where each instruction strats, allowing instructions and their operand to be searched
+ * forwards and backwards
+ */
+ private int[] instructionOffsets;
+
+ /**
+ * the number of valid offsets to instrctions in array instructionOffsets
+ */
+
+ private int numInstructions;
+
+ /**
+ * data array storing instructions and their operands encoded as ints.
+ *
+ * integer operands are embedded as is
+ * operands which are strings (type, const, field etc) must be translated via the names array in
+ * the associated cfg.
+ * operands which are jump labels msut be translated by calling getNthOut() on the associated
+ * basic block.
+ * n.b. all basic blocks are terminated by a jump instruction so when this class is used to encode
+ * instructions in a basic block or in the terminal basic block of a path the encoded argument
+ * is always -1. when it is used to encode instructions in a basic block in some initial segment of a
+ * path the encoded argument identifies the out path from the branch and will be a non-negative integer.
+ * It can be converted to a block start label by calling BBlock.nthOut(arg)
+ */
+ private int[] encodedInstructions;
+
+ /**
+ * the number of valid entries in array encodedInstructions
+ */
+
+ private int numEncoded;
+
+ /**
+ * expand the offsets array if necessary to allow room for 1 more instructions with count more arguments
+ */
+ private void ensureSpace(int count)
+ {
+ int length = instructionOffsets.length;
+ if (numInstructions == length) {
+ int[] newOffsets = new int[length * 2];
+ for (int i = 0; i < numInstructions; i++) {
+ newOffsets[i] = instructionOffsets[i];
+ }
+ instructionOffsets = newOffsets;
+ }
+ // we need room for the instruction and count args
+ length = encodedInstructions.length;
+ if (numEncoded + count + 1 >= length) {
+ int[] newEncoded = new int[length * 2];
+ for (int i = 0; i < numEncoded; i++) {
+ newEncoded[i] = encodedInstructions[i];
+ }
+ encodedInstructions = newEncoded;
+ }
+ }
+
+ public InstructionSequence()
+ {
+ instructionOffsets = new int[3];
+ encodedInstructions = new int[6];
+ }
+
+ /**
+ * return the number of instructions in the sequence
+ *
+ * @return the the number of instructions in the sequence
+ */
+ public int size()
+ {
+ return numInstructions;
+ }
+
+ /**
+ * return the instruction at the supplied offset
+ *
+ * @return the ith instruction in the sequuence
+ */
+ public int get(int i)
+ {
+ int offset = instructionOffsets[i];
+ return encodedInstructions[offset];
+ }
+
+ /**
+ * return the type of a given instruction
+ *
+ * @return the ith instruction in the sequuence
+ */
+ public int getType(int i)
+ {
+ int offset = instructionOffsets[i];
+ int insn = encodedInstructions[offset];
+ return OpcodesHelper.insnType(insn);
+ }
+
+ /**
+ * return the number of encoded arguments of a given instruction
+ * @param i the offset of the instruction
+ *
+ * @return the number of encoded arguments of the ith instruction in the sequuence
+ */
+ public int getArgCount(int i)
+ {
+ int offset = instructionOffsets[i];
+ int nextOffset;
+ if (offset == numInstructions - 1) {
+ nextOffset = numEncoded;
+ } else {
+ nextOffset = instructionOffsets[i + 1];
+ }
+
+ return (nextOffset - (offset + 1));
+ }
+
+ /**
+ * return a specific encoded argument of a given instruction
+ * @param i the offset of the instruction
+ * @param j the index of the arguument attached to the instruction
+ *
+ * @return the jth encoded argument of the ith instruction in the sequuence
+ */
+ public int getArg(int i, int j)
+ {
+ int offset = instructionOffsets[i];
+ return encodedInstructions[offset + j + 1];
+ }
+
+ /**
+ * add an instruction to the sequence
+ * @param insn
+ * @return the index of the newly added instruction
+ */
+ public int add(int insn)
+ {
+ int result = numInstructions;
+ ensureSpace(0);
+ instructionOffsets[numInstructions++] = numEncoded;
+ encodedInstructions[numEncoded++] = insn;
+ return result;
+ }
+
+ /**
+ * add an instruction with one encoded argument to the sequence
+ * @param insn
+ * @return the index of the newly added instruction
+ */
+ public int add(int insn, int arg1)
+ {
+ int result = numInstructions;
+ ensureSpace(1);
+ instructionOffsets[numInstructions++] = numEncoded;
+ encodedInstructions[numEncoded++] = insn;
+ encodedInstructions[numEncoded++] = arg1;
+ return result;
+ }
+
+ /**
+ * add an instruction with two encoded arguments to the sequence
+ * @param insn
+ * @return the index of the newly added instruction
+ */
+ public int add(int insn, int arg1, int arg2)
+ {
+ int result = numInstructions;
+ ensureSpace(2);
+ instructionOffsets[numInstructions++] = numEncoded;
+ encodedInstructions[numEncoded++] = insn;
+ encodedInstructions[numEncoded++] = arg1;
+ encodedInstructions[numEncoded++] = arg2;
+ return result;
+ }
+
+ /**
+ * add an instruction with three encoded arguments to the sequence
+ * @param insn
+ * @return the index of the newly added instruction
+ */
+ public int add(int insn, int arg1, int arg2, int arg3)
+ {
+ int result = numInstructions;
+ ensureSpace(3);
+ instructionOffsets[numInstructions++] = numEncoded;
+ encodedInstructions[numEncoded++] = insn;
+ encodedInstructions[numEncoded++] = arg1;
+ encodedInstructions[numEncoded++] = arg2;
+ encodedInstructions[numEncoded++] = arg3;
+ return result;
+ }
+
+ /**
+ * add an instruction with an arbitrary number of encoded arguments to the sequence
+ * @param insn
+ * @return the index of the newly added instruction
+ */
+ public int add(int insn, int[] args)
+ {
+ int result = numInstructions;
+ ensureSpace(args.length);
+ instructionOffsets[numInstructions++] = numEncoded;
+ encodedInstructions[numEncoded++] = insn;
+ for (int i = 0; i < args.length; i++) {
+ encodedInstructions[numEncoded++] = args[i];
+ }
+ return result;
+ }
+}
Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/Link.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/Link.java (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/Link.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -0,0 +1,107 @@
+package org.jboss.jbossts.orchestration.agent.adapter.cfg;
+
+import org.objectweb.asm.Label;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Iterator;
+
+/**
+ * A representation of a 1:M relation between labels/code locations. This is used to represent
+ * branchouts in a CFG where the 1 is the label of the BBlock and the M lists outgoing normal
+ * (non-exception) control flow. It is also used to represent the relationship between basic
+ * blocks (identified by their primary label) and labels identifying instructions contained in
+ * the block. Note that in the former case the use of labels allows control flow linkes to basic
+ * blocks which have not yet been generated to be recorded.
+ */
+public class Link
+{
+ /**
+ * the 1 in the 1:m
+ */
+ private Label from;
+ /**
+ * the m in the 1:m
+ */
+ private List<Label> to;
+
+ /**
+ * construct a new empty link
+ * @param from
+ */
+ public Link(Label from)
+ {
+ this.from = from;
+ this.to = new LinkedList<Label>();
+ }
+
+ /**
+ * construct a new link with one element in the target set
+ * @param from
+ * @param to
+ */
+ public Link(Label from, Label to)
+ {
+ this(from);
+ append(to);
+ }
+
+ /**
+ * construct a new link with two elements in the target set
+ * @param from
+ * @param to1
+ * @param to2
+ */
+ public Link(Label from, Label to1, Label to2)
+ {
+ this(from);
+ append(to1);
+ append(to2);
+ }
+
+ public Label getFrom()
+ {
+ return from;
+ }
+
+ /**
+ * add a new link to the target set
+ * @param to
+ */
+ public void append(Label to)
+ {
+ this.to.add(to);
+ }
+
+ /**
+ * retrieve alink from the target set by index
+ * @param i
+ * @return
+ */
+ public Label getTo(int i)
+ {
+ if (to.size() > i) {
+ return to.get(i);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * retrieve the size of the target set
+ * @return
+ */
+ public int getToCount()
+ {
+ return to.size();
+ }
+
+ /**
+ * obtain an iterator over the target set
+ * @return
+ */
+ public Iterator<Label> iterator()
+ {
+ return to.iterator();
+ }
+}
Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/TriggerDetails.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/TriggerDetails.java (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/TriggerDetails.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -0,0 +1,95 @@
+package org.jboss.jbossts.orchestration.agent.adapter.cfg;
+
+import org.objectweb.asm.Label;
+
+import java.util.LinkedList;
+
+/**
+ * auxiliary used by CFG to store details of a specific trigger insertion point
+ */
+public class TriggerDetails
+{
+ /**
+ * back link to the flow graph
+ */
+ private CFG cfg;
+
+ /**
+ * the label identifying the start of the trigger sequence injected into the bytecode
+ */
+ private Label start;
+
+ /**
+ * the label identifying the end of the trigger sequence injected into the bytecode
+ */
+ private Label end;
+
+ /**
+ * the label identifying the start of the handler block for any ReturnException thrown by the trigger call
+ */
+ private Label earlyReturnHandler;
+
+ /**
+ * the label identifying the start of the handler block for any ThrowException thrown by the trigger call
+ */
+ private Label throwHandler;
+
+ /**
+ * the label identifying the start of the handler block for any ExecuteException thrown by the trigger call
+ */
+ private Label executeHandler;
+
+ /**
+ * construct a new trigger details instance
+ * @param cfg
+ * @param start
+ */
+ public TriggerDetails(CFG cfg, Label start)
+ {
+ this.cfg = cfg;
+ this.start = start;
+ this.end = null;
+ }
+
+ // accessors
+
+ public Label getStart() {
+ return start;
+ }
+
+ public void setStart(Label start) {
+ this.start = start;
+ }
+
+ public Label getEnd() {
+ return end;
+ }
+
+ public void setEnd(Label end) {
+ this.end = end;
+ }
+
+ public Label getExecuteHandler() {
+ return executeHandler;
+ }
+
+ public void setExecuteHandler(Label executeHandler) {
+ this.executeHandler = executeHandler;
+ }
+
+ public Label getEarlyReturnHandler() {
+ return earlyReturnHandler;
+ }
+
+ public void setEarlyReturnHandler(Label earlyReturnHandler) {
+ this.earlyReturnHandler = earlyReturnHandler;
+ }
+
+ public Label getThrowHandler() {
+ return throwHandler;
+ }
+
+ public void setThrowHandler(Label throwHandler) {
+ this.throwHandler = throwHandler;
+ }
+}
\ No newline at end of file
Added: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/TryCatchDetails.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/TryCatchDetails.java (rev 0)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/agent/adapter/cfg/TryCatchDetails.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -0,0 +1,117 @@
+package org.jboss.jbossts.orchestration.agent.adapter.cfg;
+
+import org.objectweb.asm.Label;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Iterator;
+
+/**
+ * auxiliary used by CFG to store details of a specific try catch block
+ */
+public class TryCatchDetails
+{
+ /**
+ * back link to the control flow graph
+ */
+ private CFG cfg;
+ /**
+ * the label identifying the start of the try catch block
+ */
+ private Label start;
+ /**
+ * the label identifying the end of the try catch block
+ */
+ private Label end;
+ /**
+ * the label identifying the start of the try catch block handler
+ */
+ private Label handler;
+ /**
+ * a list of monitor enter instructions which are still open on entry to this try catch block
+ * and hence which may require closing in the associated handler
+ */
+ private List<CodeLocation> openEnters;
+ /**
+ * the name of the exception type handled by the handler or null if it is a catch all handler
+ */
+ private String type;
+ /**
+ * true if this is a trigger handler otherwise false
+ */
+ private boolean isTriggerHandler;
+
+ /**
+ * construct a try catch details instance
+ * @param cfg
+ * @param start
+ * @param end
+ * @param handler
+ * @param type
+ * @param isTriggerHandler
+ */
+ public TryCatchDetails(CFG cfg, Label start, Label end, Label handler, String type, boolean isTriggerHandler)
+ {
+ this.cfg = cfg;
+ this.start = start;
+ this.end = end;
+ this.handler = handler;
+ this.openEnters = new LinkedList<CodeLocation>();
+ this.type = type;
+ this.isTriggerHandler = isTriggerHandler;
+ }
+
+ // accessors
+
+ public Label getStart() {
+ return start;
+ }
+
+ public Label getEnd() {
+ return end;
+ }
+
+ public Label getHandler() {
+ return handler;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public boolean isTriggerHandler() {
+ return isTriggerHandler;
+ }
+
+ /**
+ * add a new monitor enter location to the list of open locations associated with this handler
+ * @param openEnter
+ */
+ public void addOpenEnter(CodeLocation openEnter)
+ {
+ openEnters.add(openEnter);
+ }
+
+ /**
+ * check if a monitor enter location belongs to the list of open locations associated with this handler
+ * @param openEnter
+ */
+ public boolean containsOpenEnter(CodeLocation openEnter)
+ {
+ return openEnters.contains(openEnter);
+ }
+
+ /**
+ * add all the open locations associated with this handler to the supplied list of open locations
+ * @param openMonitorEnters
+ */
+ public void addOpenLocations(List<CodeLocation> openMonitorEnters) {
+ Iterator<CodeLocation> iterator = openEnters.iterator();
+ while (iterator.hasNext()) {
+ CodeLocation location = iterator.next();
+ if (!openMonitorEnters.contains(location)) {
+ openMonitorEnters.add(location);
+ }
+ }
+ }
+}
Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/RuleElement.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/RuleElement.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/RuleElement.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -383,7 +383,13 @@
}
if (toType.isAssignableFrom(fromType)) {
- // nothing more to do
+ // special case -- isAssignableFrom says yes if we are trying to assign to a String but
+ // we may still need to do a toString cobversion all the same
+ if (toType == Type.STRING && fromType != Type.STRING) {
+ compileStringConversion(fromType, toType, mv, currentStackHeights, maxStackHeights);
+ } else {
+ // nothing more to do
+ }
} else {
// this happens when we downcast a bound variable from Object to the variable's type
assert fromType.isAssignableFrom(toType);
Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ReturnExpression.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ReturnExpression.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/expression/ReturnExpression.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -170,7 +170,7 @@
public void compile(MethodVisitor mv, StackHeights currentStackHeights, StackHeights maxStackHeights) throws CompileException
{
- Type returnType = returnValue.getType();
+ Type returnType = (returnValue == null ? Type.VOID : returnValue.getType());
int currentStack = currentStackHeights.stackCount;
int expected = 1;
int extraSlots = 0;
Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/helper/Helper.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/helper/Helper.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/rule/helper/Helper.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -259,11 +259,19 @@
// countdown support
/**
+ * for backwards compatibility
+ */
+ public boolean getCountDown(Object identifier)
+ {
+ return isCountDown(identifier);
+ }
+
+ /**
* builtin to test test if a countdown has been installed
* @param identifier an object which uniquely identifies the countdown in question
* @return true if the countdown is currently installed
*/
- public boolean getCountDown(Object identifier)
+ public boolean isCountDown(Object identifier)
{
synchronized (countDownMap) {
return (countDownMap.get(identifier) != null);
@@ -430,15 +438,31 @@
}
/**
- * call signalKill(Object, boolean) defaulting the second argument to
- * false
+ * for backwards compatibility
*/
public boolean signalKill(Object identifier)
{
- return signalKill(identifier, false);
+ return signalThrow(identifier);
}
/**
+ * for backwards compatibility
+ */
+ public boolean signalKill(Object identifier, boolean mustMeet)
+ {
+ return signalThrow(identifier, mustMeet);
+ }
+
+ /**
+ * call signalThrow(Object, boolean) defaulting the second argument to
+ * false
+ */
+ public boolean signalThrow(Object identifier)
+ {
+ return signalThrow(identifier, false);
+ }
+
+ /**
* signal an event identified by the suppied object, causing all waiting threads to throw an
* exception and clearing the event. if there are no objects waiting, either because there has been
* no call to @link{#waitFor} or because some other thread has already sent the signal, then this
@@ -452,13 +476,13 @@
* thread is actually waiting on a waiter identified by identifier. if there is no such waiter
* when this method is called then the calling thread will suspend until one arrives.
*/
- public boolean signalKill(Object identifier, boolean mustMeet)
+ public boolean signalThrow(Object identifier, boolean mustMeet)
{
if (mustMeet == false) {
Waiter waiter = removeWaiter(identifier);
if (waiter != null) {
- return waiter.signalKill();
+ return waiter.signalThrow();
}
return false;
@@ -470,7 +494,7 @@
waiter = removeWaiter(identifier);
if (waiter != null) {
- return waiter.signalKill();
+ return waiter.signalThrow();
} else {
// insert a pre-signalled waiter
waiter = new Waiter(identifier, true, false);
@@ -509,16 +533,6 @@
}
}
- /**
- * create a counter identified by the given object with count 0 as its initial count
- * @param o an identifier used to refer to the counter in future
- * @return true if a new counter was created and false if one already existed under the given identifier
- */
- public boolean createCounter(Object o)
- {
- return createCounter(o, 0);
- }
-
// rendezvous support
/**
* call createRendezvous(Object, int, boolean) supplying false for the last parameter
@@ -557,6 +571,19 @@
* test whether a rendezvous with a specific expected count is associated with identifier
* @param identifier the identifier for the rendezvous
* @param expected the number of threads expected to meet at the rendezvous
+ * @return true if the endezvous exists and is active otherwise false
+ */
+ public boolean isRendezvous(Object identifier, int expected)
+ {
+ int arrived = getRendezvous(identifier, expected);
+
+ return (arrived >= 0 && arrived < expected);
+ }
+
+ /**
+ * test whether a rendezvous with a specific expected count is associated with identifier
+ * @param identifier the identifier for the rendezvous
+ * @param expected the number of threads expected to meet at the rendezvous
* @return the numer of threads currently arrived at the rendezvous
*/
public int getRendezvous(Object identifier, int expected)
@@ -565,7 +592,7 @@
if (rendezvous == null || rendezvous.getExpected() != expected) {
return -1;
}
-
+
return rendezvous.getArrived();
}
@@ -629,6 +656,16 @@
// counter support
/**
+ * create a counter identified by the given object with count 0 as its initial count
+ * @param o an identifier used to refer to the counter in future
+ * @return true if a new counter was created and false if one already existed under the given identifier
+ */
+ public boolean createCounter(Object o)
+ {
+ return createCounter(o, 0);
+ }
+
+ /**
* create a counter identified by the given object with the supplied value as its iniital count
* @param o an identifier used to refer to the counter in future
* @param value the initial value for the counter
Modified: labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/synchronization/Waiter.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/synchronization/Waiter.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/src/org/jboss/jbossts/orchestration/synchronization/Waiter.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -82,7 +82,7 @@
return result;
}
- public boolean signalKill()
+ public boolean signalThrow()
{
boolean result;
Modified: labs/jbosstm/workspace/adinn/orchestration/tests/build.xml
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/tests/build.xml 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/tests/build.xml 2009-06-03 10:48:41 UTC (rev 26809)
@@ -111,6 +111,19 @@
<pathelement location="${build.lib.dir}/orchestration-tests.jar"/>
<pathelement location="${junit.home}/${junit.jar}"/>
</classpath>
+ <!-- uncomment for verbose toast output
+ <jvmarg value="-Dorg.jboss.jbossts.orchestration.verbose"/>
+ -->
+ <!-- uncomment to dump generated code
+ <jvmarg value="-Dorg.jboss.jbossts.orchestration.dump.generated.classes"/>
+ <jvmarg value="-Dorg.jboss.jbossts.orchestration.dump.generated.classes.directory=dump"/>
+ -->
+ <!-- uncomment to enable debug
+ <jvmarg value="-Xdebug"/>
+ <jvmarg value="-Xnoagent"/>
+ <jvmarg value="-Djava.compiler=NONE"/>
+ <jvmarg value="-Xrunjdwp:transport=dt_socket,server=n,suspend=y,address=5005"/>
+ -->
<jvmarg value="-javaagent:${toast.home}/${toast.jar}=script:${scripts.dir}/location/TestCall.txt"/>
<test name="org.jboss.jbossts.orchestration.tests.location.TestCall"/>
</junit>
@@ -122,7 +135,6 @@
<jvmarg value="-javaagent:${toast.home}/${toast.jar}=script:${scripts.dir}/location/TestSynch.txt"/>
<test name="org.jboss.jbossts.orchestration.tests.location.TestSynch"/>
</junit>
- <!-- THROW triggers are not currently working correctly in the presence of synchronizations
<junit fork="true" showoutput="true">
<classpath>
<pathelement location="${build.lib.dir}/orchestration-tests.jar"/>
@@ -131,7 +143,6 @@
<jvmarg value="-javaagent:${toast.home}/${toast.jar}=script:${scripts.dir}/location/TestThrow.txt"/>
<test name="org.jboss.jbossts.orchestration.tests.location.TestThrow"/>
</junit>
- -->
<junit fork="true" showoutput="true">
<classpath>
<pathelement location="${build.lib.dir}/orchestration-tests.jar"/>
@@ -179,8 +190,21 @@
<pathelement location="${build.lib.dir}/orchestration-tests.jar"/>
<pathelement location="${junit.home}/${junit.jar}"/>
</classpath>
+ <!-- uncomment for verbose toast output
+ <jvmarg value="-Dorg.jboss.jbossts.orchestration.verbose"/>
+ -->
+ <!-- uncomment to dump generated code
+ <jvmarg value="-Dorg.jboss.jbossts.orchestration.dump.generated.classes"/>
+ <jvmarg value="-Dorg.jboss.jbossts.orchestration.dump.generated.classes.directory=dump"/>
+ -->
+ <!-- uncomment to enable debug
+ <jvmarg value="-Xdebug"/>
+ <jvmarg value="-Xnoagent"/>
+ <jvmarg value="-Djava.compiler=NONE"/>
+ <jvmarg value="-Xrunjdwp:transport=dt_socket,server=n,suspend=y,address=5005"/>
+ -->
<jvmarg value="-javaagent:${toast.home}/${toast.jar}=script:${scripts.dir}/location/TestCall.txt"/>
- <jvmarg value="-Drg.jboss.jbossts.orchestration.compileToBytecode"/>
+ <jvmarg value="-Dorg.jboss.jbossts.orchestration.compileToBytecode"/>
<test name="org.jboss.jbossts.orchestration.tests.location.TestCall"/>
</junit>
<junit fork="true" showoutput="true">
@@ -192,7 +216,6 @@
<jvmarg value="-Drg.jboss.jbossts.orchestration.compileToBytecode"/>
<test name="org.jboss.jbossts.orchestration.tests.location.TestSynch"/>
</junit>
- <!-- THROW triggers are not currently working correctly in the presence of synchronizations
<junit fork="true" showoutput="true">
<classpath>
<pathelement location="${build.lib.dir}/orchestration-tests.jar"/>
@@ -202,7 +225,6 @@
<jvmarg value="-Drg.jboss.jbossts.orchestration.compileToBytecode"/>
<test name="org.jboss.jbossts.orchestration.tests.location.TestThrow"/>
</junit>
- -->
<junit fork="true" showoutput="true">
<classpath>
<pathelement location="${build.lib.dir}/orchestration-tests.jar"/>
Modified: labs/jbosstm/workspace/adinn/orchestration/tests/dd/scripts/location/TestCall.txt
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/tests/dd/scripts/location/TestCall.txt 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/tests/dd/scripts/location/TestCall.txt 2009-06-03 10:48:41 UTC (rev 26809)
@@ -48,3 +48,14 @@
DO test.log("CALL setCounter 2 triggered in TestCallThrowSynchAuxiliary.testMethod")
ENDRULE
+RULE test call setCounter trigger 3
+CLASS TestCallThrowSynchAuxiliary
+METHOD testMethod()
+HELPER org.jboss.jbossts.orchestration.tests.helpers.Default
+AT CALL setCounter 3
+BIND test : Test = $0.getTest()
+IF TRUE
+DO test.log("CALL setCounter 3 triggered in TestCallThrowSynchAuxiliary.testMethod"),
+ return
+ENDRULE
+
Modified: labs/jbosstm/workspace/adinn/orchestration/tests/dd/scripts/location/TestThrow.txt
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/tests/dd/scripts/location/TestThrow.txt 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/tests/dd/scripts/location/TestThrow.txt 2009-06-03 10:48:41 UTC (rev 26809)
@@ -1,12 +1,12 @@
-RULE test throw trigger
-CLASS TestCallThrowSynchAuxiliary
-METHOD testMethod()
-HELPER org.jboss.jbossts.orchestration.tests.helpers.Default
-AT THROW
-BIND test : Test = $0.getTest()
-IF TRUE
-DO test.log("THROW 1 triggered in TestCallThrowSynchAuxiliary.testMethod")
-ENDRULE
+#RULE test throw trigger
+#CLASS TestCallThrowSynchAuxiliary
+#METHOD testMethod()
+#HELPER org.jboss.jbossts.orchestration.tests.helpers.Default
+#AT THROW
+#BIND test : Test = $0.getTest()
+#IF TRUE
+#DO test.log("THROW 1 triggered in TestCallThrowSynchAuxiliary.testMethod")
+#ENDRULE
RULE test throw trigger 2
CLASS TestCallThrowSynchAuxiliary
Modified: labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/auxiliary/TestCallThrowSynchAuxiliary.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/auxiliary/TestCallThrowSynchAuxiliary.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/auxiliary/TestCallThrowSynchAuxiliary.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -45,6 +45,12 @@
synchronized(this) {
test.log("3: currentCounter == " + currentCounter);
}
+
+ synchronized(this) {
+ setCounter(currentCounter + 1);
+ // should not get printed for call test since call to setCounter should trigger a return
+ test.log("4: currentCounter == " + currentCounter);
+ }
}
public Test getTest()
Modified: labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/location/TestCall.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/location/TestCall.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/location/TestCall.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -52,6 +52,7 @@
logExpected("CALL setCounter 2 triggered in TestCallThrowSynchAuxiliary.testMethod");
logExpected("CALL getCounter 3 triggered in TestCallThrowSynchAuxiliary.testMethod");
logExpected("3: currentCounter == 2");
+ logExpected("CALL setCounter 3 triggered in TestCallThrowSynchAuxiliary.testMethod");
logExpected("called TestCallThrowSynchAuxiliary.testMethod");
return super.getExpected();
Modified: labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/location/TestSynch.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/location/TestSynch.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/location/TestSynch.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -47,6 +47,7 @@
// and before printing the 3rd counter
logExpected("SYNCHRONIZE 2 triggered in TestCallThrowSynchAuxiliary.testMethod");
logExpected("3: currentCounter == 2");
+ logExpected("4: currentCounter == 2");
logExpected("called TestCallThrowSynchAuxiliary.testMethod");
return super.getExpected();
Modified: labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/location/TestThrow.java
===================================================================
--- labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/location/TestThrow.java 2009-06-03 09:20:32 UTC (rev 26808)
+++ labs/jbosstm/workspace/adinn/orchestration/tests/src/org/jboss/jbossts/orchestration/tests/location/TestThrow.java 2009-06-03 10:48:41 UTC (rev 26809)
@@ -17,6 +17,7 @@
public void test()
{
+ /*
runNumber = 1;
try {
@@ -34,6 +35,7 @@
}
checkOutput(true);
+ */
runNumber = 2;
More information about the jboss-svn-commits
mailing list