summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraclement <aclement>2007-02-09 10:45:08 +0000
committeraclement <aclement>2007-02-09 10:45:08 +0000
commit291bb7dbcfcc7ae00047a6d306a7962b5b84e914 (patch)
tree8e125f2948096a9736bda6e5b48b08d141d9c54c
parentdb03e4bbe73821a6fa73b6d96a09e1547e7c3b94 (diff)
downloadaspectj-verification.tar.gz
aspectj-verification.zip
verification prototype codeverification
-rw-r--r--bcel-builder/.classpath2
-rw-r--r--bcel-builder/.fbprefs105
-rw-r--r--bcel-builder/.settings/org.eclipse.jdt.core.prefs17
-rw-r--r--bcel-builder/foo.jarbin0 -> 777213 bytes
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/Constants.java27
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/Attribute.java15
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/ConstantNameAndType.java4
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/DescendingVisitor.java10
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/EmptyVisitor.java6
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/GenericSignatureParser.java8
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java5
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/Method.java9
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java3
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMap.java11
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapEntry.java4
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapFrame.java333
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapTable.java282
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapType.java21
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/Utility.java11
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/classfile/Visitor.java6
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/ArrayType.java4
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/ConstantPoolGen.java7
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/EmptyVisitor.java4
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionHandle.java35
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionList.java3
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/MethodGen.java41
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/generic/Type.java4
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/Verifier.java23
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/DOUBLE_Upper.java4
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/LONG_Upper.java4
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/StringRepresentation.java12
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ControlFlowGraph.java5
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ExecutionVisitor.java6
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/InstConstraintVisitor.java16
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/LocalVariables.java7
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/Pass3bVerifier.java55
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ControlFlowGraph.java140
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExceptionHandler.java93
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExceptionHandlers.java112
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExecutionVisitor.java1143
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Frame.java375
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstConstraintVisitor.java2667
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContext.java113
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContextImpl.java395
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContextQueue.java34
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/LocalVariables.java268
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/OperandStack.java300
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/StackMapHelper.java225
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Subroutine.java127
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/SubroutineImpl.java293
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Subroutines.java395
-rw-r--r--bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/UninitializedObjectType.java104
-rw-r--r--bcel-builder/testdata/stackmap/Code.classbin0 -> 576 bytes
-rw-r--r--bcel-builder/testdata/stackmap/Code.java23
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/preverifier/PreverifierBaseTestCase.java189
-rw-r--r--bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/preverifier/PreverifierTest.java771
56 files changed, 8726 insertions, 150 deletions
diff --git a/bcel-builder/.classpath b/bcel-builder/.classpath
index 955afd2c0..8c64eb4d1 100644
--- a/bcel-builder/.classpath
+++ b/bcel-builder/.classpath
@@ -4,6 +4,6 @@
<classpathentry kind="src" path="testsrc"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="/lib/regexp/jakarta-regexp-1.2.jar"/>
- <classpathentry sourcepath="/lib/junit/junit-src.jar" kind="lib" path="/lib/junit/junit.jar"/>
+ <classpathentry kind="lib" path="/lib/junit/junit.jar" sourcepath="/lib/junit/junit-src.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/bcel-builder/.fbprefs b/bcel-builder/.fbprefs
new file mode 100644
index 000000000..e0032fe06
--- /dev/null
+++ b/bcel-builder/.fbprefs
@@ -0,0 +1,105 @@
+#FindBugs User Preferences
+#Fri Feb 09 09:32:57 GMT 2007
+default_directory=C\:\\e33m4\\eclipse
+detectorBadAppletConstructor=BadAppletConstructor|false
+detectorBadResultSetAccess=BadResultSetAccess|true
+detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true
+detectorBadUseOfReturnValue=BadUseOfReturnValue|true
+detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true
+detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true
+detectorCloneIdiom=CloneIdiom|true
+detectorComparatorIdiom=ComparatorIdiom|true
+detectorConfusedInheritance=ConfusedInheritance|true
+detectorConfusionBetweenInheritedAndOuterMethod=ConfusionBetweenInheritedAndOuterMethod|true
+detectorDoInsideDoPrivileged=DoInsideDoPrivileged|true
+detectorDontCatchIllegalMonitorStateException=DontCatchIllegalMonitorStateException|true
+detectorDroppedException=DroppedException|true
+detectorDumbMethodInvocations=DumbMethodInvocations|true
+detectorDumbMethods=DumbMethods|true
+detectorDuplicateBranches=DuplicateBranches|true
+detectorEmptyZipFileEntry=EmptyZipFileEntry|true
+detectorFindBadCast2=FindBadCast2|true
+detectorFindBadForLoop=FindBadForLoop|true
+detectorFindCircularDependencies=FindCircularDependencies|false
+detectorFindDeadLocalStores=FindDeadLocalStores|true
+detectorFindDoubleCheck=FindDoubleCheck|true
+detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true
+detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true
+detectorFindFinalizeInvocations=FindFinalizeInvocations|true
+detectorFindFloatEquality=FindFloatEquality|true
+detectorFindHEmismatch=FindHEmismatch|true
+detectorFindInconsistentSync2=FindInconsistentSync2|true
+detectorFindJSR166LockMonitorenter=FindJSR166LockMonitorenter|true
+detectorFindLocalSelfAssignment2=FindLocalSelfAssignment2|true
+detectorFindMaskedFields=FindMaskedFields|true
+detectorFindMismatchedWaitOrNotify=FindMismatchedWaitOrNotify|true
+detectorFindNakedNotify=FindNakedNotify|true
+detectorFindNonSerializableStoreIntoSession=FindNonSerializableStoreIntoSession|true
+detectorFindNonSerializableValuePassedToWriteObject=FindNonSerializableValuePassedToWriteObject|true
+detectorFindNonShortCircuit=FindNonShortCircuit|true
+detectorFindNullDeref=FindNullDeref|true
+detectorFindOpenStream=FindOpenStream|true
+detectorFindPuzzlers=FindPuzzlers|true
+detectorFindRefComparison=FindRefComparison|true
+detectorFindReturnRef=FindReturnRef|true
+detectorFindRunInvocations=FindRunInvocations|true
+detectorFindSelfComparison=FindSelfComparison|true
+detectorFindSelfComparison2=FindSelfComparison2|true
+detectorFindSleepWithLockHeld=FindSleepWithLockHeld|true
+detectorFindSpinLoop=FindSpinLoop|true
+detectorFindSqlInjection=FindSqlInjection|true
+detectorFindTwoLockWait=FindTwoLockWait|true
+detectorFindUncalledPrivateMethods=FindUncalledPrivateMethods|true
+detectorFindUnconditionalWait=FindUnconditionalWait|true
+detectorFindUninitializedGet=FindUninitializedGet|true
+detectorFindUnrelatedTypesInGenericContainer=FindUnrelatedTypesInGenericContainer|true
+detectorFindUnreleasedLock=FindUnreleasedLock|true
+detectorFindUnsyncGet=FindUnsyncGet|true
+detectorFindUselessControlFlow=FindUselessControlFlow|true
+detectorHugeSharedStringConstants=HugeSharedStringConstants|true
+detectorIDivResultCastToDouble=IDivResultCastToDouble|true
+detectorIncompatMask=IncompatMask|true
+detectorInefficientMemberAccess=InefficientMemberAccess|false
+detectorInefficientToArray=InefficientToArray|true
+detectorInfiniteLoop=InfiniteLoop|true
+detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true
+detectorInfiniteRecursiveLoop2=InfiniteRecursiveLoop2|false
+detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true
+detectorInitializationChain=InitializationChain|true
+detectorInstantiateStaticClass=InstantiateStaticClass|true
+detectorInvalidJUnitTest=InvalidJUnitTest|true
+detectorIteratorIdioms=IteratorIdioms|true
+detectorLazyInit=LazyInit|true
+detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true
+detectorMethodReturnCheck=MethodReturnCheck|true
+detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true
+detectorMutableLock=MutableLock|true
+detectorMutableStaticFields=MutableStaticFields|true
+detectorNaming=Naming|true
+detectorNumberConstructor=NumberConstructor|true
+detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true
+detectorPublicSemaphores=PublicSemaphores|false
+detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true
+detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true
+detectorRedundantInterfaces=RedundantInterfaces|true
+detectorRuntimeExceptionCapture=RuntimeExceptionCapture|true
+detectorSerializableIdiom=SerializableIdiom|true
+detectorStartInConstructor=StartInConstructor|true
+detectorStringConcatenation=StringConcatenation|true
+detectorSuperfluousInstanceOf=SuperfluousInstanceOf|true
+detectorSuspiciousThreadInterrupted=SuspiciousThreadInterrupted|true
+detectorSwitchFallthrough=SwitchFallthrough|true
+detectorURLProblems=URLProblems|true
+detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true
+detectorUnnecessaryMath=UnnecessaryMath|true
+detectorUnreadFields=UnreadFields|true
+detectorUseObjectEquals=UseObjectEquals|false
+detectorUselessSubclassMethod=UselessSubclassMethod|false
+detectorVarArgsProblems=VarArgsProblems|true
+detectorVolatileUsage=VolatileUsage|true
+detectorWaitInLoop=WaitInLoop|true
+detectorWrongMapIterator=WrongMapIterator|true
+detectorXMLFactoryBypass=XMLFactoryBypass|true
+detector_threshold=2
+filter_settings=Medium|PERFORMANCE,CORRECTNESS,I18N,MT_CORRECTNESS,BAD_PRACTICE,MALICIOUS_CODE,STYLE|false
+filter_settings_neg=|
diff --git a/bcel-builder/.settings/org.eclipse.jdt.core.prefs b/bcel-builder/.settings/org.eclipse.jdt.core.prefs
index fd14c0abb..56a224610 100644
--- a/bcel-builder/.settings/org.eclipse.jdt.core.prefs
+++ b/bcel-builder/.settings/org.eclipse.jdt.core.prefs
@@ -1,6 +1,6 @@
-#Fri Nov 25 19:12:57 GMT 2005
+#Wed Dec 06 15:02:55 GMT 2006
eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.1
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.3
@@ -10,7 +10,7 @@ org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=ignore
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
-org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=ignore
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
@@ -46,12 +46,13 @@ org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
-org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
-org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=1.3
diff --git a/bcel-builder/foo.jar b/bcel-builder/foo.jar
new file mode 100644
index 000000000..ac306e049
--- /dev/null
+++ b/bcel-builder/foo.jar
Binary files differ
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/Constants.java b/bcel-builder/src/org/aspectj/apache/bcel/Constants.java
index 51c139901..2eaebd96b 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/Constants.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/Constants.java
@@ -57,7 +57,7 @@ package org.aspectj.apache.bcel;
/**
* Constants for the project, mostly defined in the JVM specification.
*
- * @version $Id: Constants.java,v 1.3 2006/05/04 11:28:26 aclement Exp $
+ * @version $Id: Constants.java,v 1.3.4.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*/
public interface Constants {
@@ -431,6 +431,7 @@ public interface Constants {
public static final byte T_REFERENCE = 14; // Deprecated
public static final byte T_UNKNOWN = 15;
public static final byte T_ADDRESS = 16;
+ public static final byte T_TOP = 17;
/** The primitive type names corresponding to the T_XX constants,
* e.g., TYPE_NAMES[T_INT] = "int"
@@ -439,6 +440,7 @@ public interface Constants {
ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE, ILLEGAL_TYPE,
"boolean", "char", "float", "double", "byte", "short", "int", "long",
"void", "array", "object", "unknown" // Non-standard
+ ,"address","top"
};
/** The primitive class names corresponding to the T_XX constants,
@@ -766,8 +768,8 @@ public interface Constants {
public static final byte ATTR_SYNTHETIC = 7;
public static final byte ATTR_DEPRECATED = 8;
public static final byte ATTR_PMG = 9;
- public static final byte ATTR_SIGNATURE = 10; //J5TODO: Is this the same as a Java5 signature attribute?
- public static final byte ATTR_STACK_MAP = 11;
+ public static final byte ATTR_SIGNATURE = 10;
+ public static final byte ATTR_STACK_MAP_TABLE = 11;
// J5SUPPORT:
public static final byte ATTR_RUNTIME_VISIBLE_ANNOTATIONS = 12;
@@ -784,27 +786,28 @@ public interface Constants {
"SourceFile", "ConstantValue", "Code", "Exceptions",
"LineNumberTable", "LocalVariableTable",
"InnerClasses", "Synthetic", "Deprecated",
- "PMGClass", "Signature", "StackMap",
+ "PMGClass", "Signature", "StackMapTable",
// J5SUPPORT:
"RuntimeVisibleAnnotations","RuntimeInvisibleAnnotations",
"RuntimeVisibleParameterAnnotations","RuntimeInvisibleParameterAnnotations",
"LocalVariableTypeTable","EnclosingMethod","AnnotationDefault"
};
- /** Constants used in the StackMap attribute.
+ /**
+ * Constants used in the StackMap attribute.
*/
- public static final byte ITEM_Bogus = 0;
+ public static final byte ITEM_Top = 0;
public static final byte ITEM_Integer = 1;
public static final byte ITEM_Float = 2;
public static final byte ITEM_Double = 3;
public static final byte ITEM_Long = 4;
- public static final byte ITEM_Null = 5;
- public static final byte ITEM_InitObject = 6;
- public static final byte ITEM_Object = 7;
- public static final byte ITEM_NewObject = 8;
+ public static final byte ITEM_Null = 5;
+ public static final byte ITEM_UninitializedThis = 6;
+ public static final byte ITEM_Object = 7;
+ public static final byte ITEM_Uninitialized = 8;
public static final String[] ITEM_NAMES = {
- "Bogus", "Integer", "Float", "Double", "Long",
- "Null", "InitObject", "Object", "NewObject"
+ "Top", "Integer", "Float", "Double", "Long",
+ "Null", "UninitializedThis", "Object", "Uninitalized"
};
}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Attribute.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Attribute.java
index 8d7deb62e..386d2802d 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Attribute.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Attribute.java
@@ -71,7 +71,7 @@ import java.util.HashMap;
* <em>Synthetic</em> attributes are supported. The
* <em>Unknown</em> attribute stands for non-standard-attributes.
*
- * @version $Id: Attribute.java,v 1.2 2004/11/19 16:45:18 aclement Exp $
+ * @version $Id: Attribute.java,v 1.2.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @see ConstantValue
* @see SourceFile
@@ -168,15 +168,14 @@ public abstract class Attribute implements Cloneable, Node, Serializable {
c = (ConstantUtf8)constant_pool.getConstant(name_index,
Constants.CONSTANT_Utf8);
name = c.getBytes();
-
// Length of data in bytes
length = file.readInt();
// Compare strings to find known attribute
- for(byte i=0; i < Constants.KNOWN_ATTRIBUTES; i++) {
+ for (byte i=0; i < Constants.KNOWN_ATTRIBUTES; i++) {
if(name.equals(Constants.ATTRIBUTE_NAMES[i])) {
- tag = i; // found!
- break;
+ tag = i; // found!
+ break;
}
}
@@ -186,7 +185,7 @@ public abstract class Attribute implements Cloneable, Node, Serializable {
AttributeReader r = (AttributeReader)readers.get(name);
if(r != null)
- return r.createAttribute(name_index, length, file, constant_pool);
+ return r.createAttribute(name_index, length, file, constant_pool);
else
return new Unknown(name_index, length, file, constant_pool);
@@ -223,8 +222,8 @@ public abstract class Attribute implements Cloneable, Node, Serializable {
case Constants.ATTR_SIGNATURE:
return new Signature(name_index, length, file, constant_pool);
- case Constants.ATTR_STACK_MAP:
- return new StackMap(name_index, length, file, constant_pool);
+ case Constants.ATTR_STACK_MAP_TABLE:
+ return new StackMapTable(name_index, length, file, constant_pool);
// J5SUPPORT:
case Constants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/ConstantNameAndType.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/ConstantNameAndType.java
index f6fb51239..04573c146 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/ConstantNameAndType.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/ConstantNameAndType.java
@@ -63,7 +63,7 @@ import java.io.*;
* and represents a reference to the name and signature
* of a field or method.
*
- * @version $Id: ConstantNameAndType.java,v 1.2 2004/11/19 16:45:18 aclement Exp $
+ * @version $Id: ConstantNameAndType.java,v 1.2.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @see Constant
*/
@@ -86,7 +86,7 @@ public final class ConstantNameAndType extends Constant {
*/
ConstantNameAndType(DataInputStream file) throws IOException
{
- this((int)file.readUnsignedShort(), (int)file.readUnsignedShort());
+ this(file.readUnsignedShort(), file.readUnsignedShort());
}
/**
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/DescendingVisitor.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/DescendingVisitor.java
index 7d61dc2d1..237408ad3 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/DescendingVisitor.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/DescendingVisitor.java
@@ -66,7 +66,7 @@ import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleParameterAnnot
* class supplies the traversal strategy, other classes can make use
* of it.
*
- * @version $Id: DescendingVisitor.java,v 1.2 2004/11/19 16:45:18 aclement Exp $
+ * @version $Id: DescendingVisitor.java,v 1.2.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*/
public class DescendingVisitor implements Visitor {
@@ -89,7 +89,7 @@ public class DescendingVisitor implements Visitor {
if((size < 2) || (level < 0))
return null;
- else
+
return stack.elementAt(size - (level + 2)); // size - 1 == current
}
@@ -212,18 +212,18 @@ public class DescendingVisitor implements Visitor {
stack.pop();
}
- public void visitStackMap(StackMap table) {
+ public void visitStackMap(StackMapTable table) {
stack.push(table);
table.accept(visitor);
- StackMapEntry[] vars = table.getStackMap();
+ StackMapFrame[] vars = table.getStackMap();
for(int i=0; i < vars.length; i++)
vars[i].accept(this);
stack.pop();
}
- public void visitStackMapEntry(StackMapEntry var) {
+ public void visitStackMapEntry(StackMapFrame var) {
stack.push(var);
var.accept(visitor);
stack.pop();
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/EmptyVisitor.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/EmptyVisitor.java
index 1113f0af5..5d4b016fc 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/EmptyVisitor.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/EmptyVisitor.java
@@ -66,7 +66,7 @@ import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleParameterAnnot
* By courtesy of David Spencer.
*
* @see DescendingVisitor
- * @version $Id: EmptyVisitor.java,v 1.3 2004/11/19 16:45:18 aclement Exp $
+ * @version $Id: EmptyVisitor.java,v 1.3.8.1 2007/02/09 10:45:09 aclement Exp $
*
*/
public class EmptyVisitor implements Visitor {
@@ -102,8 +102,8 @@ public class EmptyVisitor implements Visitor {
public void visitSourceFile(SourceFile obj) {}
public void visitSynthetic(Synthetic obj) {}
public void visitUnknown(Unknown obj) {}
- public void visitStackMap(StackMap obj) {}
- public void visitStackMapEntry(StackMapEntry obj) {}
+ public void visitStackMap(StackMapTable obj) {}
+ public void visitStackMapEntry(StackMapFrame obj) {}
// J5SUPPORT:
public void visitEnclosingMethod(EnclosingMethod obj) {}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/GenericSignatureParser.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/GenericSignatureParser.java
index fe45f28da..9c94125b0 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/GenericSignatureParser.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/GenericSignatureParser.java
@@ -170,10 +170,9 @@ public class GenericSignatureParser {
FieldTypeSignature fieldType = parseFieldTypeSignature(true);
if (fieldType != null) {
return new ArrayTypeSignature(fieldType);
- } else {
- // must be BaseType array
- return new ArrayTypeSignature(new BaseTypeSignature(eatIdentifier()));
}
+ // must be BaseType array
+ return new ArrayTypeSignature(new BaseTypeSignature(eatIdentifier()));
}
// L PackageSpecifier* SimpleClassTypeSignature ClassTypeSignature* ;
@@ -264,9 +263,8 @@ public class GenericSignatureParser {
TypeArgument[] tArgs = new TypeArgument[typeArgs.size()];
typeArgs.toArray(tArgs);
return tArgs;
- } else {
- return null;
}
+ return null;
}
private TypeVariableSignature parseTypeVariableSignature() {
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java
index e019947f5..7b89379ad 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java
@@ -77,7 +77,7 @@ import java.util.StringTokenizer;
* class file. Those interested in programatically generating classes
* should see the <a href="../generic/ClassGen.html">ClassGen</a> class.
- * @version $Id: JavaClass.java,v 1.9 2005/12/02 06:56:14 acolyer Exp $
+ * @version $Id: JavaClass.java,v 1.9.6.1 2007/02/09 10:45:09 aclement Exp $
* @see org.aspectj.apache.bcel.generic.ClassGen
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*/
@@ -971,9 +971,8 @@ public class JavaClass extends AccessFlags implements Cloneable, Node {
loadGenericSignatureInfoIfNecessary();
if (signatureAttribute != null) {
return signatureAttribute.asClassSignature();
- } else {
- return null;
}
+ return null;
}
}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Method.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Method.java
index 56ff334e5..8408cb416 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Method.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Method.java
@@ -69,7 +69,7 @@ import org.aspectj.apache.bcel.generic.Type;
* for a method in the class. See JVM specification for details.
* A method has access flags, a name, a signature and a number of attributes.
*
- * @version $Id: Method.java,v 1.2 2004/11/19 16:45:18 aclement Exp $
+ * @version $Id: Method.java,v 1.2.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*/
public final class Method extends FieldOrMethod {
@@ -169,7 +169,6 @@ public final class Method extends FieldOrMethod {
if(code != null)
return code.getLocalVariableTable();
- else
return null;
}
@@ -181,8 +180,8 @@ public final class Method extends FieldOrMethod {
if(code != null)
return code.getLineNumberTable();
- else
- return null;
+
+ return null;
}
/**
@@ -252,7 +251,7 @@ public final class Method extends FieldOrMethod {
if (parameterAnnotationsOutOfDate) {
// Find attributes that contain annotation data
Attribute[] attrs = getAttributes();
- List accumulatedAnnotations = new ArrayList();
+// List accumulatedAnnotations = new ArrayList();
for (int i = 0; i < attrs.length; i++) {
Attribute attribute = attrs[i];
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java
index bb9673103..fea8c4c69 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java
@@ -69,7 +69,7 @@ import org.aspectj.apache.bcel.Constants;
* This class is derived from <em>Attribute</em> and represents a reference
* to a <href="http://wwwipd.ira.uka.de/~pizza/gj/">GJ</a> attribute.
*
- * @version $Id: Signature.java,v 1.6 2005/07/12 13:59:06 aclement Exp $
+ * @version $Id: Signature.java,v 1.6.6.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @see Attribute
*/
@@ -119,7 +119,6 @@ public final class Signature extends Attribute {
* @param v Visitor object
*/
public void accept(Visitor v) {
- System.err.println("Visiting non-standard Signature object");
v.visitSignature(this);
}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMap.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMap.java
index df976fc69..7c6f765b8 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMap.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMap.java
@@ -54,8 +54,9 @@ package org.aspectj.apache.bcel.classfile;
* <http://www.apache.org/>.
*/
-import org.aspectj.apache.bcel.Constants;
-import java.io.*;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
/**
* This class represents a stack map attribute used for
@@ -66,7 +67,7 @@ import java.io.*;
* within the Code attribute of a method. See CLDC specification
* §5.3.1.2
*
- * @version $Id: StackMap.java,v 1.2 2004/11/19 16:45:18 aclement Exp $
+ * @version $Id: StackMap.java,v 1.2.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @see Code
* @see StackMapEntry
@@ -85,7 +86,7 @@ public final class StackMap extends Attribute implements Node {
public StackMap(int name_index, int length, StackMapEntry[] map,
ConstantPool constant_pool)
{
- super(Constants.ATTR_STACK_MAP, name_index, length, constant_pool);
+ super(/*dunno - do we want to support the 'old style' ? */(byte)12/*Constants.ATTR_STACK_MAP*/, name_index, length, constant_pool);
setStackMap(map);
}
@@ -178,7 +179,7 @@ public final class StackMap extends Attribute implements Node {
* @param v Visitor object
*/
public void accept(Visitor v) {
- v.visitStackMap(this);
+ //v.visitStackMap(this);
}
public final int getMapLength() { return map_length; }
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapEntry.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapEntry.java
index e20d11f5f..3a23e4324 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapEntry.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapEntry.java
@@ -63,7 +63,7 @@ import java.io.IOException;
* local variables and the the of stack items at a given byte code offset.
* See CLDC specification §5.3.1.2
*
- * @version $Id: StackMapEntry.java,v 1.4 2004/11/22 08:31:27 aclement Exp $
+ * @version $Id: StackMapEntry.java,v 1.4.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @see StackMap
* @see StackMapType
@@ -193,7 +193,7 @@ public final class StackMapEntry implements Cloneable {
* @param v Visitor object
*/
public void accept(Visitor v) {
- v.visitStackMapEntry(this);
+ // v.visitStackMapEntry(this);
}
/**
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapFrame.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapFrame.java
new file mode 100644
index 000000000..9ae5fe918
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapFrame.java
@@ -0,0 +1,333 @@
+package org.aspectj.apache.bcel.classfile;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.aspectj.apache.bcel.generic.ConstantPoolGen;
+import org.aspectj.apache.bcel.verifier.utility.Frame;
+
+/**
+ * This class represents a stack map entry recording the types of
+ * local variables and the the of stack items at a given byte code offset.
+ * See CLDC specification §5.3.1.2
+ *
+ * @version $Id$
+ * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
+ * @see StackMapTable
+ * @see StackMapType
+ */
+public final class StackMapFrame implements Cloneable, Node {
+
+ // XXX move to bcel constants
+ public static final byte SameFrameKind = 0;
+ public static final byte SameLocalsOneStackItemFrameKind = 1;
+ public static final byte RESERVEDKind = 2;
+ public static final byte SameLocalsOneStackItemFrameExtendedKind = 3;
+ public static final byte ChopFrameKind = 4;
+ public static final byte SameFrameExtendedKind = 5;
+ public static final byte AppendFrameKind = 6;
+ public static final byte FullFrameKind = 7;
+ public static final byte UnknownKind = 8;
+
+ private byte kind = UnknownKind;
+
+ private static String[] ALL_KINDS = {
+ "SameFrame","SameLocalsOneStackItemFrame","RESERVED",
+ "SameLocalsOneStackItemFrameExtended","ChopFrame",
+ "SameFrameExtended","AppendFrame","FullFrame","???"
+ };
+
+ /**
+ * 000..063 => SameFrame
+ * 064..127 => SameLocalsOneStackItemFrame
+ * 128..246 => RESERVED
+ * 247 => SameLocalsOneStackItemFrameExtended
+ * 248..250 => ChopFrame
+ * 251 => SameFrameExtended
+ * 252..254 => AppendFrame
+ * 255 => FullFrame
+ */
+ private int tag;
+
+ private int offsetDelta;
+
+ private int localCount=0;
+ private int stackCount=0;
+ private StackMapType[] localTypes;
+ private StackMapType[] stackTypes;
+ private ConstantPool cpool;
+
+
+ // temporary
+ boolean built = false;
+ /**
+ * Build a StackMapFrame from the file stream contents
+ * @param is Data input stream
+ * @throws IOException
+ */
+ StackMapFrame(DataInputStream is, ConstantPool constantPool) throws IOException {
+ cpool = constantPool;
+ tag = is.readUnsignedByte();
+ if (tag<64) { // SameFrame
+ // same locals as before, stack height is zero
+ kind = SameFrameKind;
+ offsetDelta=tag;
+ if (debug) System.err.println("Loading SameFrame: offset="+offsetDelta);
+ } else if (tag<128) { // SameLocalsOneStackItemFrame
+ kind = SameLocalsOneStackItemFrameKind;
+ offsetDelta = tag-64;
+ if (debug) System.err.println("Loading SameLocalsOneStackItemFrame: offset="+offsetDelta);
+ stackCount=1;
+ stackTypes=new StackMapType[1];
+ stackTypes[0]=new StackMapType(is,constantPool);
+ } else if (tag<247) { // RESERVED
+ kind=RESERVEDKind;
+ if (debug) System.err.println("Loading reserved");
+ } else if (tag==247) { // SameLocalsOneStackItemFrameExtended
+ kind=SameLocalsOneStackItemFrameExtendedKind;
+ offsetDelta = is.readUnsignedShort();
+ if (debug) System.err.println("Loading SameLocalsOneStackItemFrameExtended: offset="+offsetDelta);
+ stackCount=1;
+ stackTypes=new StackMapType[1];
+ stackTypes[0]=new StackMapType(is,constantPool);
+ } else if (tag<251) { // ChopFrame
+ kind=ChopFrameKind;
+ if (debug) System.err.println("Loading ChopFrame");
+ offsetDelta = is.readUnsignedShort();
+ localCount=251-tag; // locals removed from previous frame
+ } else if (tag==251) { // SameFrameExtended
+ kind=SameFrameExtendedKind;
+ // same locals as before, stack height is zero
+ offsetDelta = is.readUnsignedShort();
+ if (debug) System.err.println("Loading SameFrameExtended: offset="+offsetDelta);
+ } else if (tag<255) { // AppendFrame
+ kind=AppendFrameKind;
+ offsetDelta = is.readUnsignedShort();
+ localCount = tag - 251;
+ stackCount = 0; // implied
+ if (debug) System.err.println("Loading AppendFrame, number of locals="+localCount+" offset="+offsetDelta);
+ localTypes = new StackMapType[localCount];
+ for(int i=0;i<localCount;i++) {
+ localTypes[i] = new StackMapType(is,constantPool);
+ if (debug) System.err.println(" Position ["+i+"] = "+localTypes[i]);
+ }
+ } else if (tag==255) { // FullFrame
+ kind=FullFrameKind;
+ if (debug) System.err.println("Loading FullFrame...");
+ offsetDelta = is.readUnsignedShort();
+ localCount = is.readUnsignedShort();
+ localTypes = new StackMapType[localCount];
+ for(int i=0;i<localCount;i++) {
+ localTypes[i] = new StackMapType(is,constantPool);
+ if (debug) System.err.println(" Locals ["+i+"] = "+localTypes[i]);
+ }
+ stackCount = is.readUnsignedShort();
+ stackTypes = new StackMapType[stackCount];
+ for(int i=0;i<stackCount;i++) {
+ stackTypes[i] = new StackMapType(is,constantPool);
+ if (debug) System.err.println(" Stack ["+i+"] = "+stackTypes[i]);
+ }
+ if (debug) System.err.println("Loaded FullFrame, offset="+offsetDelta+" number of locals="+localCount+" number of stack items="+stackCount);
+ }
+ }
+
+ private boolean debug = false;
+
+ public StackMapFrame(int byte_code_offset, int number_of_locals,
+ StackMapType[] types_of_locals,
+ int number_of_stack_items,
+ StackMapType[] types_of_stack_items,
+ ConstantPool constant_pool) {
+ this.offsetDelta = byte_code_offset;
+ this.localCount = number_of_locals;
+ this.localTypes = types_of_locals;
+ this.stackCount = number_of_stack_items;
+ this.stackTypes = types_of_stack_items;
+ this.cpool = constant_pool;
+ }
+
+ /**
+ * Dump stack map entry
+ *
+ * @param file Output file stream
+ * @throws IOException
+ */
+ public final void dump(DataOutputStream file) throws IOException
+ {
+ // all frames are full ones!
+ file.writeByte(255);
+ file.writeShort(offsetDelta);
+
+ file.writeShort(localTypes.length);//localCount);
+ for(int i=0; i < localTypes.length; i++) {
+ localTypes[i].dump(file);
+ }
+
+ file.writeShort(stackTypes.length);
+ for(int i=0; i < stackTypes.length; i++)
+ stackTypes[i].dump(file);
+ }
+
+ /**
+ * @return String representation.
+ */
+ public final String toString() {
+// if (!built) return "Unfinished StackMapFrame, tag="+Integer.toString(tag);
+ StringBuffer buf = new StringBuffer(getKindString()+" (offset=" + offsetDelta);
+ if (localCount!=0 && localTypes==null && kind!=ChopFrameKind) {
+ System.err.println("BADLY FORMED STACKMAPFRAME: "+getKindString()+" locals size is "+localCount+" but localtypes is null");
+ }
+
+ // For a 'ChopFrame' - the localCount is the number to remove, so the localTypes field stays null.
+ if (kind==ChopFrameKind) {
+ buf.append(" chopping "+localCount+" local").append(localCount>1?"s":"");
+ } else {
+
+ if(localCount > 0) {
+ buf.append(", LOCALS["+localCount+"]={");
+ for(int i=0; i < localCount; i++) {
+ buf.append(localTypes[i]);
+ if(i < localCount - 1)
+ buf.append(", ");
+ }
+ buf.append("}");
+ }
+ }
+
+ if(stackCount > 0) {
+ buf.append(", STACK["+stackCount+"]={");
+ for(int i=0; i < stackCount; i++) {
+ buf.append(stackTypes[i]);
+ if(i < stackCount - 1)
+ buf.append(", ");
+ }
+
+ buf.append("}");
+ }
+
+ buf.append(")");
+
+ return buf.toString();
+ }
+
+
+ public void setByteCodeOffset(int b) { offsetDelta = b; }
+ public int getByteCodeOffset() { return offsetDelta; }
+ public void setNumberOfLocals(int n) { localCount = n; }
+ public int getNumberOfLocals() { return localCount; }
+ public void setTypesOfLocals(StackMapType[] t) { localTypes = t; }
+ public StackMapType[] getTypesOfLocals() { return localTypes; }
+ public void setNumberOfStackItems(int n) { stackCount = n; }
+ public int getNumberOfStackItems() { return stackCount; }
+ public void setTypesOfStackItems(StackMapType[] t) { stackTypes = t; }
+ public StackMapType[] getTypesOfStackItems() { return stackTypes; }
+
+ /**
+ * @return deep copy of this object
+ */
+ public StackMapFrame copy() {
+ try {
+ return (StackMapFrame)clone();
+ } catch(CloneNotSupportedException e) {}
+
+ return null;
+ }
+
+ /**
+ * Called by objects that are traversing the nodes of the tree implicitely
+ * defined by the contents of a Java class. I.e., the hierarchy of methods,
+ * fields, attributes, etc. spawns a tree of objects.
+ *
+ * @param v Visitor object
+ */
+ public void accept(Visitor v) {
+ v.visitStackMapEntry(this);
+ }
+
+ public String getKindString() {
+ return ALL_KINDS[kind];
+ }
+
+ /**
+ * @return Constant pool used by this object.
+ */
+ public final ConstantPool getConstantPool() { return cpool; }
+
+ /**
+ * @param constant_pool Constant pool to be used for this object.
+ */
+ public final void setConstantPool(ConstantPool constant_pool) {
+ this.cpool = constant_pool;
+ }
+
+ public int getKind() {
+ return kind;
+ }
+
+ public static StackMapFrame forFrame(int offset, Frame frame, ConstantPoolGen cpg) {
+ //System.out.println("? StackMapFrame.forFrame(): new frame at offset "+offset+": locals="+frame.getLocals().toCompactString());
+ StackMapFrame smf =
+ new StackMapFrame(offset,
+ frame.getLocals().maxLocals(),
+ frame.getLocalsAsStackMapTypes(cpg),
+ frame.getStack().maxStack(),
+ frame.getStackAsStackMapTypes(cpg),
+ cpg.getConstantPool());
+ return smf;
+ }
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapTable.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapTable.java
new file mode 100644
index 000000000..030978f36
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapTable.java
@@ -0,0 +1,282 @@
+package org.aspectj.apache.bcel.classfile;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.aspectj.apache.bcel.Constants;
+import org.aspectj.apache.bcel.generic.ConstantPoolGen;
+import org.aspectj.apache.bcel.verifier.utility.Frame;
+
+import java.io.*;
+
+/**
+ * This class represents a stack map attribute used for
+ * preverification of Java classes for the <a
+ * href="http://java.sun.com/j2me/"> Java 2 Micro Edition</a>
+ * (J2ME). This attribute is used by the <a
+ * href="http://java.sun.com/products/cldc/">KVM</a> and contained
+ * within the Code attribute of a method. See CLDC specification
+ * §5.3.1.2
+ *
+ * @version $Id$
+ * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
+ * @see Code
+ * @see StackMapFrame
+ * @see StackMapType
+ *
+ * overhauled - Andy Clement 4th April 2006
+ */
+public final class StackMapTable extends Attribute implements Node {
+ private StackMapFrame[] entries; // Table of stack map entries
+
+ private int numberOfEntries;
+ // if 'isInPackedState' then the data array needs unpacking into the entries array before use
+ private boolean isInPackedState = false;
+ private byte[] data;
+
+ // temporary
+ String dataString;
+
+ /**
+ * @param nameIdx Index of name
+ * @param len Content length in bytes
+ * @param map Table of stack map entries
+ * @param constantPool Array of constants
+ */
+ public StackMapTable(int nameIdx, int len, StackMapFrame[] map, ConstantPool constantPool) {
+ super(Constants.ATTR_STACK_MAP_TABLE, nameIdx, len, constantPool);
+ setStackMap(map);
+ isInPackedState=false;
+ }
+
+
+ /**
+ * Construct object from file stream.
+ * @param nameIdx Index of name
+ * @param len Content length in bytes
+ * @param file Input stream
+ * @throws IOException
+ * @param constant_pool Array of constants
+ */
+ StackMapTable(int nameIdx, int len, DataInputStream file, ConstantPool constantPool) throws IOException {
+ this(nameIdx, len, (StackMapFrame[])null, constantPool);
+ numberOfEntries = file.readUnsignedShort();
+// entries = new StackMapFrame[numberOfEntries];
+
+ data = new byte[length-2];
+ int byteReads = file.read(data);
+ isInPackedState = true;
+ // assert(bytesRead==length)
+
+// for (int i=0; i < numberOfEntries; i++) {
+// entries[i] = new StackMapFrame(file, constantPool);
+// }
+ }
+
+ private void ensureUnpacked() {
+ if (!isInPackedState) return;
+ try {
+
+ // temporary
+ // construct an int representation for debugging
+ StringBuffer sb = new StringBuffer();
+ sb.append("StackMapTable [");
+ String zeroes = "000";
+ for (int i = 0; i < data.length; i++) {
+ int b = (int) data[i];
+ if (b<0) b+=256;
+ StringBuffer sb2 = new StringBuffer().append(zeroes).append(Integer.toString(b));
+ sb.append(sb2.substring(sb2.length()-3)).append(" ");
+ if ((sb.length()%60)>55) sb.append("\n");
+ }
+ dataString = sb.append("]").toString();
+
+ ByteArrayInputStream bs = new ByteArrayInputStream(data);
+ DataInputStream dis = new DataInputStream(bs);
+// numberOfEntries = (dis.readUnsignedShort());
+ entries = new StackMapFrame[numberOfEntries];
+ if (debug) System.err.println("Unpacking "+numberOfEntries+" StackFrames");
+ int bcoffset=0;
+ for (int i=0; i < numberOfEntries; i++) {
+ entries[i] = new StackMapFrame(dis, constant_pool);
+ bcoffset+=(entries[i].getByteCodeOffset()+(i==0?0:1));
+ if (debug) System.err.println("That was at bytecode offset "+bcoffset);
+ }
+ dis.close();
+ data = null; // throw it away now
+ } catch (IOException e) {
+ throw new RuntimeException("Unpacking of StackMapTable attribute failed");
+ }
+ isInPackedState=false;
+ }
+
+ private static boolean debug = false;
+
+ /**
+ * Dump line number table attribute to file stream in binary format.
+ *
+ * @param file Output file stream
+ * @throws IOException
+ */
+ public final void dump(DataOutputStream file) throws IOException
+ {
+ super.dump(file);
+ file.writeShort(numberOfEntries);
+ if (isInPackedState) {
+ file.write(data);
+ } else {
+ for(int i=0; i < numberOfEntries; i++)
+ entries[i].dump(file);
+ }
+ }
+
+ /**
+ * @return Array of stack map entries
+ */
+ public final StackMapFrame[] getStackMap() { ensureUnpacked();return entries; }
+
+ /**
+ * @param map Array of stack map entries
+ */
+ public final void setStackMap(StackMapFrame[] map) {
+ this.data = null;
+ this.isInPackedState=false;
+ entries = map;
+ numberOfEntries = (map == null)? 0 : map.length;
+ }
+
+ /**
+ * @return String representation.
+ */
+ public final String toString() {
+
+ ensureUnpacked();
+ return dataString;
+// StringBuffer buf = new StringBuffer("StackMapTable(");
+//
+// for(int i=0; i < numberOfEntries; i++) {
+// buf.append(entries[i].toString());
+//
+// if(i < numberOfEntries - 1)
+// buf.append(", ");
+// }
+//
+// buf.append(')');
+//
+// return buf.toString();
+ }
+
+ /**
+ * @return deep copy of this attribute
+ */
+ public Attribute copy(ConstantPool constant_pool) {
+ ensureUnpacked();
+ StackMapTable c = (StackMapTable)clone();
+
+ c.entries = new StackMapFrame[numberOfEntries];
+ for(int i=0; i < numberOfEntries; i++)
+ c.entries[i] = entries[i].copy();
+
+ c.constant_pool = constant_pool;
+ return c;
+ }
+
+ /**
+ * Called by objects that are traversing the nodes of the tree implicitely
+ * defined by the contents of a Java class. I.e., the hierarchy of methods,
+ * fields, attributes, etc. spawns a tree of objects.
+ *
+ * @param v Visitor object
+ */
+ public void accept(Visitor v) {
+ ensureUnpacked();
+ v.visitStackMap(this);
+ }
+
+ public final int getMapLength() { return numberOfEntries; }
+
+ /**
+ * Takes a sequence of execution frames and builds a StackMapTable attribute for them
+ */
+ public static StackMapTable forFrames(Frame[] frames,/* int[] offsets,*/ ConstantPoolGen cpg) {
+ if (debug) System.out.println("> StackMapTable.forFrames(): Building table from a set of frames");
+ if (debug) System.out.print("Offsets:");
+ for (int i = 0; i < frames.length; i++) {
+ if (debug) System.out.print(frames[i].position+" ");
+ }
+ if (debug) System.out.println();
+ try {
+ StackMapFrame[] smf = new StackMapFrame[frames.length]; // don't need the first frame, calculated from descriptor
+ int offset = 0;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(baos);
+ for (int i = 0; i < frames.length; i++) {
+ if (i==0) offset= frames[0].position; else offset = frames[i].position-frames[i-1].position-1;
+ if (offset<0) {
+ throw new RuntimeException();
+ }
+ smf[i] = StackMapFrame.forFrame(offset,frames[i],cpg);
+ smf[i].dump(dos);
+ }
+ dos.flush();dos.close();
+ int len = baos.toByteArray().length+2;
+ int nameIndex = cpg.addUtf8(Constants.ATTRIBUTE_NAMES[Constants.ATTR_STACK_MAP_TABLE]);
+ StackMapTable table = new StackMapTable(nameIndex,len,smf,cpg.getConstantPool());
+ return table;
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapType.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapType.java
index 0dd072d3b..7f986bb64 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapType.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapType.java
@@ -61,11 +61,12 @@ import java.io.*;
* This class represents the type of a local variable or item on stack
* used in the StackMap entries.
*
- * @version $Id: StackMapType.java,v 1.2 2004/11/19 16:45:18 aclement Exp $
+ * @version $Id: StackMapType.java,v 1.2.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
- * @see StackMapEntry
- * @see StackMap
+ * @see StackMapFrame
+ * @see StackMapTable
* @see Constants
+ *
*/
public final class StackMapType implements Cloneable {
private byte type;
@@ -77,13 +78,9 @@ public final class StackMapType implements Cloneable {
* @param file Input stream
* @throws IOException
*/
- StackMapType(DataInputStream file, ConstantPool constant_pool) throws IOException
- {
+ StackMapType(DataInputStream file, ConstantPool constant_pool) throws IOException {
this(file.readByte(), -1, constant_pool);
-
- if(hasIndex())
- setIndex(file.readShort());
-
+ if(hasIndex()) setIndex(file.readShort());
setConstantPool(constant_pool);
}
@@ -98,7 +95,7 @@ public final class StackMapType implements Cloneable {
}
public void setType(byte t) {
- if((t < Constants.ITEM_Bogus) || (t > Constants.ITEM_NewObject))
+ if ((t < Constants.ITEM_Top) || (t > Constants.ITEM_Uninitialized))
throw new RuntimeException("Illegal type for StackMapType: " + t);
type = t;
}
@@ -128,13 +125,13 @@ public final class StackMapType implements Cloneable {
*/
public final boolean hasIndex() {
return ((type == Constants.ITEM_Object) ||
- (type == Constants.ITEM_NewObject));
+ (type == Constants.ITEM_Uninitialized));
}
private String printIndex() {
if(type == Constants.ITEM_Object)
return ", class=" + constant_pool.constantToString(index, Constants.CONSTANT_Class);
- else if(type == Constants.ITEM_NewObject)
+ else if(type == Constants.ITEM_Uninitialized)
return ", offset=" + index;
else
return "";
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Utility.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Utility.java
index 7e1d4affe..46dc911b4 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Utility.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Utility.java
@@ -86,7 +86,7 @@ import org.aspectj.apache.bcel.util.ByteSequence;
/**
* Utility functions that do not really belong to any class in particular.
*
- * @version $Id: Utility.java,v 1.5 2006/07/19 12:06:15 aclement Exp $
+ * @version $Id: Utility.java,v 1.5.2.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*
* modified: Andy Clement 2-mar-05 Removed unnecessary static and optimized
@@ -458,11 +458,10 @@ public abstract class Utility {
if(vars != null) {
LocalVariable l = vars.getLocalVariable(var_index);
-
- if(l != null)
- buf.append(" " + l.getName());
- } else
+ if(l != null) buf.append(" " + l.getName());
+ } else {
buf.append(" arg" + var_index);
+ }
if("double".equals(param_type) || "long".equals(param_type))
var_index += 2;
@@ -778,7 +777,7 @@ public abstract class Utility {
if(left_justify)
return str + new String(buf);
- else
+
return new String(buf) + str;
}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Visitor.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Visitor.java
index 525512d31..4ad116e76 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Visitor.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Visitor.java
@@ -67,7 +67,7 @@ import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleParameterAnnot
* Implemented by wish of
* <A HREF="http://www.inf.fu-berlin.de/~bokowski">Boris Bokowski</A>.
*
- * @version $Id: Visitor.java,v 1.2 2004/11/19 16:45:18 aclement Exp $
+ * @version $Id: Visitor.java,v 1.2.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*/
public interface Visitor {
@@ -101,8 +101,8 @@ public interface Visitor {
public void visitSourceFile(SourceFile obj);
public void visitSynthetic(Synthetic obj);
public void visitUnknown(Unknown obj);
- public void visitStackMap(StackMap obj);
- public void visitStackMapEntry(StackMapEntry obj);
+ public void visitStackMap(StackMapTable obj);
+ public void visitStackMapEntry(StackMapFrame obj);
// Java5
public void visitEnclosingMethod(EnclosingMethod obj);
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/ArrayType.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/ArrayType.java
index e937a7c1d..e0877bba6 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/generic/ArrayType.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/ArrayType.java
@@ -58,7 +58,7 @@ import org.aspectj.apache.bcel.Constants;
/**
* Denotes array type, such as int[][]
*
- * @version $Id: ArrayType.java,v 1.2 2004/11/19 16:45:19 aclement Exp $
+ * @version $Id: ArrayType.java,v 1.2.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*/
public final class ArrayType extends ReferenceType {
@@ -132,7 +132,7 @@ public final class ArrayType extends ReferenceType {
public Type getElementType() {
if(dimensions == 1)
return basic_type;
- else
+
return new ArrayType(basic_type, dimensions - 1);
}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/ConstantPoolGen.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/ConstantPoolGen.java
index 686f54e25..42ac0365d 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/generic/ConstantPoolGen.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/ConstantPoolGen.java
@@ -82,7 +82,7 @@ import org.aspectj.apache.bcel.classfile.ConstantUtf8;
* Constants.MAX_SHORT entries. Note that the first (0) is used by the
* JVM and that Double and Long constants need two slots.
*
- * @version $Id: ConstantPoolGen.java,v 1.3 2004/11/22 08:31:27 aclement Exp $
+ * @version $Id: ConstantPoolGen.java,v 1.3.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @see Constant
*/
@@ -160,8 +160,9 @@ public class ConstantPoolGen implements java.io.Serializable {
delim = IMETHODREF_DELIM;
else if(c instanceof ConstantFieldref)
delim = FIELDREF_DELIM;
-
- cp_table.put(class_name + delim + method_name + delim + signature, new Index(i));
+ StringBuffer key = new StringBuffer(class_name);
+ key.append(delim).append(method_name).append(delim).append(signature);
+ cp_table.put(key.toString(), new Index(i));
}
}
}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/EmptyVisitor.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/EmptyVisitor.java
index ca983400b..8dc3aaf3b 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/generic/EmptyVisitor.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/EmptyVisitor.java
@@ -57,10 +57,10 @@ package org.aspectj.apache.bcel.generic;
/**
* Supplies empty method bodies to be overridden by subclasses.
*
- * @version $Id: EmptyVisitor.java,v 1.2 2004/11/19 16:45:18 aclement Exp $
+ * @version $Id: EmptyVisitor.java,v 1.2.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*/
-public abstract class EmptyVisitor implements Visitor {
+public class EmptyVisitor implements Visitor {
public void visitStackInstruction(StackInstruction obj) { }
public void visitLocalVariableInstruction(LocalVariableInstruction obj) { }
public void visitBranchInstruction(BranchInstruction obj) { }
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionHandle.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionHandle.java
index df4b4b547..78b134126 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionHandle.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionHandle.java
@@ -58,6 +58,7 @@ import org.aspectj.apache.bcel.classfile.Utility;
import java.util.HashSet;
import java.util.Collection;
import java.util.HashMap;
+import java.util.Iterator;
/**
* Instances of this class give users a handle to the instructions contained in
@@ -71,7 +72,7 @@ import java.util.HashMap;
* can traverse the list via an Enumeration returned by
* InstructionList.elements().
*
- * @version $Id: InstructionHandle.java,v 1.2 2004/11/19 16:45:19 aclement Exp $
+ * @version $Id: InstructionHandle.java,v 1.2.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @see Instruction
* @see BranchHandle
@@ -83,6 +84,10 @@ public class InstructionHandle implements java.io.Serializable {
protected int i_position = -1; // byte code offset of instruction
private HashSet targeters;
private HashMap attributes;
+ private int flags = 0;
+
+ private static int IS_JUMP_DESTINATION_CALCULATED = 0x0001;
+ private static int IS_JUMP_DESTINATION = 0x0002;
public final InstructionHandle getNext() { return next; }
public final InstructionHandle getPrev() { return prev; }
@@ -136,6 +141,34 @@ public class InstructionHandle implements java.io.Serializable {
return ih;
}
}
+
+ /**
+ * Return true if the instruction referenced is a jump destination, meaning it is targeted by a branch instruction or
+ */
+ public boolean isJumpDestination() {
+ if ((flags&IS_JUMP_DESTINATION_CALCULATED)!=0) return ((flags&IS_JUMP_DESTINATION)!=0);
+ if (targeters!=null) {
+ for (Iterator iter = targeters.iterator(); iter.hasNext();) {
+ InstructionTargeter targeter = (InstructionTargeter) iter.next();
+ if (targeter instanceof BranchInstruction ||
+ targeter instanceof CodeExceptionGen) {
+ boolean catchBlockEntry =false;
+ // Skip it if targeted just because exception handler catch block entry
+ if (targeter instanceof CodeExceptionGen) {
+ CodeExceptionGen ceg = (CodeExceptionGen)targeter;
+ if (ceg.getHandlerPC().getPosition()!=getPosition()) catchBlockEntry=true;
+ }
+ if (!catchBlockEntry) {
+ flags|=(IS_JUMP_DESTINATION_CALCULATED|IS_JUMP_DESTINATION);
+ return true;
+ }
+ }
+ }
+ }
+ flags|=IS_JUMP_DESTINATION_CALCULATED;
+ return false;
+ }
+
/**
* Called by InstructionList.setPositions when setting the position for every
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionList.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionList.java
index cf0fb321a..fcae5795b 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionList.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionList.java
@@ -75,7 +75,7 @@ import java.util.ArrayList;
* A list is finally dumped to a byte code array with <a
* href="#getByteCode()">getByteCode</a>.
*
- * @version $Id: InstructionList.java,v 1.4 2006/05/12 08:17:43 aclement Exp $
+ * @version $Id: InstructionList.java,v 1.4.4.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @see Instruction
* @see InstructionHandle
@@ -956,6 +956,7 @@ public class InstructionList implements Serializable {
Instruction i = ih.instruction;
ih.setPosition(index);
+
pos[count++] = index;
index += i.getLength();
}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/MethodGen.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/MethodGen.java
index e414b94e7..10b16adc9 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/generic/MethodGen.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/MethodGen.java
@@ -70,11 +70,13 @@ import org.aspectj.apache.bcel.classfile.LineNumberTable;
import org.aspectj.apache.bcel.classfile.LocalVariable;
import org.aspectj.apache.bcel.classfile.LocalVariableTable;
import org.aspectj.apache.bcel.classfile.Method;
+import org.aspectj.apache.bcel.classfile.StackMapTable;
import org.aspectj.apache.bcel.classfile.Utility;
import org.aspectj.apache.bcel.classfile.annotation.Annotation;
import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnotations;
import org.aspectj.apache.bcel.classfile.annotation.RuntimeParameterAnnotations;
import org.aspectj.apache.bcel.generic.annotation.AnnotationGen;
+import org.aspectj.apache.bcel.verifier.utility.StackMapHelper;
/**
* Template class for building up a method. This is done by defining exception
@@ -86,7 +88,7 @@ import org.aspectj.apache.bcel.generic.annotation.AnnotationGen;
* use the `removeNOPs' method to get rid off them.
* The resulting method object can be obtained via the `getMethod()' method.
*
- * @version $Id: MethodGen.java,v 1.7 2006/02/21 10:49:15 aclement Exp $
+ * @version $Id: MethodGen.java,v 1.7.4.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @author <A HREF="http://www.vmeng.com/beard">Patrick C. Beard</A> [setMaxStack()]
* @see InstructionList
@@ -703,6 +705,7 @@ public class MethodGen extends FieldGenOrMethodGen {
if(il != null)
byte_code = il.getByteCode();
+// calculateStackMapTable();
LineNumberTable lnt = null;
LocalVariableTable lvt = null;
//J5TODO: LocalVariableTypeTable support!
@@ -1144,5 +1147,41 @@ public class MethodGen extends FieldGenOrMethodGen {
l.add(annotation);
param_annotations[parameterIndex] = l;
}
+ }
+
+ private Attribute findAttribute(String name, Attribute[] all) {
+ for (int i = 0; i < all.length; i++) {
+ if (all[i].getName().equals(name)) return all[i];
+ }
+ return null;
+ }
+
+ private boolean debug = true;
+ public void calculateStackMapTable() {
+ if (il==null) return; // native method?
+// if (debug) System.out.println("> MethodGen.calculateStackMapTable() for "+getName());
+
+ // jsr check
+ InstructionHandle iHandle = il.getStart();
+ boolean hasJsr = false;
+ while (iHandle!=null && !hasJsr) {
+ Instruction ins = iHandle.getInstruction();
+ if (ins instanceof JsrInstruction || ins instanceof JSR_W) {
+ hasJsr = true;
+ }
+ iHandle = iHandle.getNext();
+ }
+ if (hasJsr) {
+ System.out.println("SKIPPING METHOD - CONTAINS JSR");
+ return;
+ }
+
+ StackMapTable stackmap = (StackMapTable)findAttribute("StackMapTable", getCodeAttributes());
+
+
+ //StackMapFrame[] smfs = stackmap.getStackMap(); // causes unpacking
+ if (stackmap!=null) removeCodeAttribute(stackmap);
+ StackMapTable smt = new StackMapHelper().produceStackMapTableAttribute(this);
+ addCodeAttribute(smt);
}
}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/generic/Type.java b/bcel-builder/src/org/aspectj/apache/bcel/generic/Type.java
index 7ea02cb45..9c7ef94ef 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/generic/Type.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/generic/Type.java
@@ -65,7 +65,7 @@ import org.aspectj.apache.bcel.classfile.Utility;
* Abstract super class for all possible java types, namely basic types
* such as int, object types like String and array types, e.g. int[]
*
- * @version $Id: Type.java,v 1.7 2006/07/19 12:06:17 aclement Exp $
+ * @version $Id: Type.java,v 1.7.2.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*
* modified:
@@ -89,9 +89,11 @@ public abstract class Type implements java.io.Serializable {
public static final ObjectType STRING = new ObjectType("java.lang.String");
public static final ObjectType STRINGBUFFER = new ObjectType("java.lang.StringBuffer");
public static final ObjectType THROWABLE = new ObjectType("java.lang.Throwable");
+ public static final ObjectType CLASS = new ObjectType("java.lang.Class");
public static final Type[] NO_ARGS = new Type[0];
public static final ReferenceType NULL = new ReferenceType(){};
public static final Type UNKNOWN = new Type(Constants.T_UNKNOWN,"<unknown object>"){};
+ public static final Type TOP = new Type(Constants.T_TOP,"<top>"){};
protected Type(byte t, String s) {
type = t;
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/Verifier.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/Verifier.java
index aa7bb1b3d..d86b150aa 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/verifier/Verifier.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/Verifier.java
@@ -59,6 +59,7 @@ import java.util.HashMap;
import java.util.Iterator;
import org.aspectj.apache.bcel.classfile.JavaClass;
+import org.aspectj.apache.bcel.classfile.Method;
import org.aspectj.apache.bcel.verifier.statics.Pass1Verifier;
import org.aspectj.apache.bcel.verifier.statics.Pass2Verifier;
import org.aspectj.apache.bcel.verifier.statics.Pass3aVerifier;
@@ -75,7 +76,7 @@ import org.aspectj.apache.bcel.verifier.structurals.Pass3bVerifier;
* A Verifier creates PassVerifier instances to perform the actual verification.
* Verifier instances are usually generated by the VerifierFactory.
*
- * @version $Id: Verifier.java,v 1.4 2004/11/22 08:31:27 aclement Exp $
+ * @version $Id: Verifier.java,v 1.4.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
* @see org.aspectj.apache.bcel.verifier.VerifierFactory
* @see org.aspectj.apache.bcel.verifier.PassVerifier
@@ -122,6 +123,16 @@ public class Verifier{
}
return p3av.verify();
}
+
+ public VerificationResult doPass3a(String methodName) {
+ Method[] ms = org.aspectj.apache.bcel.Repository.lookupClass(classname).getMethods();
+ int found=-1;
+ for (int i = 0; i < ms.length; i++) {
+ if (ms[i].getName().equals(methodName)) {found =i;break;}
+ }
+ if (found==-1) return null;
+ return doPass3a(found);
+ }
/** Returns the VerificationResult for the given pass. */
public VerificationResult doPass3b(int method_no){
@@ -134,6 +145,16 @@ public class Verifier{
}
return p3bv.verify();
}
+
+ public VerificationResult doPass3b(String methodName) {
+ Method[] ms = org.aspectj.apache.bcel.Repository.lookupClass(classname).getMethods();
+ int found=-1;
+ for (int i = 0; i < ms.length; i++) {
+ if (ms[i].getName().equals(methodName)) {found =i;break;}
+ }
+ if (found==-1) return null;
+ return doPass3b(found);
+ }
/**
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/DOUBLE_Upper.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/DOUBLE_Upper.java
index ed68a24a8..05846d02a 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/DOUBLE_Upper.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/DOUBLE_Upper.java
@@ -59,7 +59,7 @@ import org.aspectj.apache.bcel.generic.Type;
/**
* This class represents the upper half of a DOUBLE variable.
- * @version $Id: DOUBLE_Upper.java,v 1.2 2004/11/19 16:45:19 aclement Exp $
+ * @version $Id: DOUBLE_Upper.java,v 1.2.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
*/
public final class DOUBLE_Upper extends Type{
@@ -69,7 +69,7 @@ public final class DOUBLE_Upper extends Type{
/** The constructor; this class must not be instantiated from the outside. */
private DOUBLE_Upper(){
- super(Constants.T_UNKNOWN, "Long_Upper");
+ super(Constants.T_TOP, "Long_Upper");
}
/** Use this method to get the single instance of this class. */
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/LONG_Upper.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/LONG_Upper.java
index 9b1bbeae4..cdf5540d9 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/LONG_Upper.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/LONG_Upper.java
@@ -59,7 +59,7 @@ import org.aspectj.apache.bcel.generic.Type;
/**
* This class represents the upper half of a LONG variable.
- * @version $Id: LONG_Upper.java,v 1.2 2004/11/19 16:45:19 aclement Exp $
+ * @version $Id: LONG_Upper.java,v 1.2.8.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
*/
public final class LONG_Upper extends Type{
@@ -69,7 +69,7 @@ public final class LONG_Upper extends Type{
/** The constructor; this class must not be instantiated from the outside. */
private LONG_Upper(){
- super(Constants.T_UNKNOWN, "Long_Upper");
+ super(Constants.T_TOP, "Long_Upper");
}
/** Use this method to get the single instance of this class. */
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/StringRepresentation.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/StringRepresentation.java
index 24337f155..1039261c5 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/StringRepresentation.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/StringRepresentation.java
@@ -71,6 +71,7 @@ import org.aspectj.apache.bcel.classfile.ConstantString;
import org.aspectj.apache.bcel.classfile.ConstantUtf8;
import org.aspectj.apache.bcel.classfile.ConstantValue;
import org.aspectj.apache.bcel.classfile.Deprecated;
+import org.aspectj.apache.bcel.classfile.EnclosingMethod;
import org.aspectj.apache.bcel.classfile.ExceptionTable;
import org.aspectj.apache.bcel.classfile.Field;
import org.aspectj.apache.bcel.classfile.InnerClass;
@@ -85,7 +86,8 @@ import org.aspectj.apache.bcel.classfile.Method;
import org.aspectj.apache.bcel.classfile.Node;
import org.aspectj.apache.bcel.classfile.Signature;
import org.aspectj.apache.bcel.classfile.SourceFile;
-import org.aspectj.apache.bcel.classfile.StackMap;
+import org.aspectj.apache.bcel.classfile.StackMapFrame;
+import org.aspectj.apache.bcel.classfile.StackMapTable;
import org.aspectj.apache.bcel.classfile.Synthetic;
import org.aspectj.apache.bcel.classfile.Unknown;
import org.aspectj.apache.bcel.classfile.Visitor;
@@ -107,7 +109,7 @@ import org.aspectj.apache.bcel.verifier.exc.AssertionViolatedException;
* Note that this class also serves as a placeholder for more sophisticated message
* handling in future versions of JustIce.
*
- * @version $Id: StringRepresentation.java,v 1.4 2006/07/04 16:57:42 aclement Exp $
+ * @version $Id: StringRepresentation.java,v 1.4.2.1 2007/02/09 10:45:09 aclement Exp $
* @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
*/
public class StringRepresentation extends org.aspectj.apache.bcel.classfile.EmptyVisitor implements Visitor{
@@ -249,9 +251,9 @@ public class StringRepresentation extends org.aspectj.apache.bcel.classfile.Empt
public void visitSourceFile(SourceFile obj){
tostring = toString(obj);
}
- public void visitStackMap(StackMap obj){
- tostring = toString(obj);
- }
+ public void visitStackMap(StackMapTable obj){
+ tostring = toString(obj);
+ }
public void visitSynthetic(Synthetic obj){
tostring = toString(obj);
}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ControlFlowGraph.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ControlFlowGraph.java
index d64e6eb38..66a3752c0 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ControlFlowGraph.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ControlFlowGraph.java
@@ -74,7 +74,7 @@ import org.aspectj.apache.bcel.verifier.exc.StructuralCodeConstraintException;
/**
* This class represents a control flow graph of a method.
*
- * @version $Id: ControlFlowGraph.java,v 1.4 2004/11/22 08:31:27 aclement Exp $
+ * @version $Id: ControlFlowGraph.java,v 1.4.8.1 2007/02/09 10:45:08 aclement Exp $
* @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
*/
public class ControlFlowGraph{
@@ -213,7 +213,8 @@ public class ControlFlowGraph{
// instruction, but does not modify the workingFrame object.
//InstConstraintVisitor icv = InstConstraintVisitor.getInstance(VerifierFactory.getVerifier(method_gen.getClassName()));
icv.setFrame(workingFrame);
- getInstruction().accept(icv);
+ // will go bang...
+// getInstruction().accept(icv);
}
catch(StructuralCodeConstraintException ce){
ce.extendMessage("","\nInstructionHandle: "+getInstruction()+"\n");
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ExecutionVisitor.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ExecutionVisitor.java
index c4951520c..59236033d 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ExecutionVisitor.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ExecutionVisitor.java
@@ -86,7 +86,7 @@ import org.aspectj.apache.bcel.generic.*;
* If a two-slot type is stored into a local variable, the next variable
* is given the type Type.UNKNOWN.
*
- * @version $Id: ExecutionVisitor.java,v 1.5 2005/02/02 09:11:39 aclement Exp $
+ * @version $Id: ExecutionVisitor.java,v 1.5.6.1 2007/02/09 10:45:08 aclement Exp $
* @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
* @see #visitDSTORE(DSTORE o)
* @see InstConstraintVisitor
@@ -335,7 +335,7 @@ public class ExecutionVisitor extends EmptyVisitor implements Visitor{
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
public void visitDSTORE(DSTORE o){
locals().set(o.getIndex(), stack().pop());
- locals().set(o.getIndex()+1, Type.UNKNOWN);
+ locals().set(o.getIndex()+1, Type.TOP);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
public void visitDSUB(DSUB o){
@@ -1014,7 +1014,7 @@ public class ExecutionVisitor extends EmptyVisitor implements Visitor{
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
public void visitLSTORE(LSTORE o){
locals().set(o.getIndex(), stack().pop());
- locals().set(o.getIndex()+1, Type.UNKNOWN);
+ locals().set(o.getIndex()+1, Type.TOP);
}
/** Symbolically executes the corresponding Java Virtual Machine instruction. */
public void visitLSUB(LSUB o){
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/InstConstraintVisitor.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/InstConstraintVisitor.java
index 2e39d10fa..2597dc680 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/InstConstraintVisitor.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/InstConstraintVisitor.java
@@ -79,7 +79,7 @@ import org.aspectj.apache.bcel.verifier.exc.*;
* TODO: Currently, the JVM's behaviour concerning monitors (MONITORENTER,
* MONITOREXIT) is not modeled in JustIce.
*
- * @version $Id: InstConstraintVisitor.java,v 1.4 2005/02/02 09:11:39 aclement Exp $
+ * @version $Id: InstConstraintVisitor.java,v 1.4.6.1 2007/02/09 10:45:08 aclement Exp $
* @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
* @see org.aspectj.apache.bcel.verifier.exc.StructuralCodeConstraintException
* @see org.aspectj.apache.bcel.verifier.exc.LinkingConstraintException
@@ -234,12 +234,12 @@ public class InstConstraintVisitor extends EmptyVisitor implements org.aspectj.a
private void _visitStackAccessor(Instruction o){
int consume = o.consumeStack(cpg); // Stack values are always consumed first; then produced.
if (consume > stack().slotsUsed()){
- constraintViolated((Instruction) o, "Cannot consume "+consume+" stack slots: only "+stack().slotsUsed()+" slot(s) left on stack!\nStack:\n"+stack());
+ constraintViolated(o, "Cannot consume "+consume+" stack slots: only "+stack().slotsUsed()+" slot(s) left on stack!\nStack:\n"+stack());
}
- int produce = o.produceStack(cpg) - ((Instruction) o).consumeStack(cpg); // Stack values are always consumed first; then produced.
+ int produce = o.produceStack(cpg) - (o).consumeStack(cpg); // Stack values are always consumed first; then produced.
if ( produce + stack().slotsUsed() > stack().maxStack() ){
- constraintViolated((Instruction) o, "Cannot produce "+produce+" stack slots: only "+(stack().maxStack()-stack().slotsUsed())+" free stack slot(s) left.\nStack:\n"+stack());
+ constraintViolated(o, "Cannot produce "+produce+" stack slots: only "+(stack().maxStack()-stack().slotsUsed())+" free stack slot(s) left.\nStack:\n"+stack());
}
}
@@ -1645,7 +1645,7 @@ public class InstConstraintVisitor extends EmptyVisitor implements org.aspectj.a
Verifier v = VerifierFactory.getVerifier( name );
VerificationResult vr = v.doPass2();
if (vr.getStatus() != VerificationResult.VERIFIED_OK){
- constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ constraintViolated(o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
}
}
@@ -1729,7 +1729,7 @@ public class InstConstraintVisitor extends EmptyVisitor implements org.aspectj.a
Verifier v = VerifierFactory.getVerifier( name );
VerificationResult vr = v.doPass2();
if (vr.getStatus() != VerificationResult.VERIFIED_OK){
- constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ constraintViolated( o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
}
}
@@ -1810,7 +1810,7 @@ public class InstConstraintVisitor extends EmptyVisitor implements org.aspectj.a
Verifier v = VerifierFactory.getVerifier( name );
VerificationResult vr = v.doPass2();
if (vr.getStatus() != VerificationResult.VERIFIED_OK){
- constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ constraintViolated(o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
}
}
@@ -1855,7 +1855,7 @@ public class InstConstraintVisitor extends EmptyVisitor implements org.aspectj.a
Verifier v = VerifierFactory.getVerifier( name );
VerificationResult vr = v.doPass2();
if (vr.getStatus() != VerificationResult.VERIFIED_OK){
- constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ constraintViolated( o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
}
}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/LocalVariables.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/LocalVariables.java
index 44a690886..0e905c1d7 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/LocalVariables.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/LocalVariables.java
@@ -62,7 +62,7 @@ import org.aspectj.apache.bcel.verifier.exc.*;
* This class implements an array of local variables used for symbolic JVM
* simulation.
*
- * @version $Id: LocalVariables.java,v 1.2 2004/11/19 16:45:19 aclement Exp $
+ * @version $Id: LocalVariables.java,v 1.2.8.1 2007/02/09 10:45:08 aclement Exp $
* @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
*/
public class LocalVariables{
@@ -75,7 +75,7 @@ public class LocalVariables{
public LocalVariables(int maxLocals){
locals = new Type[maxLocals];
for (int i=0; i<maxLocals; i++){
- locals[i] = Type.UNKNOWN;
+ locals[i] = Type.TOP;
}
}
@@ -122,6 +122,9 @@ public class LocalVariables{
if (type == Type.BYTE || type == Type.SHORT || type == Type.BOOLEAN || type == Type.CHAR){
throw new AssertionViolatedException("LocalVariables do not know about '"+type+"'. Use Type.INT instead.");
}
+ if (type==Type.TOP) {
+ int stop =1;
+ }
locals[i] = type;
}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/Pass3bVerifier.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/Pass3bVerifier.java
index b2375a9c6..cd344e69d 100644
--- a/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/Pass3bVerifier.java
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/Pass3bVerifier.java
@@ -57,7 +57,6 @@ package org.aspectj.apache.bcel.verifier.structurals;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
-import java.util.Random;
import java.util.Vector;
import org.aspectj.apache.bcel.Constants;
@@ -86,7 +85,7 @@ import org.aspectj.apache.bcel.verifier.exc.VerifierConstraintViolatedException;
* More detailed information is to be found at the do_verify() method's
* documentation.
*
- * @version $Id: Pass3bVerifier.java,v 1.5 2005/02/02 09:11:39 aclement Exp $
+ * @version $Id: Pass3bVerifier.java,v 1.5.6.1 2007/02/09 10:45:08 aclement Exp $
* @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
* @see #do_verify()
*/
@@ -155,44 +154,34 @@ public final class Pass3bVerifier extends PassVerifier{
myOwner = owner;
this.method_no = method_no;
}
+
+ public Pass3bVerifier() {}
/**
- * Whenever the outgoing frame
- * situation of an InstructionContext changes, all its successors are
- * put [back] into the queue [as if they were unvisited].
- * The proof of termination is about the existence of a
- * fix point of frame merging.
+ * Whenever the outgoing frame situation of an InstructionContext changes,
+ * all its successors are put [back] into the queue [as if they were unvisited].
+ * The proof of termination is about the existence of a fix point of frame merging.
*/
- private void circulationPump(ControlFlowGraph cfg, InstructionContext start, Frame vanillaFrame, InstConstraintVisitor icv, ExecutionVisitor ev){
- final Random random = new Random();
- InstructionContextQueue icq = new InstructionContextQueue();
+ private void circulationPump(ControlFlowGraph cfg, InstructionContext start,
+ Frame vanillaFrame, InstConstraintVisitor icv, ExecutionVisitor ev){
+
+ InstructionContextQueue contextQueue = new InstructionContextQueue();
start.execute(vanillaFrame, new ArrayList(), icv, ev); // new ArrayList() <=> no Instruction was executed before
- // => Top-Level routine (no jsr call before)
- icq.add(start, new ArrayList());
+ // => Top-Level routine (no jsr call before)
+ contextQueue.add(start, new ArrayList());
- // LOOP!
- while (!icq.isEmpty()){
- InstructionContext u;
- ArrayList ec;
- if (!DEBUG){
- int r = random.nextInt(icq.size());
- u = icq.getIC(r);
- ec = icq.getEC(r);
- icq.remove(r);
- }
- else{
- u = icq.getIC(0);
- ec = icq.getEC(0);
- icq.remove(0);
- }
+ while (!contextQueue.isEmpty()){
+ InstructionContext u = contextQueue.getIC(0);
+ ArrayList ec = contextQueue.getEC(0);
+ contextQueue.remove(0);
ArrayList oldchain = (ArrayList) (ec.clone());
ArrayList newchain = (ArrayList) (ec.clone());
newchain.add(u);
if ((u.getInstruction().getInstruction()) instanceof RET){
-//System.err.println(u);
+ //System.err.println(u);
// We can only follow _one_ successor, the one after the
// JSR that was recently executed.
RET ret = (RET) (u.getInstruction().getInstruction());
@@ -206,7 +195,7 @@ public final class Pass3bVerifier extends PassVerifier{
if (skip_jsr < 0){
throw new AssertionViolatedException("More RET than JSR in execution chain?!");
}
-//System.err.println("+"+oldchain.get(ss));
+ //System.err.println("+"+oldchain.get(ss));
if (((InstructionContext) oldchain.get(ss)).getInstruction().getInstruction() instanceof JsrInstruction){
if (skip_jsr == 0){
lastJSR = (InstructionContext) oldchain.get(ss);
@@ -229,7 +218,7 @@ public final class Pass3bVerifier extends PassVerifier{
}
if (theSuccessor.execute(u.getOutFrame(oldchain), newchain, icv, ev)){
- icq.add(theSuccessor, (ArrayList) newchain.clone());
+ contextQueue.add(theSuccessor, (ArrayList) newchain.clone());
}
}
else{// "not a ret"
@@ -239,7 +228,7 @@ public final class Pass3bVerifier extends PassVerifier{
for (int s=0; s<succs.length; s++){
InstructionContext v = succs[s];
if (v.execute(u.getOutFrame(oldchain), newchain, icv, ev)){
- icq.add(v, (ArrayList) newchain.clone());
+ contextQueue.add(v, (ArrayList) newchain.clone());
}
}
}// end "not a ret"
@@ -260,7 +249,7 @@ public final class Pass3bVerifier extends PassVerifier{
//if (v.execute(new Frame(u.getOutFrame(oldchain).getLocals(), new OperandStack (u.getOutFrame().getStack().maxStack(), (exc_hds[s].getExceptionType()==null? Type.THROWABLE : exc_hds[s].getExceptionType())) ), newchain), icv, ev){
//icq.add(v, (ArrayList) newchain.clone());
if (v.execute(new Frame(u.getOutFrame(oldchain).getLocals(), new OperandStack (u.getOutFrame(oldchain).getStack().maxStack(), (exc_hds[s].getExceptionType()==null? Type.THROWABLE : exc_hds[s].getExceptionType())) ), new ArrayList(), icv, ev)){
- icq.add(v, new ArrayList());
+ contextQueue.add(v, new ArrayList());
}
}
@@ -370,6 +359,8 @@ public final class Pass3bVerifier extends PassVerifier{
}
return VerificationResult.VR_OK;
}
+
+
/** Returns the method number as supplied when instantiating. */
public int getMethodNo(){
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ControlFlowGraph.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ControlFlowGraph.java
new file mode 100644
index 000000000..5ca4dfd7e
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ControlFlowGraph.java
@@ -0,0 +1,140 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import java.util.Hashtable;
+
+import org.aspectj.apache.bcel.generic.InstructionHandle;
+import org.aspectj.apache.bcel.generic.MethodGen;
+import org.aspectj.apache.bcel.verifier.exc.AssertionViolatedException;
+
+/**
+ * This class represents a control flow graph of a method.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class ControlFlowGraph {
+
+ // The MethodGen object we're working on
+ private final MethodGen method;
+
+ // The Subroutines for the method
+ final Subroutines subroutines;
+
+ // The ExceptionHandlers object for the method
+ final ExceptionHandlers exceptionhandlers;
+
+ // All InstructionContext instances of this ControlFlowGraph
+ private Hashtable /*InstructionHandle > InstructionContextImpl*/ instructionContexts = new Hashtable();
+
+ // ---
+ public Subroutines getSubroutines() {
+ return subroutines;
+ }
+
+ public ControlFlowGraph(MethodGen method){
+ subroutines = new Subroutines(method);
+ exceptionhandlers = new ExceptionHandlers(method);
+
+ InstructionHandle[] instructionhandles = method.getInstructionList().getInstructionHandles();
+ for (int i=0; i<instructionhandles.length; i++) {
+ instructionContexts.put(instructionhandles[i], new InstructionContextImpl(this, instructionhandles[i]));
+ }
+
+ this.method = method;
+ }
+
+ /**
+ * Returns the InstructionContext of a given instruction.
+ */
+ public InstructionContext contextOf(InstructionHandle inst){
+ InstructionContext ic = (InstructionContext) instructionContexts.get(inst);
+ if (ic == null){
+ throw new AssertionViolatedException("InstructionContext requested for an InstructionHandle that's not known!");
+ }
+ return ic;
+ }
+
+ /**
+ * Returns the InstructionContext[] of a given InstructionHandle[],
+ * in a naturally ordered manner.
+ */
+ public InstructionContext[] contextsOf(InstructionHandle[] insts){
+ InstructionContext[] ret = new InstructionContext[insts.length];
+ for (int i=0; i<insts.length; i++){
+ ret[i] = contextOf(insts[i]);
+ }
+ return ret;
+ }
+
+ /**
+ * Returns an InstructionContext[] with all the InstructionContext instances
+ * for the method whose control flow is represented by this ControlFlowGraph
+ * <B>(NOT ORDERED!)</B>.
+ */
+ public InstructionContext[] getInstructionContexts(){
+ InstructionContext[] ret = new InstructionContext[instructionContexts.values().size()];
+ return (InstructionContext[]) instructionContexts.values().toArray(ret);
+ }
+
+ /**
+ * Returns true, if and only if the said instruction is not reachable; that means,
+ * if it not part of this ControlFlowGraph.
+ */
+ public boolean isDead(InstructionHandle i){
+ return instructionContexts.containsKey(i);
+ }
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExceptionHandler.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExceptionHandler.java
new file mode 100644
index 000000000..62a29e1ff
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExceptionHandler.java
@@ -0,0 +1,93 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.aspectj.apache.bcel.generic.*;
+
+/**
+ * This class represents an exception handler; that is, an ObjectType
+ * representing a subclass of java.lang.Throwable and the instruction
+ * the handler starts off (represented by an InstructionContext).
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class ExceptionHandler{
+ /** The type of the exception to catch. NULL means ANY. */
+ private ObjectType catchtype;
+
+ /** The InstructionHandle where the handling begins. */
+ private InstructionHandle handlerpc;
+
+ /** Leave instance creation to JustIce. */
+ ExceptionHandler(ObjectType catch_type, InstructionHandle handler_pc){
+ catchtype = catch_type;
+ handlerpc = handler_pc;
+ }
+
+ /**
+ * Returns the type of the exception that's handled. <B>'null' means 'ANY'.</B>
+ */
+ public ObjectType getExceptionType(){
+ return catchtype;
+ }
+
+ /**
+ * Returns the InstructionHandle where the handler starts off.
+ */
+ public InstructionHandle getHandlerStart(){
+ return handlerpc;
+ }
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExceptionHandlers.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExceptionHandlers.java
new file mode 100644
index 000000000..ee59b587f
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExceptionHandlers.java
@@ -0,0 +1,112 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.aspectj.apache.bcel.generic.*;
+import java.util.HashSet;
+import java.util.Hashtable;
+
+/**
+ * This class allows easy access to ExceptionHandler objects.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class ExceptionHandlers{
+ /**
+ * The ExceptionHandler instances.
+ * Key: InstructionHandle objects, Values: HashSet<ExceptionHandler> instances.
+ */
+ private Hashtable exceptionhandlers;
+
+ /**
+ * Constructor. Creates a new ExceptionHandlers instance.
+ */
+ public ExceptionHandlers(MethodGen mg){
+ exceptionhandlers = new Hashtable();
+ CodeExceptionGen[] cegs = mg.getExceptionHandlers();
+ for (int i=0; i<cegs.length; i++){
+ ExceptionHandler eh = new ExceptionHandler(cegs[i].getCatchType(), cegs[i].getHandlerPC());
+ for (InstructionHandle ih=cegs[i].getStartPC(); ih != cegs[i].getEndPC().getNext(); ih=ih.getNext()) {
+ if (ih==cegs[i].getStartPC() ||
+ ih.getInstruction() instanceof ExceptionThrower ||
+ ih.getInstruction() instanceof ASTORE) {
+ HashSet hs;
+ hs = (HashSet) exceptionhandlers.get(ih);
+ if (hs == null){
+ hs = new HashSet();
+ exceptionhandlers.put(ih, hs);
+ }
+ hs.add(eh);
+ }
+ }
+ }
+// System.out.println("ExceptionHandler size is "+exceptionhandlers.keySet().size());
+ }
+
+ /**
+ * Returns all the ExceptionHandler instances representing exception
+ * handlers that protect the instruction ih.
+ */
+ public ExceptionHandler[] getExceptionHandlers(InstructionHandle ih){
+ HashSet hs = (HashSet) exceptionhandlers.get(ih);
+ if (hs == null) return new ExceptionHandler[0];
+ else{
+ ExceptionHandler[] ret = new ExceptionHandler[hs.size()];
+ return (ExceptionHandler[]) (hs.toArray(ret));
+ }
+ }
+
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExecutionVisitor.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExecutionVisitor.java
new file mode 100644
index 000000000..86b34ba77
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExecutionVisitor.java
@@ -0,0 +1,1143 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.aspectj.apache.bcel.Constants;
+import org.aspectj.apache.bcel.classfile.Constant;
+import org.aspectj.apache.bcel.classfile.ConstantClass;
+import org.aspectj.apache.bcel.classfile.ConstantDouble;
+import org.aspectj.apache.bcel.classfile.ConstantFloat;
+import org.aspectj.apache.bcel.classfile.ConstantInteger;
+import org.aspectj.apache.bcel.classfile.ConstantLong;
+import org.aspectj.apache.bcel.classfile.ConstantString;
+import org.aspectj.apache.bcel.generic.*;
+
+/**
+ * This Visitor class may be used for a type-based Java Virtual Machine
+ * simulation.
+ * It does not check for correct types on the OperandStack or in the
+ * LocalVariables; nor does it check their sizes are sufficiently big.
+ * Thus, to use this Visitor for bytecode verifying, you have to make sure
+ * externally that the type constraints of the Java Virtual Machine instructions
+ * are satisfied. An InstConstraintVisitor may be used for this.
+ * Anyway, this Visitor does not mandate it. For example, when you
+ * visitIADD(IADD o), then there are two stack slots popped and one
+ * stack slot containing a Type.INT is pushed (where you could also
+ * pop only one slot if you know there are two Type.INT on top of the
+ * stack). Monitor-specific behaviour is not simulated.
+ *
+ * </P><B>Conventions:</B>
+ *
+ * Type.VOID will never be pushed onto the stack. Type.DOUBLE and Type.LONG
+ * that would normally take up two stack slots (like Double_HIGH and
+ * Double_LOW) are represented by a simple single Type.DOUBLE or Type.LONG
+ * object on the stack here.
+ * If a two-slot type is stored into a local variable, the next variable
+ * is given the type Type.UNKNOWN.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see #visitDSTORE(DSTORE o)
+ * @see InstConstraintVisitor
+ */
+public class ExecutionVisitor extends EmptyVisitor implements Visitor{
+
+ /**
+ * The executionframe we're operating on.
+ */
+ private Frame frame = null;
+
+ /**
+ * The ConstantPoolGen we're working with.
+ * @see #setConstantPoolGen(ConstantPoolGen)
+ */
+ private ConstantPoolGen cpg = null;
+
+ /**
+ * Constructor. Constructs a new instance of this class.
+ */
+ public ExecutionVisitor(){}
+ public ExecutionVisitor(ConstantPoolGen cpg) {this.cpg=cpg;}
+
+ boolean isJava5OrLater = true;
+
+ private int pos;
+ /**
+ * The OperandStack from the current Frame we're operating on.
+ * @see #setFrame(Frame)
+ */
+ private OperandStack stack(){
+ return frame.getStack();
+ }
+
+ /**
+ * The LocalVariables from the current Frame we're operating on.
+ * @see #setFrame(Frame)
+ */
+ private LocalVariables locals(){
+ return frame.getLocals();
+ }
+
+ /**
+ * Sets the ConstantPoolGen needed for symbolic execution.
+ */
+ public void setConstantPoolGen(ConstantPoolGen cpg){
+ this.cpg = cpg;
+ }
+
+ /**
+ * The only method granting access to the single instance of
+ * the ExecutionVisitor class. Before actively using this
+ * instance, <B>SET THE ConstantPoolGen FIRST</B>.
+ * @see #setConstantPoolGen(ConstantPoolGen)
+ */
+ public void setFrame(Frame f){
+ this.frame = f;
+ }
+
+ ///** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ //public void visitWIDE(WIDE o){
+ // The WIDE instruction is modelled as a flag
+ // of the embedded instructions in BCEL.
+ // Therefore BCEL checks for possible errors
+ // when parsing in the .class file: We don't
+ // have even the possibilty to care for WIDE
+ // here.
+ //}
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitAALOAD(AALOAD o){
+ stack().pop(); // pop the index int
+//System.out.print(stack().peek());
+ Type t = stack().pop(); // Pop Array type
+ if (t == Type.NULL){
+ stack().push(Type.NULL);
+ } // Do nothing stackwise --- a NullPointerException is thrown at Run-Time
+ else{
+ ArrayType at = (ArrayType) t;
+ stack().push(at.getElementType());
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitAASTORE(AASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitACONST_NULL(ACONST_NULL o){
+ stack().push(Type.NULL);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitALOAD(ALOAD o){
+ stack().push(locals().get(o.getIndex()));
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitANEWARRAY(ANEWARRAY o){
+ stack().pop(); //count
+ stack().push( new ArrayType(o.getType(cpg), 1) );
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitARETURN(ARETURN o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitARRAYLENGTH(ARRAYLENGTH o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitASTORE(ASTORE o){
+ locals().set(o.getIndex(), stack().pop());
+// System.err.println("TODO-DEBUG: set LV '"+o.getIndex()+"' to '"+locals().get(o.getIndex())+"'.");
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitATHROW(ATHROW o){
+ Type t = stack().pop();
+ stack().clear();
+ if (t.equals(Type.NULL))
+ stack().push(Type.getType("Ljava/lang/NullPointerException;"));
+ else
+ stack().push(t);
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitBALOAD(BALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitBASTORE(BASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitBIPUSH(BIPUSH o){
+ stack().push(Type.INT);
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitCALOAD(CALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitCASTORE(CASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitCHECKCAST(CHECKCAST o){
+ // It's possibly wrong to do so, but SUN's
+ // ByteCode verifier seems to do (only) this, too.
+ // TODO: One could use a sophisticated analysis here to check
+ // if a type cannot possibly be cated to another and by
+ // so doing predict the ClassCastException at run-time.
+ stack().pop();
+ stack().push(o.getType(cpg));
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitD2F(D2F o){
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitD2I(D2I o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitD2L(D2L o){
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDADD(DADD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDALOAD(DALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDASTORE(DASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDCMPG(DCMPG o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDCMPL(DCMPL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDCONST(DCONST o){
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDDIV(DDIV o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDLOAD(DLOAD o){
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDMUL(DMUL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDNEG(DNEG o){
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDREM(DREM o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDRETURN(DRETURN o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDSTORE(DSTORE o){
+ locals().set(o.getIndex(), stack().pop());
+ locals().set(o.getIndex()+1, Type.TOP);//UNKNOWN);//fubar
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDSUB(DSUB o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDUP(DUP o){
+ Type t = stack().pop();
+ stack().push(t);
+ stack().push(t);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDUP_X1(DUP_X1 o){
+ Type w1 = stack().pop();
+ Type w2 = stack().pop();
+ stack().push(w1);
+ stack().push(w2);
+ stack().push(w1);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDUP_X2(DUP_X2 o){
+ Type w1 = stack().pop();
+ Type w2 = stack().pop();
+ if (w2.getSize() == 2){
+ stack().push(w1);
+ stack().push(w2);
+ stack().push(w1);
+ }
+ else{
+ Type w3 = stack().pop();
+ stack().push(w1);
+ stack().push(w3);
+ stack().push(w2);
+ stack().push(w1);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDUP2(DUP2 o){
+ Type t = stack().pop();
+ if (t.getSize() == 2){
+ stack().push(t);
+ stack().push(t);
+ }
+ else{ // t.getSize() is 1
+ Type u = stack().pop();
+ stack().push(u);
+ stack().push(t);
+ stack().push(u);
+ stack().push(t);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDUP2_X1(DUP2_X1 o){
+ Type t = stack().pop();
+ if (t.getSize() == 2){
+ Type u = stack().pop();
+ stack().push(t);
+ stack().push(u);
+ stack().push(t);
+ }
+ else{ //t.getSize() is1
+ Type u = stack().pop();
+ Type v = stack().pop();
+ stack().push(u);
+ stack().push(t);
+ stack().push(v);
+ stack().push(u);
+ stack().push(t);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitDUP2_X2(DUP2_X2 o){
+ Type t = stack().pop();
+ if (t.getSize() == 2){
+ Type u = stack().pop();
+ if (u.getSize() == 2){
+ stack().push(t);
+ stack().push(u);
+ stack().push(t);
+ }else{
+ Type v = stack().pop();
+ stack().push(t);
+ stack().push(v);
+ stack().push(u);
+ stack().push(t);
+ }
+ }
+ else{ //t.getSize() is 1
+ Type u = stack().pop();
+ Type v = stack().pop();
+ if (v.getSize() == 2){
+ stack().push(u);
+ stack().push(t);
+ stack().push(v);
+ stack().push(u);
+ stack().push(t);
+ }else{
+ Type w = stack().pop();
+ stack().push(u);
+ stack().push(t);
+ stack().push(w);
+ stack().push(v);
+ stack().push(u);
+ stack().push(t);
+ }
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitF2D(F2D o){
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitF2I(F2I o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitF2L(F2L o){
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFADD(FADD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFALOAD(FALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFASTORE(FASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFCMPG(FCMPG o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFCMPL(FCMPL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFCONST(FCONST o){
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFDIV(FDIV o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFLOAD(FLOAD o){
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFMUL(FMUL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFNEG(FNEG o){
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFREM(FREM o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFRETURN(FRETURN o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFSTORE(FSTORE o){
+ locals().set(o.getIndex(), stack().pop());
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitFSUB(FSUB o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitGETFIELD(GETFIELD o){
+ stack().pop();
+ Type t = o.getFieldType(cpg);
+ if ( t.equals(Type.BOOLEAN) ||
+ t.equals(Type.CHAR) ||
+ t.equals(Type.BYTE) ||
+ t.equals(Type.SHORT) )
+ t = Type.INT;
+ stack().push(t);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitGETSTATIC(GETSTATIC o){
+ Type t = o.getFieldType(cpg);
+ if ( t.equals(Type.BOOLEAN) ||
+ t.equals(Type.CHAR) ||
+ t.equals(Type.BYTE) ||
+ t.equals(Type.SHORT) )
+ t = Type.INT;
+ stack().push(t);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitGOTO(GOTO o){
+ // no stack changes.
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitGOTO_W(GOTO_W o){
+ // no stack changes.
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitI2B(I2B o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitI2C(I2C o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitI2D(I2D o){
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitI2F(I2F o){
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitI2L(I2L o){
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitI2S(I2S o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIADD(IADD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIALOAD(IALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIAND(IAND o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIASTORE(IASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitICONST(ICONST o){
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIDIV(IDIV o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ACMPEQ(IF_ACMPEQ o){
+ if (stack().size()<2) {
+ int stop = 1;
+ }
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ACMPNE(IF_ACMPNE o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ICMPEQ(IF_ICMPEQ o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ICMPGE(IF_ICMPGE o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ICMPGT(IF_ICMPGT o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ICMPLE(IF_ICMPLE o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ICMPLT(IF_ICMPLT o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIF_ICMPNE(IF_ICMPNE o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFEQ(IFEQ o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFGE(IFGE o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFGT(IFGT o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFLE(IFLE o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFLT(IFLT o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFNE(IFNE o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFNONNULL(IFNONNULL o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIFNULL(IFNULL o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIINC(IINC o){
+ // stack is not changed.
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitILOAD(ILOAD o){
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIMUL(IMUL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitINEG(INEG o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitINSTANCEOF(INSTANCEOF o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitINVOKEINTERFACE(INVOKEINTERFACE o){
+ stack().pop(); //objectref
+// for (int i=0; i<o.getArgumentTypes(cpg).length; i++){
+// stack().pop();
+// }
+ Type[] args = o.getArgumentTypes(cpg);
+ int size=0;
+ for (int i = 0; i < args.length; i++) { size+=args[i].getSize();}
+ for (int i=0;i<size;i++) stack().pop();
+ // We are sure the invoked method will xRETURN eventually
+ // We simulate xRETURNs functionality here because we
+ // don't really "jump into" and simulate the invoked
+ // method.
+ if (o.getReturnType(cpg) != Type.VOID){
+ Type t = o.getReturnType(cpg);
+ if ( t.equals(Type.BOOLEAN) ||
+ t.equals(Type.CHAR) ||
+ t.equals(Type.BYTE) ||
+ t.equals(Type.SHORT) )
+ t = Type.INT;
+ stack().push(t);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitINVOKESPECIAL(INVOKESPECIAL o){
+ if (o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME)){
+ Type[] args = o.getArgumentTypes(cpg);
+ int size=0;
+ for (int i = 0; i < args.length; i++) { size+=args[i].getSize();}
+ UninitializedObjectType t = (UninitializedObjectType) stack().peek(size);
+ if (t == Frame._this){
+ Frame._this = null;
+ }
+ stack().initializeObject(t);
+ locals().initializeObject(t);
+ }
+ stack().pop(); //objectref
+ for (int i=0; i<o.getArgumentTypes(cpg).length; i++){
+ stack().pop();
+ }
+ // We are sure the invoked method will xRETURN eventually
+ // We simulate xRETURNs functionality here because we
+ // don't really "jump into" and simulate the invoked
+ // method.
+ if (o.getReturnType(cpg) != Type.VOID){
+ Type t = o.getReturnType(cpg);
+ if ( t.equals(Type.BOOLEAN) ||
+ t.equals(Type.CHAR) ||
+ t.equals(Type.BYTE) ||
+ t.equals(Type.SHORT) )
+ t = Type.INT;
+ stack().push(t);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitINVOKESTATIC(INVOKESTATIC o){
+ for (int i=0; i<o.getArgumentTypes(cpg).length; i++){
+ stack().pop();
+ }
+ // We are sure the invoked method will xRETURN eventually
+ // We simulate xRETURNs functionality here because we
+ // don't really "jump into" and simulate the invoked
+ // method.
+ if (o.getReturnType(cpg) != Type.VOID){
+ Type t = o.getReturnType(cpg);
+ if ( t.equals(Type.BOOLEAN) ||
+ t.equals(Type.CHAR) ||
+ t.equals(Type.BYTE) ||
+ t.equals(Type.SHORT) )
+ t = Type.INT;
+ stack().push(t);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitINVOKEVIRTUAL(INVOKEVIRTUAL o){
+ stack().pop(); //objectref
+ for (int i=0; i<o.getArgumentTypes(cpg).length; i++){
+ stack().pop();
+ }
+ // We are sure the invoked method will xRETURN eventually
+ // We simulate xRETURNs functionality here because we
+ // don't really "jump into" and simulate the invoked
+ // method.
+ if (o.getReturnType(cpg) != Type.VOID){
+ Type t = o.getReturnType(cpg);
+ if ( t.equals(Type.BOOLEAN) ||
+ t.equals(Type.CHAR) ||
+ t.equals(Type.BYTE) ||
+ t.equals(Type.SHORT) )
+ t = Type.INT;
+ stack().push(t);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIOR(IOR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIREM(IREM o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIRETURN(IRETURN o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitISHL(ISHL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitISHR(ISHR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitISTORE(ISTORE o){
+ locals().set(o.getIndex(), stack().pop());
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitISUB(ISUB o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIUSHR(IUSHR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitIXOR(IXOR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitJSR(JSR o){
+ stack().push(new ReturnaddressType(o.physicalSuccessor()));
+//System.err.println("TODO-----------:"+o.physicalSuccessor());
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitJSR_W(JSR_W o){
+ stack().push(new ReturnaddressType(o.physicalSuccessor()));
+ }
+
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitL2D(L2D o){
+ stack().pop();
+ stack().push(Type.DOUBLE);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitL2F(L2F o){
+ stack().pop();
+ stack().push(Type.FLOAT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitL2I(L2I o){
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLADD(LADD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLALOAD(LALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLAND(LAND o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLASTORE(LASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLCMP(LCMP o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLCONST(LCONST o){
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLDC(LDC o){
+ Constant c = cpg.getConstant(o.getIndex());
+ if (c instanceof ConstantInteger){
+ stack().push(Type.INT);
+ } else if (c instanceof ConstantFloat){
+ stack().push(Type.FLOAT);
+ return;
+ } else if (c instanceof ConstantString){
+ stack().push(Type.STRING);
+ } else if (c instanceof ConstantClass && isJava5OrLater) {
+ stack().push(Type.CLASS);
+ } else {
+ throw new RuntimeException("Incorrect constant type for LDC: "+c);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLDC_W(LDC_W o){
+ Constant c = cpg.getConstant(o.getIndex());
+ if (c instanceof ConstantInteger){
+ stack().push(Type.INT);
+ } else if (c instanceof ConstantFloat){
+ stack().push(Type.FLOAT);
+ } else if (c instanceof ConstantString){
+ stack().push(Type.STRING);
+ } else if (c instanceof ConstantClass && isJava5OrLater) {
+ stack().push(Type.CLASS);
+ } else {
+ throw new RuntimeException("Incorrect constant type for LDC_W");
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLDC2_W(LDC2_W o){
+ Constant c = cpg.getConstant(o.getIndex());
+ if (c instanceof ConstantLong){
+ stack().push(Type.LONG);
+ }
+ if (c instanceof ConstantDouble){
+ stack().push(Type.DOUBLE);
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLDIV(LDIV o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLLOAD(LLOAD o){
+ stack().push(locals().get(o.getIndex()));
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLMUL(LMUL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLNEG(LNEG o){
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLOOKUPSWITCH(LOOKUPSWITCH o){
+ stack().pop(); //key
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLOR(LOR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLREM(LREM o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLRETURN(LRETURN o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLSHL(LSHL o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLSHR(LSHR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLSTORE(LSTORE o){
+ locals().set(o.getIndex(), stack().pop());
+ locals().set(o.getIndex()+1, Type.TOP);//UNKNOWN); //fubar
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLSUB(LSUB o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLUSHR(LUSHR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitLXOR(LXOR o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.LONG);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitMONITORENTER(MONITORENTER o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitMONITOREXIT(MONITOREXIT o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitMULTIANEWARRAY(MULTIANEWARRAY o){
+ for (int i=0; i<o.getDimensions(); i++){
+ stack().pop();
+ }
+ stack().push(o.getType(cpg));
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitNEW(NEW o){
+ stack().push(new UninitializedObjectType((ObjectType) (o.getType(cpg)),false,pos));
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitNEWARRAY(NEWARRAY o){
+ stack().pop();
+ stack().push(o.getType());
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitNOP(NOP o){
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitPOP(POP o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitPOP2(POP2 o){
+ Type t = stack().pop();
+ if (t.getSize() == 1){
+ stack().pop();
+ }
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitPUTFIELD(PUTFIELD o){
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitPUTSTATIC(PUTSTATIC o){
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitRET(RET o){
+ // do nothing, return address
+ // is in in the local variables.
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitRETURN(RETURN o){
+ // do nothing.
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitSALOAD(SALOAD o){
+ stack().pop();
+ stack().pop();
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitSASTORE(SASTORE o){
+ stack().pop();
+ stack().pop();
+ stack().pop();
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitSIPUSH(SIPUSH o){
+ stack().push(Type.INT);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitSWAP(SWAP o){
+ Type t = stack().pop();
+ Type u = stack().pop();
+ stack().push(t);
+ stack().push(u);
+ }
+ /** Symbolically executes the corresponding Java Virtual Machine instruction. */
+ public void visitTABLESWITCH(TABLESWITCH o){
+ stack().pop();
+ }
+ public void setPosition(int position) {
+ this.pos = position;
+ }
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Frame.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Frame.java
new file mode 100644
index 000000000..c20bf1b0e
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Frame.java
@@ -0,0 +1,375 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.aspectj.apache.bcel.Constants;
+import org.aspectj.apache.bcel.classfile.ConstantClass;
+import org.aspectj.apache.bcel.classfile.ConstantPool;
+import org.aspectj.apache.bcel.classfile.StackMapFrame;
+import org.aspectj.apache.bcel.classfile.StackMapType;
+import org.aspectj.apache.bcel.generic.ArrayType;
+import org.aspectj.apache.bcel.generic.BasicType;
+import org.aspectj.apache.bcel.generic.ConstantPoolGen;
+import org.aspectj.apache.bcel.generic.ObjectType;
+import org.aspectj.apache.bcel.generic.Type;
+import org.aspectj.apache.bcel.generic.Type.TypeHolder;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+
+/**
+ * This class represents a JVM execution frame; that means, a local variable array and an operand stack.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+
+public class Frame {
+
+ /**
+ * For instance initialization methods, it is important to remember
+ * which instance it is that is not initialized yet. It will be
+ * initialized invoking another constructor later.
+ * NULL means the instance already *is* initialized.
+ */
+ protected static UninitializedObjectType _this;
+
+ private LocalVariables locals;
+ private OperandStack stack;
+
+ public int position; // used for stackmapframe creation
+
+ // ---
+ public Frame(int maxLocals, int maxStack){
+ locals = new LocalVariables(maxLocals);
+ stack = new OperandStack(maxStack);
+ }
+
+ public Frame(LocalVariables locals, OperandStack stack){
+ this.locals = locals;
+ this.stack = stack;
+ }
+
+ // ===
+
+ protected Object clone() {
+ Frame f = new Frame(locals.getClone(), stack.getClone());
+ return f;
+ }
+
+ public Frame getClone() {
+ return (Frame) clone();
+ }
+
+ public LocalVariables getLocals() { return locals; }
+ public OperandStack getStack() { return stack; }
+
+ public boolean equals(Object o){
+ if (!(o instanceof Frame)) return false; // implies "null" is non-equal.
+ Frame f = (Frame) o;
+ return this.stack.equals(f.stack) && this.locals.equals(f.locals);
+ }
+
+ /**
+ * Returns a String representation of the Frame instance.
+ */
+ public String toString(){
+ StringBuffer sb = new StringBuffer();
+ sb.append("FRAMELOCS"+locals.toCompactString()).append("\n");
+ sb.append("FRAMESTAK"+stack.toCompactString()).append("\n");
+ return sb.toString();
+ }
+
+ public String toString(String prefix){
+ StringBuffer sb = new StringBuffer();
+ sb.append(prefix).append("FRAMELOCS"+locals.toCompactString()).append("\n");
+ sb.append(prefix).append("FRAMESTAK"+stack.toCompactString());
+ return sb.toString();
+ }
+
+ private int addLocal(int pos,StackMapType smType) {
+ byte itemkey = smType.getType();
+ ConstantPool cp = smType.getConstantPool();
+ if (debug) System.out.println(">>"+Constants.ITEM_NAMES[itemkey]);
+ switch (itemkey) {
+
+ // single slot items
+ case Constants.ITEM_Integer:
+ locals.set(pos++, BasicType.INT);
+ return 1;
+ case Constants.ITEM_Object:
+ ConstantClass c = (ConstantClass)cp.getConstant(smType.getIndex(), Constants.CONSTANT_Class);
+ String sig = c.getBytes(cp);
+ if (sig.charAt(0)!='[') sig = "L"+sig+";";
+ TypeHolder th = Type.getTypeInternal(sig);
+ locals.set(pos++,th.getType());//new ObjectType(c.getBytes(cp)));
+ return 1;
+
+ case Constants.ITEM_Top:
+ locals.set(pos++,Type.TOP/*Top - why is it not Top? */);return 1;
+
+
+ case Constants.ITEM_Float:
+ case Constants.ITEM_Null:
+ case Constants.ITEM_UninitializedThis:
+ case Constants.ITEM_Uninitialized:
+
+ // double slot items
+ case Constants.ITEM_Double:
+ case Constants.ITEM_Long:
+ throw new RuntimeException("Frame.addLocal() - need to implement support for "+Constants.ITEM_NAMES[itemkey]);
+ }
+ return 0;
+ }
+
+ private int addStack(StackMapType smType) {
+ byte itemkey = smType.getType();
+ ConstantPool cp = smType.getConstantPool();
+ if (debug) System.out.println(">>"+Constants.ITEM_NAMES[itemkey]);
+ switch (itemkey) {
+
+ // single slot items
+ case Constants.ITEM_Integer:
+ stack.push(BasicType.INT);
+ return 1;
+ case Constants.ITEM_Object:
+ ConstantClass c = (ConstantClass)cp.getConstant(smType.getIndex(), Constants.CONSTANT_Class);
+ stack.push(new ObjectType(c.getBytes(cp)));
+ return 1;
+ case Constants.ITEM_Top:
+ case Constants.ITEM_Float:
+ case Constants.ITEM_Null:
+ case Constants.ITEM_UninitializedThis:
+ case Constants.ITEM_Uninitialized:
+
+ // double slot items
+ case Constants.ITEM_Double:
+ case Constants.ITEM_Long:
+ throw new RuntimeException("Frame.addStack() - need to implement support for "+Constants.ITEM_NAMES[itemkey]);
+
+ }
+ return 0;
+ }
+
+
+ private boolean debug=true;
+ /** Applies a StackMapFrame to this Frame */
+ public boolean apply(StackMapFrame frame) {
+ if (debug) System.out.println(">> Applying a stackmapframe: "+frame);
+ int newLocalEntryCount,newStackEntryCount;
+ StackMapType[] localEntries,stackEntries;
+ switch (frame.getKind()) {
+
+ // Same locals, empty stack
+ case StackMapFrame.SameFrameKind: stack.clear();return true;
+
+ // Same locals, empty stack
+ case StackMapFrame.SameFrameExtendedKind: stack.clear();return true;
+
+ // Empty stack, additional locals specified
+ case StackMapFrame.AppendFrameKind:
+ newLocalEntryCount = frame.getNumberOfLocals();
+ localEntries = frame.getTypesOfLocals();
+ if (debug) System.out.println("AppendFrame - "+newLocalEntryCount+" new locals");
+ int pos = locals.getNextUnset();
+ locals.haveSet(newLocalEntryCount+pos);
+ for (int i = 0; i < newLocalEntryCount; i++) pos+=addLocal(pos,localEntries[i]);
+ stack.clear();
+ return true;
+
+
+ case StackMapFrame.FullFrameKind:
+ newLocalEntryCount = frame.getNumberOfLocals();
+ newStackEntryCount = frame.getNumberOfStackItems();
+ localEntries = frame.getTypesOfLocals();
+ locals.flush();
+ stackEntries = frame.getTypesOfStackItems();
+ if (debug) System.out.println("FullFrame - "+newLocalEntryCount+" new locals");
+ if (debug) System.out.println("Fixing locals");
+ pos=0;
+ for (int i = 0; i < newLocalEntryCount; i++) pos+=addLocal(pos,localEntries[i]);
+ stack.clear();
+ locals.haveSet(newLocalEntryCount);
+ if (debug) System.out.println("Fixing stack");
+ for (int i = 0; i < newStackEntryCount; i++) pos+=addStack(stackEntries[i]);
+ return true;
+
+ case StackMapFrame.SameLocalsOneStackItemFrameKind:
+ stack.clear();
+ stackEntries = frame.getTypesOfStackItems();
+ if (stackEntries.length!=1) throw new RuntimeException("Assertion failed: should be length 1 but is length "+stackEntries.length);
+ // assert(stackEntries.length==1)
+ addStack(stackEntries[0]);
+ return true;
+
+ case StackMapFrame.ChopFrameKind:
+ stack.clear();
+ // XXX is this the last X number of known ones or the last X of the maxLocals() number?
+ // From methodTypesToSignature in Utility - there are two chop frames, so it it must be chopping 'the last X we currently know about'
+ pos = locals.getNextUnset();
+ if (pos==-1) pos=locals.maxLocals();
+ locals.haveSet(locals.getNextUnset()-frame.getNumberOfLocals());
+ for (int j=0;j<frame.getNumberOfLocals();j++) {
+ locals.set(pos-j-1, Type.UNKNOWN);
+ }
+ return true;
+
+ default:
+ throw new RuntimeException("Frame.apply() - you need to implement support for "+frame.getKindString());
+// System.err.println("DUNNO > "+frame.getKindString());
+ }
+ }
+
+ private StackMapType getTheType(Type type,ConstantPoolGen cpg) {
+// System.out.println("> Frame.getTheType(): type = "+type);
+ byte tag = type.getType();
+ StackMapType smt = null;
+ int pos = -1;
+ switch (tag) {
+ case Constants.T_INT:
+ smt = new StackMapType(Constants.ITEM_Integer,-1,cpg.getConstantPool());
+ break;
+ case Constants.T_OBJECT:
+ if (type==Type.NULL) {
+ smt = new StackMapType(Constants.ITEM_Null,-1,cpg.getConstantPool());
+ } else {
+ pos = cpg.addClass((ObjectType)type);
+ smt = new StackMapType(Constants.ITEM_Object,pos,cpg.getConstantPool());
+ }
+ break;
+ case Constants.T_UNKNOWN:
+ UninitializedObjectType uot = (UninitializedObjectType)type;
+ if (uot.isThis()) {
+ smt = new StackMapType(Constants.ITEM_UninitializedThis,-1,cpg.getConstantPool());
+ } else {
+// pos = cpg.addClass(uot.getInitialized());
+ smt = new StackMapType(Constants.ITEM_Uninitialized,uot.getLoc(),cpg.getConstantPool());
+ }
+ break;
+ case Constants.T_ARRAY:
+ ArrayType aType = (ArrayType)type;
+ pos = cpg.addClass(type.getSignature());
+ smt = new StackMapType(Constants.ITEM_Object,pos,cpg.getConstantPool());
+ break;
+
+ case Constants.T_TOP:
+ smt = new StackMapType(Constants.ITEM_Top,-1,cpg.getConstantPool());
+ break;
+
+ case Constants.T_FLOAT:
+ smt = new StackMapType(Constants.ITEM_Float,-1,cpg.getConstantPool());
+ break;
+
+ case Constants.T_LONG:
+ smt = new StackMapType(Constants.ITEM_Long,-1,cpg.getConstantPool());
+ break;
+
+ case Constants.T_DOUBLE:
+ smt = new StackMapType(Constants.ITEM_Double,-1,cpg.getConstantPool());
+ break;
+
+ default:
+ throw new RuntimeException("Frame.getTheType(): Dont know about tag "+tag);
+ }
+ return smt;
+ }
+ public StackMapType[] getLocalsAsStackMapTypes(ConstantPoolGen cpg) {
+// StackMapType[] smts = new StackMapType[locals.maxLocals()];
+ List l = new ArrayList();
+ for (int i = 0; i < locals.maxLocals(); i++) {
+ Type type = (Type)locals.get(i);
+ l.add(getTheType(type, cpg));
+ if (type.getSize()==2) {
+ // can skip the TOP that follows ... yes?
+ i++;
+ if (locals.get(i)!=Type.TOP) {
+ throw new RuntimeException("Bang! should be TOP but is "+locals.get(i));
+ }
+ }
+ }
+ return (StackMapType[])l.toArray(new StackMapType[]{});
+
+// return smts;
+ }
+
+ public StackMapType[] getStackAsStackMapTypes(ConstantPoolGen cpg) {
+ List l = new ArrayList();
+ for (int i = 0; i < stack.slotsUsed(); i++) {
+ Type type = (Type)stack.get(i);
+ l.add(getTheType(type, cpg));
+ if (type.getSize()==2) {
+ // can skip the TOP that follows ... yes?
+ i++;
+ try {
+ if (stack.get(i)!=Type.TOP) {
+ throw new RuntimeException("Bang! should be TOP but is "+locals.get(i));
+ }
+ } catch (IndexOutOfBoundsException iiobe) {
+ int stop = 1;
+ }
+ }
+ }
+ return (StackMapType[])l.toArray(new StackMapType[]{});
+
+// StackMapType[] smts = new StackMapType[stack.slotsUsed()];
+// for (int i = 0; i < stack.size(); i++) {
+// smts[i] = getTheType((Type)stack.get(i),cp);
+// }
+// return smts;
+ }
+
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstConstraintVisitor.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstConstraintVisitor.java
new file mode 100644
index 000000000..8e39b621c
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstConstraintVisitor.java
@@ -0,0 +1,2667 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.aspectj.apache.bcel.Constants;
+import org.aspectj.apache.bcel.Repository;
+import org.aspectj.apache.bcel.classfile.Constant;
+import org.aspectj.apache.bcel.classfile.ConstantClass;
+import org.aspectj.apache.bcel.classfile.ConstantDouble;
+import org.aspectj.apache.bcel.classfile.ConstantInteger;
+import org.aspectj.apache.bcel.classfile.ConstantFieldref;
+import org.aspectj.apache.bcel.classfile.ConstantFloat;
+import org.aspectj.apache.bcel.classfile.ConstantLong;
+import org.aspectj.apache.bcel.classfile.ConstantString;
+import org.aspectj.apache.bcel.classfile.Field;
+import org.aspectj.apache.bcel.classfile.JavaClass;
+import org.aspectj.apache.bcel.generic.*;
+import org.aspectj.apache.bcel.verifier.*;
+import org.aspectj.apache.bcel.verifier.exc.*;
+
+
+/**
+ * A Visitor class testing for valid preconditions of JVM instructions.
+ * The instance of this class will throw a StructuralCodeConstraintException
+ * instance if an instruction is visitXXX()ed which has preconditions that are
+ * not satisfied.
+ * TODO: Currently, the JVM's behaviour concerning monitors (MONITORENTER,
+ * MONITOREXIT) is not modeled in JustIce.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see org.aspectj.apache.bcel.verifier.exc.StructuralCodeConstraintException
+ * @see org.aspectj.apache.bcel.verifier.exc.LinkingConstraintException
+ */
+public class InstConstraintVisitor extends EmptyVisitor implements org.aspectj.apache.bcel.generic.Visitor{
+
+ private static ObjectType GENERIC_ARRAY = new ObjectType("org.aspectj.apache.bcel.verifier.structurals.GenericArray");
+
+ /**
+ * The constructor. Constructs a new instance of this class.
+ */
+ public InstConstraintVisitor(){}
+ public InstConstraintVisitor(ConstantPoolGen cpg ){this.cpg=cpg;}
+
+ /**
+ * The Execution Frame we're working on.
+ *
+ * @see #setFrame(Frame f)
+ * @see #locals()
+ * @see #stack()
+ */
+ private Frame frame = null;
+
+ /**
+ * The ConstantPoolGen we're working on.
+ *
+ * @see #setConstantPoolGen(ConstantPoolGen cpg)
+ */
+ private ConstantPoolGen cpg = null;
+
+ /**
+ * The MethodGen we're working on.
+ *
+ * @see #setMethodGen(MethodGen mg)
+ */
+ private MethodGen mg = null;
+
+ /**
+ * The OperandStack we're working on.
+ *
+ * @see #setFrame(Frame f)
+ */
+ private OperandStack stack(){
+ return frame.getStack();
+ }
+
+ /**
+ * The LocalVariables we're working on.
+ *
+ * @see #setFrame(Frame f)
+ */
+ private LocalVariables locals(){
+ return frame.getLocals();
+ }
+
+ /**
+ * This method is called by the visitXXX() to notify the acceptor of this InstConstraintVisitor
+ * that a constraint violation has occured. This is done by throwing an instance of a
+ * StructuralCodeConstraintException.
+ * @throws org.aspectj.apache.bcel.verifier.exc.StructuralCodeConstraintException always.
+ */
+ private void constraintViolated(Instruction violator, String description){
+ String fq_classname = violator.getClass().getName();
+ throw new StructuralCodeConstraintException("Instruction "+ fq_classname.substring(fq_classname.lastIndexOf('.')+1) +" constraint violated: " + description);
+ }
+
+ /**
+ * This returns the single instance of the InstConstraintVisitor class.
+ * To operate correctly, other values must have been set before actually
+ * using the instance.
+ * Use this method for performance reasons.
+ *
+ * @see #setConstantPoolGen(ConstantPoolGen cpg)
+ * @see #setMethodGen(MethodGen mg)
+ */
+ public void setFrame(Frame f){
+ this.frame = f;
+ //if (singleInstance.mg == null || singleInstance.cpg == null) throw new AssertionViolatedException("Forgot to set important values first.");
+ }
+
+ /**
+ * Sets the ConstantPoolGen instance needed for constraint
+ * checking prior to execution.
+ */
+ public void setConstantPoolGen(ConstantPoolGen cpg){
+ this.cpg = cpg;
+ }
+
+ /**
+ * Sets the MethodGen instance needed for constraint
+ * checking prior to execution.
+ */
+ public void setMethodGen(MethodGen mg){
+ this.mg = mg;
+ }
+
+ /**
+ * Assures index is of type INT.
+ * @throws org.aspectj.apache.bcel.verifier.exc.StructuralCodeConstraintException if the above constraint is not satisfied.
+ */
+ private void indexOfInt(Instruction o, Type index){
+ if (! index.equals(Type.INT))
+ constraintViolated(o, "The 'index' is not of type int but of type "+index+".");
+ }
+
+ /**
+ * Assures the ReferenceType r is initialized (or Type.NULL).
+ * Formally, this means (!(r instanceof UninitializedObjectType)), because
+ * there are no uninitialized array types.
+ * @throws org.aspectj.apache.bcel.verifier.exc.StructuralCodeConstraintException if the above constraint is not satisfied.
+ */
+ private void referenceTypeIsInitialized(Instruction o, ReferenceType r){
+ if (r instanceof UninitializedObjectType){
+ constraintViolated(o, "Working on an uninitialized object '"+r+"'.");
+ }
+ }
+
+ /** Assures value is of type INT. */
+ private void valueOfInt(Instruction o, Type value){
+ if (! value.equals(Type.INT))
+ constraintViolated(o, "The 'value' is not of type int but of type "+value+".");
+ }
+
+ /**
+ * Assures arrayref is of ArrayType or NULL;
+ * returns true if and only if arrayref is non-NULL.
+ * @throws org.aspectj.apache.bcel.verifier.exc.StructuralCodeConstraintException if the above constraint is violated.
+ */
+ private boolean arrayrefOfArrayType(Instruction o, Type arrayref){
+ if (! ((arrayref instanceof ArrayType) || arrayref.equals(Type.NULL)) )
+ constraintViolated(o, "The 'arrayref' does not refer to an array but is of type "+arrayref+".");
+ return (arrayref instanceof ArrayType);
+ }
+
+ /***************************************************************/
+ /* MISC */
+ /***************************************************************/
+ /**
+ * Ensures the general preconditions of an instruction that accesses the stack.
+ * This method is here because BCEL has no such superinterface for the stack
+ * accessing instructions; and there are funny unexpected exceptions in the
+ * semantices of the superinterfaces and superclasses provided.
+ * E.g. SWAP is a StackConsumer, but DUP_X1 is not a StackProducer.
+ * Therefore, this method is called by all StackProducer, StackConsumer,
+ * and StackInstruction instances via their visitXXX() method.
+ * Unfortunately, as the superclasses and superinterfaces overlap, some instructions
+ * cause this method to be called two or three times. [TODO: Fix this.]
+ *
+ * @see #visitStackConsumer(StackConsumer o)
+ * @see #visitStackProducer(StackProducer o)
+ * @see #visitStackInstruction(StackInstruction o)
+ */
+ private void _visitStackAccessor(Instruction o){
+ int consume = o.consumeStack(cpg); // Stack values are always consumed first; then produced.
+ if (consume > stack().slotsUsed()){
+ constraintViolated( o, "Cannot consume "+consume+" stack slots: only "+stack().slotsUsed()+" slot(s) left on stack!\nStack:\n"+stack());
+ }
+
+ int produce = o.produceStack(cpg) - o.consumeStack(cpg); // Stack values are always consumed first; then produced.
+ if ( produce + stack().slotsUsed() > stack().maxStack() ){
+ constraintViolated( o, "Cannot produce "+produce+" stack slots: only "+(stack().maxStack()-stack().slotsUsed())+" free stack slot(s) left.\nStack:\n"+stack());
+ }
+ }
+
+ /***************************************************************/
+ /* "generic"visitXXXX methods where XXXX is an interface */
+ /* therefore, we don't know the order of visiting; but we know */
+ /* these methods are called before the visitYYYY methods below */
+ /***************************************************************/
+
+ /**
+ * Assures the generic preconditions of a LoadClass instance.
+ * The referenced class is loaded and pass2-verified.
+ */
+ public void visitLoadClass(LoadClass o){
+ ObjectType t = o.getLoadClassType(cpg);
+// this really means we can't verify a class by itself...
+// if (t != null){// null means "no class is loaded"
+// Verifier v = VerifierFactory.getVerifier(t.getClassName());
+// VerificationResult vr = v.doPass2();
+// if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+// constraintViolated((Instruction) o, "Class '"+o.getLoadClassType(cpg).getClassName()+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+// }
+// }
+ }
+
+ /**
+ * Ensures the general preconditions of a StackConsumer instance.
+ */
+ public void visitStackConsumer(StackConsumer o){
+ _visitStackAccessor((Instruction) o);
+ }
+
+ /**
+ * Ensures the general preconditions of a StackProducer instance.
+ */
+ public void visitStackProducer(StackProducer o){
+ _visitStackAccessor((Instruction) o);
+ }
+
+
+ /***************************************************************/
+ /* "generic" visitYYYY methods where YYYY is a superclass. */
+ /* therefore, we know the order of visiting; we know */
+ /* these methods are called after the visitXXXX methods above. */
+ /***************************************************************/
+ /**
+ * Ensures the general preconditions of a CPInstruction instance.
+ */
+ public void visitCPInstruction(CPInstruction o){
+ int idx = o.getIndex();
+ if ((idx < 0) || (idx >= cpg.getSize())){
+ throw new AssertionViolatedException("Huh?! Constant pool index of instruction '"+o+"' illegal? Pass 3a should have checked this!");
+ }
+ }
+
+ /**
+ * Ensures the general preconditions of a FieldInstruction instance.
+ */
+ public void visitFieldInstruction(FieldInstruction o){
+ // visitLoadClass(o) has been called before: Every FieldOrMethod
+ // implements LoadClass.
+ // visitCPInstruction(o) has been called before.
+ // A FieldInstruction may be: GETFIELD, GETSTATIC, PUTFIELD, PUTSTATIC
+ Constant c = cpg.getConstant(o.getIndex());
+ if (!(c instanceof ConstantFieldref)){
+ constraintViolated(o, "Index '"+o.getIndex()+"' should refer to a CONSTANT_Fieldref_info structure, but refers to '"+c+"'.");
+ }
+ // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
+ Type t = o.getType(cpg);
+ if (t instanceof ObjectType){
+ String name = ((ObjectType)t).getClassName();
+ Verifier v = VerifierFactory.getVerifier( name );
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the general preconditions of an InvokeInstruction instance.
+ */
+ public void visitInvokeInstruction(InvokeInstruction o){
+ // visitLoadClass(o) has been called before: Every FieldOrMethod
+ // implements LoadClass.
+ // visitCPInstruction(o) has been called before.
+ //TODO
+ }
+
+ /**
+ * Ensures the general preconditions of a StackInstruction instance.
+ */
+ public void visitStackInstruction(StackInstruction o){
+ _visitStackAccessor(o);
+ }
+
+ /**
+ * Assures the generic preconditions of a LocalVariableInstruction instance.
+ * That is, the index of the local variable must be valid.
+ */
+ public void visitLocalVariableInstruction(LocalVariableInstruction o){
+ if (locals().maxLocals() <= (o.getType(cpg).getSize()==1? o.getIndex() : o.getIndex()+1) ){
+ constraintViolated(o, "The 'index' is not a valid index into the local variable array.");
+ }
+ }
+
+ /**
+ * Assures the generic preconditions of a LoadInstruction instance.
+ */
+ public void visitLoadInstruction(LoadInstruction o){
+ //visitLocalVariableInstruction(o) is called before, because it is more generic.
+
+ // LOAD instructions must not read Type.UNKNOWN
+ if (locals().get(o.getIndex()) == Type.UNKNOWN){
+ constraintViolated(o, "Read-Access on local variable "+o.getIndex()+" with unknown content.");
+ }
+
+ // LOAD instructions, two-slot-values at index N must have Type.UNKNOWN
+ // as a symbol for the higher halve at index N+1
+ // [suppose some instruction put an int at N+1--- our double at N is defective]
+ if (o.getType(cpg).getSize() == 2){
+ if (locals().get(o.getIndex()+1) != Type.UNKNOWN){
+ constraintViolated(o, "Reading a two-locals value from local variables "+o.getIndex()+" and "+(o.getIndex()+1)+" where the latter one is destroyed.");
+ }
+ }
+
+ // LOAD instructions must read the correct type.
+ if (!(o instanceof ALOAD)){
+ if (locals().get(o.getIndex()) != o.getType(cpg) ){
+ constraintViolated(o, "Local Variable type and LOADing Instruction type mismatch: Local Variable: '"+locals().get(o.getIndex())+"'; Instruction type: '"+o.getType(cpg)+"'.");
+ }
+ }
+ else{ // we deal with an ALOAD
+ if (!(locals().get(o.getIndex()) instanceof ReferenceType)){
+ constraintViolated(o, "Local Variable type and LOADing Instruction type mismatch: Local Variable: '"+locals().get(o.getIndex())+"'; Instruction expects a ReferenceType.");
+ }
+ // ALOAD __IS ALLOWED__ to put uninitialized objects onto the stack!
+ //referenceTypeIsInitialized(o, (ReferenceType) (locals().get(o.getIndex())));
+ }
+
+ // LOAD instructions must have enough free stack slots.
+ if ((stack().maxStack() - stack().slotsUsed()) < o.getType(cpg).getSize()){
+ constraintViolated(o, "Not enough free stack slots to load a '"+o.getType(cpg)+"' onto the OperandStack.");
+ }
+ }
+
+ /**
+ * Assures the generic preconditions of a StoreInstruction instance.
+ */
+ public void visitStoreInstruction(StoreInstruction o){
+ //visitLocalVariableInstruction(o) is called before, because it is more generic.
+
+ if (stack().isEmpty()){ // Don't bother about 1 or 2 stack slots used. This check is implicitely done below while type checking.
+ constraintViolated(o, "Cannot STORE: Stack to read from is empty.");
+ }
+
+ if ( (!(o instanceof ASTORE)) ){
+ if (! (stack().peek() == o.getType(cpg)) ){// the other xSTORE types are singletons in BCEL.
+ constraintViolated(o, "Stack top type and STOREing Instruction type mismatch: Stack top: '"+stack().peek()+"'; Instruction type: '"+o.getType(cpg)+"'.");
+ }
+ }
+ else{ // we deal with ASTORE
+ Type stacktop = stack().peek();
+ if ( (!(stacktop instanceof ReferenceType)) && (!(stacktop instanceof ReturnaddressType)) ){
+ constraintViolated(o, "Stack top type and STOREing Instruction type mismatch: Stack top: '"+stack().peek()+"'; Instruction expects a ReferenceType or a ReturnadressType.");
+ }
+ if (stacktop instanceof ReferenceType){
+ referenceTypeIsInitialized(o, (ReferenceType) stacktop);
+ }
+ }
+ }
+
+ /**
+ * Assures the generic preconditions of a ReturnInstruction instance.
+ */
+ public void visitReturnInstruction(ReturnInstruction o){
+ if (o instanceof RETURN){
+ return;
+ }
+ if (o instanceof ARETURN){
+ if (stack().peek() == Type.NULL){
+ return;
+ }
+ else{
+ if (! (stack().peek() instanceof ReferenceType)){
+ constraintViolated(o, "Reference type expected on top of stack, but is: '"+stack().peek()+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()));
+ //ReferenceType objectref = (ReferenceType) (stack().peek());
+ // TODO: This can only be checked if using Staerk-et-al's "set of object types" instead of a
+ // "wider cast object type" created during verification.
+ //if (! (objectref.isAssignmentCompatibleWith(mg.getType())) ){
+ // constraintViolated(o, "Type on stack top which should be returned is a '"+stack().peek()+"' which is not assignment compatible with the return type of this method, '"+mg.getType()+"'.");
+ //}
+ }
+ }
+ else{
+ Type method_type = mg.getType();
+ if (method_type == Type.BOOLEAN ||
+ method_type == Type.BYTE ||
+ method_type == Type.SHORT ||
+ method_type == Type.CHAR){
+ method_type = Type.INT;
+ }
+ if (! ( method_type.equals( stack().peek() ))){
+ constraintViolated(o, "Current method has return type of '"+mg.getType()+"' expecting a '"+method_type+"' on top of the stack. But stack top is a '"+stack().peek()+"'.");
+ }
+ }
+ }
+
+ /***************************************************************/
+ /* "special"visitXXXX methods for one type of instruction each */
+ /***************************************************************/
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitAALOAD(AALOAD o){
+ Type arrayref = stack().peek(1);
+ Type index = stack().peek(0);
+
+ indexOfInt(o, index);
+ if (arrayrefOfArrayType(o, arrayref)){
+ if (! (((ArrayType) arrayref).getElementType() instanceof ReferenceType)){
+ constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a ReferenceType but to an array of "+((ArrayType) arrayref).getElementType()+".");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (((ArrayType) arrayref).getElementType()));
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitAASTORE(AASTORE o){
+ Type arrayref = stack().peek(2);
+ Type index = stack().peek(1);
+ Type value = stack().peek(0);
+
+ indexOfInt(o, index);
+ if (!(value instanceof ReferenceType)){
+ constraintViolated(o, "The 'value' is not of a ReferenceType but of type "+value+".");
+ }else{
+ referenceTypeIsInitialized(o, (ReferenceType) value);
+ }
+ // Don't bother further with "referenceTypeIsInitialized()", there are no arrays
+ // of an uninitialized object type.
+ if (arrayrefOfArrayType(o, arrayref)){
+ if (! (((ArrayType) arrayref).getElementType() instanceof ReferenceType)){
+ constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a ReferenceType but to an array of "+((ArrayType) arrayref).getElementType()+".");
+ }
+ if (! ((ReferenceType)value).isAssignmentCompatibleWith((ReferenceType) ((ArrayType) arrayref).getElementType())){
+ constraintViolated(o, "The type of 'value' ('"+value+"') is not assignment compatible to the components of the array 'arrayref' refers to. ('"+((ArrayType) arrayref).getElementType()+"')");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitACONST_NULL(ACONST_NULL o){
+ // Nothing needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitALOAD(ALOAD o){
+ //visitLoadInstruction(LoadInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitANEWARRAY(ANEWARRAY o){
+ if (!stack().peek().equals(Type.INT))
+ constraintViolated(o, "The 'count' at the stack top is not of type '"+Type.INT+"' but of type '"+stack().peek()+"'.");
+ // The runtime constant pool item at that index must be a symbolic reference to a class,
+ // array, or interface type. See Pass 3a.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitARETURN(ARETURN o){
+ if (! (stack().peek() instanceof ReferenceType) ){
+ constraintViolated(o, "The 'objectref' at the stack top is not of a ReferenceType but of type '"+stack().peek()+"'.");
+ }
+ ReferenceType objectref = (ReferenceType) (stack().peek());
+ referenceTypeIsInitialized(o, objectref);
+
+ // The check below should already done via visitReturnInstruction(ReturnInstruction), see there.
+ // It cannot be done using Staerk-et-al's "set of object types" instead of a
+ // "wider cast object type", anyway.
+ //if (! objectref.isAssignmentCompatibleWith(mg.getReturnType() )){
+ // constraintViolated(o, "The 'objectref' type "+objectref+" at the stack top is not assignment compatible with the return type '"+mg.getReturnType()+"' of the method.");
+ //}
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitARRAYLENGTH(ARRAYLENGTH o){
+ Type arrayref = stack().peek(0);
+ arrayrefOfArrayType(o, arrayref);
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitASTORE(ASTORE o){
+ if (! ( (stack().peek() instanceof ReferenceType) || (stack().peek() instanceof ReturnaddressType) ) ){
+ constraintViolated(o, "The 'objectref' is not of a ReferenceType or of ReturnaddressType but of "+stack().peek()+".");
+ }
+ if (stack().peek() instanceof ReferenceType){
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitATHROW(ATHROW o){
+ // It's stated that 'objectref' must be of a ReferenceType --- but since Throwable is
+ // not derived from an ArrayType, it follows that 'objectref' must be of an ObjectType or Type.NULL.
+ if (! ((stack().peek() instanceof ObjectType) || (stack().peek().equals(Type.NULL))) ){
+ constraintViolated(o, "The 'objectref' is not of an (initialized) ObjectType but of type "+stack().peek()+".");
+ }
+
+ // NULL is a subclass of every class, so to speak.
+ if (stack().peek().equals(Type.NULL)) return;
+
+ ObjectType exc = (ObjectType) (stack().peek());
+ ObjectType throwable = (ObjectType) (Type.getType("Ljava/lang/Throwable;"));
+ if ( (! (exc.subclassOf(throwable)) ) && (! (exc.equals(throwable))) ){
+ constraintViolated(o, "The 'objectref' is not of class Throwable or of a subclass of Throwable, but of '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitBALOAD(BALOAD o){
+ Type arrayref = stack().peek(1);
+ Type index = stack().peek(0);
+ indexOfInt(o, index);
+ if (arrayrefOfArrayType(o, arrayref)){
+ if (! ( (((ArrayType) arrayref).getElementType().equals(Type.BOOLEAN)) ||
+ (((ArrayType) arrayref).getElementType().equals(Type.BYTE)) ) ){
+ constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a Type.BYTE or Type.BOOLEAN but to an array of '"+((ArrayType) arrayref).getElementType()+"'.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitBASTORE(BASTORE o){
+ Type arrayref = stack().peek(2);
+ Type index = stack().peek(1);
+ Type value = stack().peek(0);
+
+ indexOfInt(o, index);
+ valueOfInt(o, value);
+ if (arrayrefOfArrayType(o, arrayref)){
+ if (! ( (((ArrayType) arrayref).getElementType().equals(Type.BOOLEAN)) ||
+ (((ArrayType) arrayref).getElementType().equals(Type.BYTE)) ) )
+ constraintViolated(o, "The 'arrayref' does not refer to an array with elements of a Type.BYTE or Type.BOOLEAN but to an array of '"+((ArrayType) arrayref).getElementType()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitBIPUSH(BIPUSH o){
+ // Nothing to do...
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitBREAKPOINT(BREAKPOINT o){
+ throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as BREAKPOINT.");
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitCALOAD(CALOAD o){
+ Type arrayref = stack().peek(1);
+ Type index = stack().peek(0);
+
+ indexOfInt(o, index);
+ arrayrefOfArrayType(o, arrayref);
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitCASTORE(CASTORE o){
+ Type arrayref = stack().peek(2);
+ Type index = stack().peek(1);
+ Type value = stack().peek(0);
+
+ indexOfInt(o, index);
+ valueOfInt(o, value);
+ if (arrayrefOfArrayType(o, arrayref)){
+ if (! ((ArrayType) arrayref).getElementType().equals(Type.CHAR) ){
+ constraintViolated(o, "The 'arrayref' does not refer to an array with elements of type char but to an array of type "+((ArrayType) arrayref).getElementType()+".");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitCHECKCAST(CHECKCAST o){
+ // The objectref must be of type reference.
+ Type objectref = stack().peek(0);
+ if (!(objectref instanceof ReferenceType)){
+ constraintViolated(o, "The 'objectref' is not of a ReferenceType but of type "+objectref+".");
+ }
+ else{
+ referenceTypeIsInitialized(o, (ReferenceType) objectref);
+ }
+ // The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the
+ // current class (§3.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant
+ // pool item at the index must be a symbolic reference to a class, array, or interface type.
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! (c instanceof ConstantClass)){
+ constraintViolated(o, "The Constant at 'index' is not a ConstantClass, but '"+c+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitD2F(D2F o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitD2I(D2I o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitD2L(D2L o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDADD(DADD o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDALOAD(DALOAD o){
+ indexOfInt(o, stack().peek());
+ if (stack().peek(1) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(1) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-top must be of type double[] but is '"+stack().peek(1)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(1))).getBasicType();
+ if (t != Type.DOUBLE){
+ constraintViolated(o, "Stack next-to-top must be of type double[] but is '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDASTORE(DASTORE o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ indexOfInt(o, stack().peek(1));
+ if (stack().peek(2) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(2) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type double[] but is '"+stack().peek(2)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(2))).getBasicType();
+ if (t != Type.DOUBLE){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type double[] but is '"+stack().peek(2)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDCMPG(DCMPG o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDCMPL(DCMPL o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDCONST(DCONST o){
+ // There's nothing to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDDIV(DDIV o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDLOAD(DLOAD o){
+ //visitLoadInstruction(LoadInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDMUL(DMUL o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDNEG(DNEG o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDREM(DREM o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDRETURN(DRETURN o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDSTORE(DSTORE o){
+ //visitStoreInstruction(StoreInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDSUB(DSUB o){
+ if (stack().peek() != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack top is not of type 'double', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.DOUBLE){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'double', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDUP(DUP o){
+ if (stack().peek().getSize() != 1){
+ constraintViolated(o, "Won't DUP type on stack top '"+stack().peek()+"' because it must occupy exactly one slot, not '"+stack().peek().getSize()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDUP_X1(DUP_X1 o){
+ if (stack().peek().getSize() != 1){
+ constraintViolated(o, "Type on stack top '"+stack().peek()+"' should occupy exactly one slot, not '"+stack().peek().getSize()+"'.");
+ }
+ if (stack().peek(1).getSize() != 1){
+ constraintViolated(o, "Type on stack next-to-top '"+stack().peek(1)+"' should occupy exactly one slot, not '"+stack().peek(1).getSize()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDUP_X2(DUP_X2 o){
+ if (stack().peek().getSize() != 1){
+ constraintViolated(o, "Stack top type must be of size 1, but is '"+stack().peek()+"' of size '"+stack().peek().getSize()+"'.");
+ }
+ if (stack().peek(1).getSize() == 2){
+ return; // Form 2, okay.
+ }
+ else{ //stack().peek(1).getSize == 1.
+ if (stack().peek(2).getSize() != 1){
+ constraintViolated(o, "If stack top's size is 1 and stack next-to-top's size is 1, stack next-to-next-to-top's size must also be 1, but is: '"+stack().peek(2)+"' of size '"+stack().peek(2).getSize()+"'.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDUP2(DUP2 o){
+ if (stack().peek().getSize() == 2){
+ return; // Form 2, okay.
+ }
+ else{ //stack().peek().getSize() == 1.
+ if (stack().peek(1).getSize() != 1){
+ constraintViolated(o, "If stack top's size is 1, then stack next-to-top's size must also be 1. But it is '"+stack().peek(1)+"' of size '"+stack().peek(1).getSize()+"'.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDUP2_X1(DUP2_X1 o){
+ if (stack().peek().getSize() == 2){
+ if (stack().peek(1).getSize() != 1){
+ constraintViolated(o, "If stack top's size is 2, then stack next-to-top's size must be 1. But it is '"+stack().peek(1)+"' of size '"+stack().peek(1).getSize()+"'.");
+ }
+ else{
+ return; // Form 2
+ }
+ }
+ else{ // stack top is of size 1
+ if ( stack().peek(1).getSize() != 1 ){
+ constraintViolated(o, "If stack top's size is 1, then stack next-to-top's size must also be 1. But it is '"+stack().peek(1)+"' of size '"+stack().peek(1).getSize()+"'.");
+ }
+ if ( stack().peek(2).getSize() != 1 ){
+ constraintViolated(o, "If stack top's size is 1, then stack next-to-next-to-top's size must also be 1. But it is '"+stack().peek(2)+"' of size '"+stack().peek(2).getSize()+"'.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitDUP2_X2(DUP2_X2 o){
+
+ if (stack().peek(0).getSize() == 2){
+ if (stack().peek(1).getSize() == 2){
+ return; // Form 4
+ }
+ else{// stack top size is 2, next-to-top's size is 1
+ if ( stack().peek(2).getSize() != 1 ){
+ constraintViolated(o, "If stack top's size is 2 and stack-next-to-top's size is 1, then stack next-to-next-to-top's size must also be 1. But it is '"+stack().peek(2)+"' of size '"+stack().peek(2).getSize()+"'.");
+ }
+ else{
+ return; // Form 2
+ }
+ }
+ }
+ else{// stack top is of size 1
+ if (stack().peek(1).getSize() == 1){
+ if ( stack().peek(2).getSize() == 2 ){
+ return; // Form 3
+ }
+ else{
+ if ( stack().peek(3).getSize() == 1){
+ return; // Form 1
+ }
+ }
+ }
+ }
+ constraintViolated(o, "The operand sizes on the stack do not match any of the four forms of usage of this instruction.");
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitF2D(F2D o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitF2I(F2I o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitF2L(F2L o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFADD(FADD o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFALOAD(FALOAD o){
+ indexOfInt(o, stack().peek());
+ if (stack().peek(1) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(1) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-top must be of type float[] but is '"+stack().peek(1)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(1))).getBasicType();
+ if (t != Type.FLOAT){
+ constraintViolated(o, "Stack next-to-top must be of type float[] but is '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFASTORE(FASTORE o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ indexOfInt(o, stack().peek(1));
+ if (stack().peek(2) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(2) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type float[] but is '"+stack().peek(2)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(2))).getBasicType();
+ if (t != Type.FLOAT){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type float[] but is '"+stack().peek(2)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFCMPG(FCMPG o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFCMPL(FCMPL o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFCONST(FCONST o){
+ // nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFDIV(FDIV o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFLOAD(FLOAD o){
+ //visitLoadInstruction(LoadInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFMUL(FMUL o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFNEG(FNEG o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFREM(FREM o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFRETURN(FRETURN o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFSTORE(FSTORE o){
+ //visitStoreInstruction(StoreInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitFSUB(FSUB o){
+ if (stack().peek() != Type.FLOAT){
+ constraintViolated(o, "The value at the stack top is not of type 'float', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.FLOAT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'float', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+
+ private Field findField(String field_name,String classname) {
+ JavaClass jc = Repository.lookupClass(classname);
+ Field[] fields = jc.getFields();
+ Field f = null;
+ for (int i=0; i<fields.length; i++){
+ if (fields[i].getName().equals(field_name)){
+ return fields[i];
+ }
+ }
+ if (jc.getSuperClass()!=null) return findField(field_name,jc.getSuperClass().getClassName());
+ return null;
+ }
+ public void visitGETFIELD(GETFIELD o){
+ Type objectref = stack().peek();
+ if (! ( (objectref instanceof ObjectType) || (objectref == Type.NULL) ) ){
+ constraintViolated(o, "Stack top should be an object reference that's not an array reference, but is '"+objectref+"'.");
+ }
+
+ String field_name = o.getFieldName(cpg);
+ Field f = findField(field_name,o.getClassType(cpg).getClassName());
+
+// JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
+// Field[] fields = jc.getFields();
+// Field f = null;
+// for (int i=0; i<fields.length; i++){
+// if (fields[i].getName().equals(field_name)){
+// f = fields[i];
+// break;
+// }
+// }
+ if (f == null){
+ throw new AssertionViolatedException("Field not found?!?");
+ }
+
+ if (f.isProtected()){
+ ObjectType classtype = o.getClassType(cpg);
+ ObjectType curr = new ObjectType(mg.getClassName());
+
+ if ( classtype.equals(curr) ||
+ curr.subclassOf(classtype) ){
+ Type t = stack().peek();
+ if (t == Type.NULL){
+ return;
+ }
+ if (! (t instanceof ObjectType) ){
+ constraintViolated(o, "The 'objectref' must refer to an object that's not an array. Found instead: '"+t+"'.");
+ }
+ ObjectType objreftype = (ObjectType) t;
+ if (! ( objreftype.equals(curr) ||
+ objreftype.subclassOf(curr) ) ){
+ //TODO: One day move to Staerk-et-al's "Set of object types" instead of "wider" object types
+ // created during the verification.
+ // "Wider" object types don't allow us to check for things like that below.
+ //constraintViolated(o, "The referenced field has the ACC_PROTECTED modifier, and it's a member of the current class or a superclass of the current class. However, the referenced object type '"+stack().peek()+"' is not the current class or a subclass of the current class.");
+ }
+ }
+ }
+
+ // TODO: Could go into Pass 3a.
+ if (f.isStatic()){
+ constraintViolated(o, "Referenced field '"+f+"' is static which it shouldn't be.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitGETSTATIC(GETSTATIC o){
+ // Field must be static: see Pass 3a.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitGOTO(GOTO o){
+ // nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitGOTO_W(GOTO_W o){
+ // nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitI2B(I2B o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitI2C(I2C o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitI2D(I2D o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitI2F(I2F o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitI2L(I2L o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitI2S(I2S o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIADD(IADD o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIALOAD(IALOAD o){
+ indexOfInt(o, stack().peek());
+ if (stack().peek(1) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(1) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-top must be of type int[] but is '"+stack().peek(1)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(1))).getBasicType();
+ if (t != Type.INT){
+ constraintViolated(o, "Stack next-to-top must be of type int[] but is '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIAND(IAND o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIASTORE(IASTORE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ indexOfInt(o, stack().peek(1));
+ if (stack().peek(2) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(2) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type int[] but is '"+stack().peek(2)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(2))).getBasicType();
+ if (t != Type.INT){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type int[] but is '"+stack().peek(2)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitICONST(ICONST o){
+ //nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIDIV(IDIV o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ACMPEQ(IF_ACMPEQ o){
+ if (!(stack().peek() instanceof ReferenceType)){
+ constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '"+stack().peek()+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+
+ if (!(stack().peek(1) instanceof ReferenceType)){
+ constraintViolated(o, "The value at the stack next-to-top is not of a ReferenceType, but of type '"+stack().peek(1)+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek(1)) );
+
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ACMPNE(IF_ACMPNE o){
+ if (!(stack().peek() instanceof ReferenceType)){
+ constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '"+stack().peek()+"'.");
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+ }
+ if (!(stack().peek(1) instanceof ReferenceType)){
+ constraintViolated(o, "The value at the stack next-to-top is not of a ReferenceType, but of type '"+stack().peek(1)+"'.");
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek(1)) );
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ICMPEQ(IF_ICMPEQ o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ICMPGE(IF_ICMPGE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ICMPGT(IF_ICMPGT o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ICMPLE(IF_ICMPLE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ICMPLT(IF_ICMPLT o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIF_ICMPNE(IF_ICMPNE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFEQ(IFEQ o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFGE(IFGE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFGT(IFGT o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFLE(IFLE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFLT(IFLT o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFNE(IFNE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFNONNULL(IFNONNULL o){
+ if (!(stack().peek() instanceof ReferenceType)){
+ constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '"+stack().peek()+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIFNULL(IFNULL o){
+ if (!(stack().peek() instanceof ReferenceType)){
+ constraintViolated(o, "The value at the stack top is not of a ReferenceType, but of type '"+stack().peek()+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIINC(IINC o){
+ // Mhhh. In BCEL, at this time "IINC" is not a LocalVariableInstruction.
+ if (locals().maxLocals() <= (o.getType(cpg).getSize()==1? o.getIndex() : o.getIndex()+1) ){
+ constraintViolated(o, "The 'index' is not a valid index into the local variable array.");
+ }
+
+ indexOfInt(o, locals().get(o.getIndex()));
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitILOAD(ILOAD o){
+ // All done by visitLocalVariableInstruction(), visitLoadInstruction()
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIMPDEP1(IMPDEP1 o){
+ throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as IMPDEP1.");
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIMPDEP2(IMPDEP2 o){
+ throw new AssertionViolatedException("In this JustIce verification pass there should not occur an illegal instruction such as IMPDEP2.");
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIMUL(IMUL o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitINEG(INEG o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitINSTANCEOF(INSTANCEOF o){
+ // The objectref must be of type reference.
+ Type objectref = stack().peek(0);
+ if (!(objectref instanceof ReferenceType)){
+ constraintViolated(o, "The 'objectref' is not of a ReferenceType but of type "+objectref+".");
+ }
+ else{
+ referenceTypeIsInitialized(o, (ReferenceType) objectref);
+ }
+ // The unsigned indexbyte1 and indexbyte2 are used to construct an index into the runtime constant pool of the
+ // current class (§3.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The runtime constant
+ // pool item at the index must be a symbolic reference to a class, array, or interface type.
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! (c instanceof ConstantClass)){
+ constraintViolated(o, "The Constant at 'index' is not a ConstantClass, but '"+c+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitINVOKEINTERFACE(INVOKEINTERFACE o){
+ // Method is not native, otherwise pass 3 would not happen.
+
+ int count = o.getCount();
+ if (count == 0){
+ constraintViolated(o, "The 'count' argument must not be 0.");
+ }
+ // It is a ConstantInterfaceMethodref, Pass 3a made it sure.
+ // TODO: Do we want to do anything with it?
+ //ConstantInterfaceMethodref cimr = (ConstantInterfaceMethodref) (cpg.getConstant(o.getIndex()));
+
+ // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
+
+ Type t = o.getType(cpg);
+ if (t instanceof ObjectType){
+ String name = ((ObjectType)t).getClassName();
+ Verifier v = VerifierFactory.getVerifier( name );
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ }
+ }
+
+
+ Type[] argtypes = o.getArgumentTypes(cpg);
+ int nargs = argtypes.length;
+
+ for (int i=nargs-1; i>=0; i--){
+ Type fromStack = stack().peek( (nargs-1) - i ); // 0 to nargs-1
+ Type fromDesc = argtypes[i];
+ if (fromDesc == Type.BOOLEAN ||
+ fromDesc == Type.BYTE ||
+ fromDesc == Type.CHAR ||
+ fromDesc == Type.SHORT){
+ fromDesc = Type.INT;
+ }
+ if (! fromStack.equals(fromDesc)){
+ if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType){
+ //ReferenceType rFromStack = (ReferenceType) fromStack;
+ //ReferenceType rFromDesc = (ReferenceType) fromDesc;
+ // TODO: This can only be checked when using Staerk-et-al's "set of object types"
+ // instead of a "wider cast object type" created during verification.
+ //if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ){
+ // constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack (which is not assignment compatible).");
+ //}
+ }
+ else{
+ constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack.");
+ }
+ }
+ }
+
+ Type objref = stack().peek(nargs);
+ if (objref == Type.NULL){
+ return;
+ }
+ if (! (objref instanceof ReferenceType) ){
+ constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '"+objref+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) objref);
+ if (!(objref instanceof ObjectType)){
+ if (!(objref instanceof ArrayType)){
+ constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '"+objref+"'."); // could be a ReturnaddressType
+ }
+ else{
+ objref = GENERIC_ARRAY;
+ }
+ }
+
+ // String objref_classname = ((ObjectType) objref).getClassName();
+ // String theInterface = o.getClassName(cpg);
+ // TODO: This can only be checked if we're using Staerk-et-al's "set of object types"
+ // instead of "wider cast object types" generated during verification.
+ //if ( ! Repository.implementationOf(objref_classname, theInterface) ){
+ // constraintViolated(o, "The 'objref' item '"+objref+"' does not implement '"+theInterface+"' as expected.");
+ //}
+
+ int counted_count = 1; // 1 for the objectref
+ for (int i=0; i<nargs; i++){
+ counted_count += argtypes[i].getSize();
+ }
+ if (count != counted_count){
+ constraintViolated(o, "The 'count' argument should probably read '"+counted_count+"' but is '"+count+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitINVOKESPECIAL(INVOKESPECIAL o){
+ // Don't init an object twice.
+ if ( (o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME)) && (!(stack().peek(o.getArgumentTypes(cpg).length) instanceof UninitializedObjectType)) ){
+ constraintViolated(o, "Possibly initializing object twice. A valid instruction sequence must not have an uninitialized object on the operand stack or in a local variable during a backwards branch, or in a local variable in code protected by an exception handler. Please see The Java Virtual Machine Specification, Second Edition, 4.9.4 (pages 147 and 148) for details.");
+ }
+
+ // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
+
+ Type t = o.getType(cpg);
+ if (t instanceof ObjectType){
+ String name = ((ObjectType)t).getClassName();
+ Verifier v = VerifierFactory.getVerifier( name );
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ }
+ }
+
+
+ Type[] argtypes = o.getArgumentTypes(cpg);
+ int nargs = argtypes.length;
+
+ for (int i=nargs-1; i>=0; i--){
+ Type fromStack = stack().peek( (nargs-1) - i ); // 0 to nargs-1
+ Type fromDesc = argtypes[i];
+ if (fromDesc == Type.BOOLEAN ||
+ fromDesc == Type.BYTE ||
+ fromDesc == Type.CHAR ||
+ fromDesc == Type.SHORT){
+ fromDesc = Type.INT;
+ }
+ if (! fromStack.equals(fromDesc)){
+ if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType){
+ ReferenceType rFromStack = (ReferenceType) fromStack;
+ ReferenceType rFromDesc = (ReferenceType) fromDesc;
+ // TODO: This can only be checked using Staerk-et-al's "set of object types", not
+ // using a "wider cast object type".
+ if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ){
+ constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack (which is not assignment compatible).");
+ }
+ }
+ else{
+ constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack.");
+ }
+ }
+ }
+
+ Type objref = stack().peek(nargs);
+ if (objref == Type.NULL){
+ return;
+ }
+ if (! (objref instanceof ReferenceType) ){
+ constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '"+objref+"'.");
+ }
+ String objref_classname = null;
+ if ( !(o.getMethodName(cpg).equals(Constants.CONSTRUCTOR_NAME))){
+ referenceTypeIsInitialized(o, (ReferenceType) objref);
+ if (!(objref instanceof ObjectType)){
+ if (!(objref instanceof ArrayType)){
+ constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '"+objref+"'."); // could be a ReturnaddressType
+ }
+ else{
+ objref = GENERIC_ARRAY;
+ }
+ }
+
+ objref_classname = ((ObjectType) objref).getClassName();
+ }
+ else{
+ if (!(objref instanceof UninitializedObjectType)){
+ constraintViolated(o, "Expecting an UninitializedObjectType as 'objectref' on the stack, not a '"+objref+"'. Otherwise, you couldn't invoke a method since an array has no methods (not to speak of a return address).");
+ }
+ objref_classname = ((UninitializedObjectType) objref).getInitialized().getClassName();
+ }
+
+
+ String theClass = o.getClassName(cpg);
+ if ( ! Repository.instanceOf(objref_classname, theClass) ){
+ constraintViolated(o, "The 'objref' item '"+objref+"' does not implement '"+theClass+"' as expected.");
+ }
+
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitINVOKESTATIC(INVOKESTATIC o){
+ // Method is not native, otherwise pass 3 would not happen.
+
+ Type t = o.getType(cpg);
+ if (t instanceof ObjectType){
+ String name = ((ObjectType)t).getClassName();
+ Verifier v = VerifierFactory.getVerifier( name );
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ }
+ }
+
+ Type[] argtypes = o.getArgumentTypes(cpg);
+ int nargs = argtypes.length;
+
+ for (int i=nargs-1; i>=0; i--){
+ Type fromStack = stack().peek( (nargs-1) - i ); // 0 to nargs-1
+ Type fromDesc = argtypes[i];
+ if (fromDesc == Type.BOOLEAN ||
+ fromDesc == Type.BYTE ||
+ fromDesc == Type.CHAR ||
+ fromDesc == Type.SHORT){
+ fromDesc = Type.INT;
+ }
+ if (! fromStack.equals(fromDesc)){
+ if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType){
+ ReferenceType rFromStack = (ReferenceType) fromStack;
+ ReferenceType rFromDesc = (ReferenceType) fromDesc;
+ // TODO: This check can possibly only be done using Staerk-et-al's "set of object types"
+ // instead of a "wider cast object type" created during verification.
+ if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ){
+ constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack (which is not assignment compatible).");
+ }
+ }
+ else{
+ constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack.");
+ }
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitINVOKEVIRTUAL(INVOKEVIRTUAL o){
+ // the o.getClassType(cpg) type has passed pass 2; see visitLoadClass(o).
+
+ Type t = o.getType(cpg);
+ if (t instanceof ObjectType){
+ String name = ((ObjectType)t).getClassName();
+ Verifier v = VerifierFactory.getVerifier( name );
+ VerificationResult vr = v.doPass2();
+ if (vr.getStatus() != VerificationResult.VERIFIED_OK){
+ constraintViolated((Instruction) o, "Class '"+name+"' is referenced, but cannot be loaded and resolved: '"+vr+"'.");
+ }
+ }
+
+
+ Type[] argtypes = o.getArgumentTypes(cpg);
+ int nargs = argtypes.length;
+
+ for (int i=nargs-1; i>=0; i--){
+ Type fromStack = stack().peek( (nargs-1) - i ); // 0 to nargs-1
+ Type fromDesc = argtypes[i];
+ if (fromDesc == Type.BOOLEAN ||
+ fromDesc == Type.BYTE ||
+ fromDesc == Type.CHAR ||
+ fromDesc == Type.SHORT){
+ fromDesc = Type.INT;
+ }
+ if (! fromStack.equals(fromDesc)){
+ if (fromStack instanceof ReferenceType && fromDesc instanceof ReferenceType){
+ ReferenceType rFromStack = (ReferenceType) fromStack;
+ ReferenceType rFromDesc = (ReferenceType) fromDesc;
+ // TODO: This can possibly only be checked when using Staerk-et-al's "set of object types" instead
+ // of a single "wider cast object type" created during verification.
+ if ( ! rFromStack.isAssignmentCompatibleWith(rFromDesc) ){
+ constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack (which is not assignment compatible).");
+ }
+ }
+ else{
+ constraintViolated(o, "Expecting a '"+fromDesc+"' but found a '"+fromStack+"' on the stack.");
+ }
+ }
+ }
+
+ Type objref = stack().peek(nargs);
+ if (objref == Type.NULL){
+ return;
+ }
+ if (! (objref instanceof ReferenceType) ){
+ constraintViolated(o, "Expecting a reference type as 'objectref' on the stack, not a '"+objref+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) objref);
+ if (!(objref instanceof ObjectType)){
+ if (!(objref instanceof ArrayType)){
+ constraintViolated(o, "Expecting an ObjectType as 'objectref' on the stack, not a '"+objref+"'."); // could be a ReturnaddressType
+ }
+ else{
+ objref = GENERIC_ARRAY;
+ }
+ }
+
+ String objref_classname = ((ObjectType) objref).getClassName();
+
+ String theClass = o.getClassName(cpg);
+
+ if ( ! Repository.instanceOf(objref_classname, theClass) ){
+ constraintViolated(o, "The 'objref' item '"+objref+"' does not implement '"+theClass+"' as expected.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIOR(IOR o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIREM(IREM o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIRETURN(IRETURN o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitISHL(ISHL o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitISHR(ISHR o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitISTORE(ISTORE o){
+ //visitStoreInstruction(StoreInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitISUB(ISUB o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIUSHR(IUSHR o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitIXOR(IXOR o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.INT){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'int', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitJSR(JSR o){
+ // nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitJSR_W(JSR_W o){
+ // nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitL2D(L2D o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitL2F(L2F o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitL2I(L2I o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLADD(LADD o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLALOAD(LALOAD o){
+ indexOfInt(o, stack().peek());
+ if (stack().peek(1) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(1) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-top must be of type long[] but is '"+stack().peek(1)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(1))).getBasicType();
+ if (t != Type.LONG){
+ constraintViolated(o, "Stack next-to-top must be of type long[] but is '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLAND(LAND o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLASTORE(LASTORE o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ indexOfInt(o, stack().peek(1));
+ if (stack().peek(2) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(2) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type long[] but is '"+stack().peek(2)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(2))).getBasicType();
+ if (t != Type.LONG){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type long[] but is '"+stack().peek(2)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLCMP(LCMP o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLCONST(LCONST o){
+ // Nothing to do here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLDC(LDC o){
+ // visitCPInstruction is called first.
+
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! ( ( c instanceof ConstantInteger) ||
+ ( c instanceof ConstantFloat ) ||
+ ( c instanceof ConstantString ) ) ){
+ constraintViolated(o, "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float or a CONSTANT_String, but is '"+c+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLDC_W(LDC_W o){
+ // visitCPInstruction is called first.
+
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! ( ( c instanceof ConstantInteger) ||
+ ( c instanceof ConstantFloat ) ||
+ ( c instanceof ConstantString ) ) ){
+ constraintViolated(o, "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float or a CONSTANT_String, but is '"+c+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLDC2_W(LDC2_W o){
+ // visitCPInstruction is called first.
+
+ Constant c = cpg.getConstant(o.getIndex());
+ if (! ( ( c instanceof ConstantLong) ||
+ ( c instanceof ConstantDouble ) ) ){
+ constraintViolated(o, "Referenced constant should be a CONSTANT_Integer, a CONSTANT_Float or a CONSTANT_String, but is '"+c+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLDIV(LDIV o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLLOAD(LLOAD o){
+ //visitLoadInstruction(LoadInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLMUL(LMUL o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLNEG(LNEG o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLOOKUPSWITCH(LOOKUPSWITCH o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ // See also pass 3a.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLOR(LOR o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLREM(LREM o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLRETURN(LRETURN o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLSHL(LSHL o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLSHR(LSHR o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLSTORE(LSTORE o){
+ //visitStoreInstruction(StoreInstruction) is called before.
+
+ // Nothing else needs to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLSUB(LSUB o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLUSHR(LUSHR o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitLXOR(LXOR o){
+ if (stack().peek() != Type.LONG){
+ constraintViolated(o, "The value at the stack top is not of type 'long', but of type '"+stack().peek()+"'.");
+ }
+ if (stack().peek(1) != Type.LONG){
+ constraintViolated(o, "The value at the stack next-to-top is not of type 'long', but of type '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitMONITORENTER(MONITORENTER o){
+ if (! ((stack().peek()) instanceof ReferenceType)){
+ constraintViolated(o, "The stack top should be of a ReferenceType, but is '"+stack().peek()+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitMONITOREXIT(MONITOREXIT o){
+ if (! ((stack().peek()) instanceof ReferenceType)){
+ constraintViolated(o, "The stack top should be of a ReferenceType, but is '"+stack().peek()+"'.");
+ }
+ referenceTypeIsInitialized(o, (ReferenceType) (stack().peek()) );
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitMULTIANEWARRAY(MULTIANEWARRAY o){
+ int dimensions = o.getDimensions();
+ // Dimensions argument is okay: see Pass 3a.
+ for (int i=0; i<dimensions; i++){
+ if (stack().peek(i) != Type.INT){
+ constraintViolated(o, "The '"+dimensions+"' upper stack types should be 'int' but aren't.");
+ }
+ }
+ // The runtime constant pool item at that index must be a symbolic reference to a class,
+ // array, or interface type. See Pass 3a.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitNEW(NEW o){
+ //visitCPInstruction(CPInstruction) has been called before.
+ //visitLoadClass(LoadClass) has been called before.
+
+ Type t = o.getType(cpg);
+ if (! (t instanceof ReferenceType)){
+ throw new AssertionViolatedException("NEW.getType() returning a non-reference type?!");
+ }
+ if (! (t instanceof ObjectType)){
+ constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '"+t+"'.");
+ }
+ ObjectType obj = (ObjectType) t;
+
+ //e.g.: Don't instantiate interfaces
+ if (! obj.referencesClass()){
+ constraintViolated(o, "Expecting a class type (ObjectType) to work on. Found: '"+obj+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitNEWARRAY(NEWARRAY o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitNOP(NOP o){
+ // nothing is to be done here.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitPOP(POP o){
+ if (stack().peek().getSize() != 1){
+ constraintViolated(o, "Stack top size should be 1 but stack top is '"+stack().peek()+"' of size '"+stack().peek().getSize()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitPOP2(POP2 o){
+ if (stack().peek().getSize() != 2){
+ constraintViolated(o, "Stack top size should be 2 but stack top is '"+stack().peek()+"' of size '"+stack().peek().getSize()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitPUTFIELD(PUTFIELD o){
+
+ Type objectref = stack().peek(1);
+ if (! ( (objectref instanceof ObjectType) || (objectref == Type.NULL) ) ){
+ constraintViolated(o, "Stack next-to-top should be an object reference that's not an array reference, but is '"+objectref+"'.");
+ }
+
+ String field_name = o.getFieldName(cpg);
+ Field f = findField(field_name, o.getClassType(cpg).getClassName());
+
+// JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
+// Field[] fields = jc.getFields();
+// Field f = null;
+// for (int i=0; i<fields.length; i++){
+// if (fields[i].getName().equals(field_name)){
+// f = fields[i];
+// break;
+// }
+// }
+ if (f == null){
+ throw new AssertionViolatedException("Field not found?!?");
+ }
+
+ Type value = stack().peek();
+ Type t = Type.getType(f.getSignature());
+ Type shouldbe = t;
+ if (shouldbe == Type.BOOLEAN ||
+ shouldbe == Type.BYTE ||
+ shouldbe == Type.CHAR ||
+ shouldbe == Type.SHORT){
+ shouldbe = Type.INT;
+ }
+ if (t instanceof ReferenceType){
+ ReferenceType rvalue = null;
+ if (value instanceof ReferenceType){
+ rvalue = (ReferenceType) value;
+ referenceTypeIsInitialized(o, rvalue);
+ }
+ else{
+ constraintViolated(o, "The stack top type '"+value+"' is not of a reference type as expected.");
+ }
+ // TODO: This can possibly only be checked using Staerk-et-al's "set-of-object types", not
+ // using "wider cast object types" created during verification.
+ // Comment it out if you encounter problems. See also the analogon at visitPUTSTATIC.
+ if (!(rvalue.isAssignmentCompatibleWith(shouldbe))){
+ constraintViolated(o, "The stack top type '"+value+"' is not assignment compatible with '"+shouldbe+"'.");
+ }
+ }
+ else{
+ if (shouldbe != value){
+ constraintViolated(o, "The stack top type '"+value+"' is not of type '"+shouldbe+"' as expected.");
+ }
+ }
+
+ if (f.isProtected()){
+ ObjectType classtype = o.getClassType(cpg);
+ ObjectType curr = new ObjectType(mg.getClassName());
+
+ if ( classtype.equals(curr) ||
+ curr.subclassOf(classtype) ){
+ Type tp = stack().peek(1);
+ if (tp == Type.NULL){
+ return;
+ }
+ if (! (tp instanceof ObjectType) ){
+ constraintViolated(o, "The 'objectref' must refer to an object that's not an array. Found instead: '"+tp+"'.");
+ }
+ ObjectType objreftype = (ObjectType) tp;
+ if (! ( objreftype.equals(curr) ||
+ objreftype.subclassOf(curr) ) ){
+ constraintViolated(o, "The referenced field has the ACC_PROTECTED modifier, and it's a member of the current class or a superclass of the current class. However, the referenced object type '"+stack().peek()+"' is not the current class or a subclass of the current class.");
+ }
+ }
+ }
+
+ // TODO: Could go into Pass 3a.
+ if (f.isStatic()){
+ constraintViolated(o, "Referenced field '"+f+"' is static which it shouldn't be.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitPUTSTATIC(PUTSTATIC o){
+ String field_name = o.getFieldName(cpg);
+ JavaClass jc = Repository.lookupClass(o.getClassType(cpg).getClassName());
+ Field[] fields = jc.getFields();
+ Field f = null;
+ for (int i=0; i<fields.length; i++){
+ if (fields[i].getName().equals(field_name)){
+ f = fields[i];
+ break;
+ }
+ }
+ if (f == null){
+ throw new AssertionViolatedException("Field not found?!?");
+ }
+ Type value = stack().peek();
+ Type t = Type.getType(f.getSignature());
+ Type shouldbe = t;
+ if (shouldbe == Type.BOOLEAN ||
+ shouldbe == Type.BYTE ||
+ shouldbe == Type.CHAR ||
+ shouldbe == Type.SHORT){
+ shouldbe = Type.INT;
+ }
+ if (t instanceof ReferenceType){
+ ReferenceType rvalue = null;
+ if (value instanceof ReferenceType){
+ rvalue = (ReferenceType) value;
+ referenceTypeIsInitialized(o, rvalue);
+ }
+ else{
+ constraintViolated(o, "The stack top type '"+value+"' is not of a reference type as expected.");
+ }
+ // TODO: This can possibly only be checked using Staerk-et-al's "set-of-object types", not
+ // using "wider cast object types" created during verification.
+ // Comment it out if you encounter problems. See also the analogon at visitPUTFIELD.
+ if (!(rvalue.isAssignmentCompatibleWith(shouldbe))){
+ constraintViolated(o, "The stack top type '"+value+"' is not assignment compatible with '"+shouldbe+"'.");
+ }
+ }
+ else{
+ if (shouldbe != value){
+ constraintViolated(o, "The stack top type '"+value+"' is not of type '"+shouldbe+"' as expected.");
+ }
+ }
+ // TODO: Interface fields may be assigned to only once. (Hard to implement in
+ // JustIce's execution model). This may only happen in <clinit>, see Pass 3a.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitRET(RET o){
+ if (! (locals().get(o.getIndex()) instanceof ReturnaddressType)){
+ constraintViolated(o, "Expecting a ReturnaddressType in local variable "+o.getIndex()+".");
+ }
+ if (locals().get(o.getIndex()) == ReturnaddressType.NO_TARGET){
+ throw new AssertionViolatedException("Oops: RET expecting a target!");
+ }
+ // Other constraints such as non-allowed overlapping subroutines are enforced
+ // while building the Subroutines data structure.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitRETURN(RETURN o){
+ if (mg.getName().equals(Constants.CONSTRUCTOR_NAME)){// If we leave an <init> method
+ if ((Frame._this != null) && (!(mg.getClassName().equals(Type.OBJECT.getClassName()))) ) {
+ constraintViolated(o, "Leaving a constructor that itself did not call a constructor.");
+ }
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitSALOAD(SALOAD o){
+ indexOfInt(o, stack().peek());
+ if (stack().peek(1) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(1) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-top must be of type short[] but is '"+stack().peek(1)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(1))).getBasicType();
+ if (t != Type.SHORT){
+ constraintViolated(o, "Stack next-to-top must be of type short[] but is '"+stack().peek(1)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitSASTORE(SASTORE o){
+ if (stack().peek() != Type.INT){
+ constraintViolated(o, "The value at the stack top is not of type 'int', but of type '"+stack().peek()+"'.");
+ }
+ indexOfInt(o, stack().peek(1));
+ if (stack().peek(2) == Type.NULL){
+ return;
+ }
+ if (! (stack().peek(2) instanceof ArrayType)){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type short[] but is '"+stack().peek(2)+"'.");
+ }
+ Type t = ((ArrayType) (stack().peek(2))).getBasicType();
+ if (t != Type.SHORT){
+ constraintViolated(o, "Stack next-to-next-to-top must be of type short[] but is '"+stack().peek(2)+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitSIPUSH(SIPUSH o){
+ // nothing to do here. Generic visitXXX() methods did the trick before.
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitSWAP(SWAP o){
+ if (stack().peek().getSize() != 1){
+ constraintViolated(o, "The value at the stack top is not of size '1', but of size '"+stack().peek().getSize()+"'.");
+ }
+ if (stack().peek(1).getSize() != 1){
+ constraintViolated(o, "The value at the stack next-to-top is not of size '1', but of size '"+stack().peek(1).getSize()+"'.");
+ }
+ }
+
+ /**
+ * Ensures the specific preconditions of the said instruction.
+ */
+ public void visitTABLESWITCH(TABLESWITCH o){
+ indexOfInt(o, stack().peek());
+ // See Pass 3a.
+ }
+
+}
+
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContext.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContext.java
new file mode 100644
index 000000000..dea064ceb
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContext.java
@@ -0,0 +1,113 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import java.util.ArrayList;
+
+import org.aspectj.apache.bcel.generic.InstructionHandle;
+
+/**
+ * An InstructionContext offers convenient access to information like control flow successors
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public interface InstructionContext{
+
+ /**
+ * This method symbolically executes the Instruction held in the
+ * InstructionContext. It "merges in" the incoming execution frame
+ * situation (see The JVM Specification, 2nd edition, page 146).
+ * By so doing, the outgoing execution frame situation is calculated.
+ *
+ * This method is JustIce-specific and is usually of no sense for
+ * users of the ControlFlowGraph class. They should use
+ * getInstruction().accept(Visitor), possibly in conjunction with the ExecutionVisitor.
+ *
+ * @see #getOutFrame(ArrayList)
+ * @return true - if and only if the "outgoing" frame situation
+ * changed from the one before execute()ing.
+ */
+ boolean execute(Frame inFrame, ArrayList executionPredecessors, InstConstraintVisitor icv, ExecutionVisitor ev);
+
+ boolean execute(Frame inFrame, ArrayList executionPredecessors, ExecutionVisitor ev);
+ /**
+ * This method returns the outgoing execution frame situation;
+ * therefore <B>it has to be calculated by execute(Frame, ArrayList)
+ * first.</B>
+ *
+ * @see #execute(Frame, ArrayList, InstConstraintVisitor, ExecutionVisitor)
+ */
+ Frame getOutFrame(ArrayList executionPredecessors);
+
+ /**
+ * Returns the InstructionHandle this InstructionContext is wrapped around.
+ *
+ * @return The InstructionHandle this InstructionContext is wrapped around.
+ */
+ InstructionHandle getInstruction();
+
+ /**
+ * Returns the usual control flow successors.
+ * @see #getExceptionHandlers()
+ */
+ InstructionContext[] getSuccessors();
+
+ /**
+ * Returns the exception handlers that protect this instruction.
+ * They are special control flow successors.
+ */
+ ExceptionHandler[] getExceptionHandlers();
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContextImpl.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContextImpl.java
new file mode 100644
index 000000000..c4d8f8124
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContextImpl.java
@@ -0,0 +1,395 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import org.aspectj.apache.bcel.generic.ATHROW;
+import org.aspectj.apache.bcel.generic.BranchInstruction;
+import org.aspectj.apache.bcel.generic.GotoInstruction;
+import org.aspectj.apache.bcel.generic.Instruction;
+import org.aspectj.apache.bcel.generic.InstructionConstants;
+import org.aspectj.apache.bcel.generic.InstructionHandle;
+import org.aspectj.apache.bcel.generic.JsrInstruction;
+import org.aspectj.apache.bcel.generic.RET;
+import org.aspectj.apache.bcel.generic.ReturnInstruction;
+import org.aspectj.apache.bcel.generic.Select;
+import org.aspectj.apache.bcel.verifier.exc.AssertionViolatedException;
+import org.aspectj.apache.bcel.verifier.exc.StructuralCodeConstraintException;
+
+/**
+ * Objects of this class represent a node in a ControlFlowGraph.
+ * These nodes are instructions, not basic blocks.
+ */
+class InstructionContextImpl implements InstructionContext{
+
+ private final ControlFlowGraph graph;
+
+ // The InstructionHandle this InstructionContext is wrapped around.
+ private InstructionHandle instruction;
+
+ // The 'incoming' execution Frames.
+ private HashMap /* last executing JSR */ inFrames;
+
+ // The 'outgoing' execution Frames.
+ private HashMap /* last executed JSR */ outFrames;
+
+ /**
+ * The 'execution predecessors' - a list of type InstructionContext
+ * of those instances that have been execute()d before in that order.
+ */
+ private List /*InstructionContext*/ executionPredecessors = null;
+
+ // ---
+
+ /**
+ * Creates an InstructionHandleImpl object from an InstructionHandle.
+ * Creation of one per InstructionHandle suffices. Don't create more.
+ */
+ public InstructionContextImpl(ControlFlowGraph graph, InstructionHandle inst){
+ if (inst == null) throw new AssertionViolatedException("Cannot instantiate InstructionContextImpl from NULL.");
+
+ this.graph = graph;
+ instruction = inst;
+ inFrames = new HashMap();
+ outFrames = new HashMap();
+ }
+
+ /**
+ * Returns the exception handlers of this instruction.
+ */
+ public ExceptionHandler[] getExceptionHandlers(){
+ return this.graph.exceptionhandlers.getExceptionHandlers(getInstruction());
+ }
+
+ /**
+ * Returns a clone of the "outgoing" frame situation with respect to the given ExecutionChain.
+ */
+ public Frame getOutFrame(ArrayList execChain){
+ executionPredecessors = execChain;
+
+ Frame org;
+
+ InstructionContext jsr = lastExecutionJSR();
+
+ org = (Frame) outFrames.get(jsr);
+
+ if (org == null){
+ throw new AssertionViolatedException("outFrame not set! This:\n"+this+"\nExecutionChain: "+getExecutionChain()+"\nOutFrames: '"+outFrames+"'.");
+ }
+ return org.getClone();
+ }
+
+ /**
+ * "Merges in" (vmspec2, page 146) the "incoming" frame situation;
+ * executes the instructions symbolically
+ * and therefore calculates the "outgoing" frame situation.
+ * Returns: True iff the "incoming" frame situation changed after
+ * merging with "inFrame".
+ * The execPreds ArrayList must contain the InstructionContext
+ * objects executed so far in the correct order. This is just
+ * one execution path [out of many]. This is needed to correctly
+ * "merge" in the special case of a RET's successor.
+ * <B>The InstConstraintVisitor and ExecutionVisitor instances
+ * must be set up correctly.</B>
+ * @return true - if and only if the "outgoing" frame situation
+ * changed from the one before execute()ing.
+ */
+
+ private List subsetIt(List l) {
+ List toKeep = new ArrayList();
+ for (Iterator iter = l.iterator(); iter.hasNext();) {
+ InstructionContext iCtx = (InstructionContext) iter.next();
+ Instruction i = iCtx.getInstruction().getInstruction();
+ if (i instanceof JsrInstruction || i instanceof RET) {
+ toKeep.add(iCtx);
+ }
+ }
+ if (toKeep.size()>0) {
+ System.err.println("keep>0!");
+ return toKeep;
+ } else {
+ return Collections.EMPTY_LIST;
+ }
+ }
+
+ /**
+ * Copy of other execute method but doesnt worry about constraint visitor
+ */
+ public boolean execute(Frame inFrame, ArrayList execPreds, ExecutionVisitor executionVisitor) {
+
+ executionPredecessors = subsetIt(execPreds);//(ArrayList) execPreds.clone();
+
+ //sanity check
+ if ( (lastExecutionJSR() == null) && (this.graph.subroutines.subroutineOf(getInstruction()) != this.graph.subroutines.getTopLevel() ) ){
+ throw new AssertionViolatedException("Huh?! Am I '"+this+"' part of a subroutine or not?");
+ }
+ if ( (lastExecutionJSR() != null) && (this.graph.subroutines.subroutineOf(getInstruction()) == this.graph.subroutines.getTopLevel() ) ){
+ throw new AssertionViolatedException("Huh?! Am I '"+this+"' part of a subroutine or not?");
+ }
+
+ Frame inF = (Frame) inFrames.get(lastExecutionJSR());
+ if (inF == null) {// no incoming frame was set, so set it.
+ inFrames.put(lastExecutionJSR(), inFrame);
+ inF = inFrame;
+ } else {// if there was an "old" inFrame
+ if (inF.equals(inFrame)){ //shortcut: no need to merge equal frames.
+ return false;
+ }
+ if (! mergeInFrames(inFrame)){
+ return false;
+ }
+ }
+
+ // Now we're sure the inFrame has changed!
+
+ // new inFrame is already merged in, see above.
+ Frame workingFrame = inF.getClone();
+
+ // This executes the Instruction - modifying the workingFrame
+ executionVisitor.setFrame(workingFrame);
+ executionVisitor.setPosition(getInstruction().getPosition());
+ getInstruction().accept(executionVisitor);
+ outFrames.put(lastExecutionJSR(), workingFrame);
+
+ return true; // new inFrame was different from old inFrame so merging them
+ // yielded a different this.inFrame.
+ }
+
+ public boolean execute(Frame inFrame, ArrayList execPreds, InstConstraintVisitor icv, ExecutionVisitor ev){
+
+ executionPredecessors = subsetIt(execPreds);//(ArrayList) execPreds.clone();
+
+ //sanity check
+ if ( (lastExecutionJSR() == null) && (this.graph.subroutines.subroutineOf(getInstruction()) != this.graph.subroutines.getTopLevel() ) ){
+ throw new AssertionViolatedException("Huh?! Am I '"+this+"' part of a subroutine or not?");
+ }
+ if ( (lastExecutionJSR() != null) && (this.graph.subroutines.subroutineOf(getInstruction()) == this.graph.subroutines.getTopLevel() ) ){
+ throw new AssertionViolatedException("Huh?! Am I '"+this+"' part of a subroutine or not?");
+ }
+
+ Frame inF = (Frame) inFrames.get(lastExecutionJSR());
+ if (inF == null){// no incoming frame was set, so set it.
+ inFrames.put(lastExecutionJSR(), inFrame);
+ inF = inFrame;
+ }
+ else{// if there was an "old" inFrame
+ if (inF.equals(inFrame)){ //shortcut: no need to merge equal frames.
+ return false;
+ }
+ if (! mergeInFrames(inFrame)){
+ return false;
+ }
+ }
+
+ // Now we're sure the inFrame has changed!
+
+ // new inFrame is already merged in, see above.
+ Frame workingFrame = inF.getClone();
+
+ try{
+ // This verifies the InstructionConstraint for the current
+ // instruction, but does not modify the workingFrame object.
+//InstConstraintVisitor icv = InstConstraintVisitor.getInstance(VerifierFactory.getVerifier(method_gen.getClassName()));
+ icv.setFrame(workingFrame);
+ // will go bang...
+ getInstruction().accept(icv);
+ }
+ catch(StructuralCodeConstraintException ce){
+ ce.extendMessage("","\nInstructionHandle: "+getInstruction()+"\n");
+ ce.extendMessage("","\nExecution Frame:\n"+workingFrame);
+ extendMessageWithFlow(ce);
+ throw ce;
+ }
+
+ // This executes the Instruction.
+ // Therefore the workingFrame object is modified.
+//ExecutionVisitor ev = ExecutionVisitor.getInstance(VerifierFactory.getVerifier(method_gen.getClassName()));
+ ev.setFrame(workingFrame);
+ ev.setPosition(getInstruction().getPosition());
+ getInstruction().accept(ev);
+ //getInstruction().accept(ExecutionVisitor.withFrame(workingFrame));
+ outFrames.put(lastExecutionJSR(), workingFrame);
+
+ return true; // new inFrame was different from old inFrame so merging them
+ // yielded a different this.inFrame.
+ }
+
+ /**
+ * Returns a simple String representation of this InstructionContext.
+ */
+ public String toString(){
+ //TODO: Put information in the brackets, e.g.
+ // Is this an ExceptionHandler? Is this a RET? Is this the start of
+ // a subroutine?
+ String ret = getInstruction().toString(false)+"\t[InstructionContext]";
+ return ret;
+ }
+
+ /**
+ * Does the actual merging (vmspec2, page 146).
+ * Returns true IFF this.inFrame was changed in course of merging with inFrame.
+ */
+ private boolean mergeInFrames(Frame inFrame){
+ // TODO: Can be performance-improved.
+ Frame inF = (Frame) inFrames.get(lastExecutionJSR());
+ OperandStack oldstack = inF.getStack().getClone();
+ LocalVariables oldlocals = inF.getLocals().getClone();
+ try{
+ inF.getStack().merge(inFrame.getStack());
+ inF.getLocals().merge(inFrame.getLocals());
+ }
+ catch (StructuralCodeConstraintException sce){
+ extendMessageWithFlow(sce);
+ throw sce;
+ }
+ if ( oldstack.equals(inF.getStack()) &&
+ oldlocals.equals(inF.getLocals()) ){
+ return false;
+ }
+ else{
+ return true;
+ }
+ }
+
+ /**
+ * Returns the control flow execution chain. This is built
+ * while execute(Frame, ArrayList)-ing the code represented
+ * by the surrounding ControlFlowGraph.
+ */
+ private String getExecutionChain(){
+ String s = this.toString();
+ for (int i=executionPredecessors.size()-1; i>=0; i--){
+ s = executionPredecessors.get(i)+"\n" + s;
+ }
+ return s;
+ }
+
+
+ /**
+ * Extends the StructuralCodeConstraintException ("e") object with an at-the-end-extended message.
+ * This extended message will then reflect the execution flow needed to get to the constraint
+ * violation that triggered the throwing of the "e" object.
+ */
+ private void extendMessageWithFlow(StructuralCodeConstraintException e){
+ String s = "Execution flow:\n";
+ e.extendMessage("", s+getExecutionChain());
+ }
+
+ /*
+ * Fulfils the contract of InstructionContext.getInstruction().
+ */
+ public InstructionHandle getInstruction(){
+ return instruction;
+ }
+
+ /**
+ * Returns the InstructionContextImpl with an JSR/JSR_W
+ * that was last in the ExecutionChain, without
+ * a corresponding RET, i.e.
+ * we were called by this one.
+ * Returns null if we were called from the top level.
+ */
+ private InstructionContextImpl lastExecutionJSR(){
+
+ int size = executionPredecessors.size();
+ int retcount = 0;
+
+ for (int i=size-1; i>=0; i--){
+ InstructionContextImpl current = (InstructionContextImpl) (executionPredecessors.get(i));
+ Instruction currentlast = current.getInstruction().getInstruction();
+ if (currentlast instanceof RET) retcount++;
+ if (currentlast instanceof JsrInstruction){
+ retcount--;
+ if (retcount == -1) {
+ throw new RuntimeException();
+// return current;
+ }
+ }
+ }
+ return null;
+ }
+
+ /* Satisfies InstructionContext.getSuccessors(). */
+ public InstructionContext[] getSuccessors(){
+ return this.graph.contextsOf(_getSuccessors());
+ }
+
+ /**
+ * A utility method that calculates the successors of a given InstructionHandle
+ * That means, a RET does have successors as defined here.
+ * A JsrInstruction has its target as its successor
+ * (opposed to its physical successor) as defined here.
+ */
+// TODO: implement caching!
+ private InstructionHandle[] _getSuccessors(){
+ final InstructionHandle[] empty = new InstructionHandle[0];
+ final InstructionHandle[] single = new InstructionHandle[1];
+ final InstructionHandle[] pair = new InstructionHandle[2];
+
+ Instruction inst = getInstruction().getInstruction();
+
+ if (inst instanceof RET){
+ Subroutine s = this.graph.subroutines.subroutineOf(getInstruction());
+ if (s==null){ //return empty; // RET in dead code. "empty" would be the correct answer, but we know something about the surrounding project...
+ throw new AssertionViolatedException("Asking for successors of a RET in dead code?!");
+ }
+//TODO: remove
+throw new AssertionViolatedException("DID YOU REALLY WANT TO ASK FOR RET'S SUCCS?");
+/*
+ InstructionHandle[] jsrs = s.getEnteringJsrInstructions();
+ InstructionHandle[] ret = new InstructionHandle[jsrs.length];
+ for (int i=0; i<jsrs.length; i++){
+ ret[i] = jsrs[i].getNext();
+ }
+ return ret;
+*/
+ }
+
+ // Terminates method normally.
+ if (inst instanceof ReturnInstruction){
+ return empty;
+ }
+
+ // Terminates method abnormally, because JustIce mandates
+ // subroutines not to be protected by exception handlers.
+ if (inst instanceof ATHROW){
+ return empty;
+ }
+
+ // See method comment.
+ if (inst instanceof JsrInstruction){
+ single[0] = ((JsrInstruction) inst).getTarget();
+ return single;
+ }
+
+ if (inst instanceof GotoInstruction){
+ single[0] = ((GotoInstruction) inst).getTarget();
+ return single;
+ }
+
+ if (inst instanceof BranchInstruction){
+ if (inst instanceof Select){
+ // BCEL's getTargets() returns only the non-default targets,
+ // thanks to Eli Tilevich for reporting.
+ InstructionHandle[] matchTargets = ((Select) inst).getTargets();
+ InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1];
+ ret[0] = ((Select) inst).getTarget();
+ System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length);
+ return ret;
+ }
+ else{
+ pair[0] = getInstruction().getNext();
+ pair[1] = ((BranchInstruction) inst).getTarget();
+ return pair;
+ }
+ }
+
+ // default case: Fall through.
+ single[0] = getInstruction().getNext();
+ return single;
+ }
+
+} \ No newline at end of file
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContextQueue.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContextQueue.java
new file mode 100644
index 000000000..3c8e133d3
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContextQueue.java
@@ -0,0 +1,34 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+import java.util.ArrayList;
+import java.util.Vector;
+
+/**
+ * An InstructionContextQueue is a utility class that holds
+ * (InstructionContext, ArrayList) pairs in a Queue data structure.
+ * This is used to hold information about InstructionContext objects
+ * externally --- i.e. that information is not saved inside the
+ * InstructionContext object itself. This is useful to save the
+ * execution path of the symbolic execution of the
+ * Pass3bVerifier - this is not information
+ * that belongs into the InstructionContext object itself.
+ * Only at "execute()"ing
+ * time, an InstructionContext object will get the current information
+ * we have about its symbolic execution predecessors.
+ */
+final class InstructionContextQueue{
+
+ private Vector instructionContexts = new Vector(); // Type: InstructionContext
+ private Vector executionChains = new Vector(); // Type: ArrayList (of InstructionContext)
+
+ public void add(InstructionContext ic, ArrayList executionChain){
+ instructionContexts.add(ic);
+ executionChains.add(executionChain);
+ }
+ public InstructionContext getIC(int i) { return (InstructionContext) instructionContexts.get(i); }
+ public ArrayList getEC(int i) { return (ArrayList) executionChains.get(i); }
+ public int size() { return instructionContexts.size(); }
+ public boolean isEmpty() { return instructionContexts.isEmpty(); }
+ public void remove() { this.remove(0); }
+ public void remove(int i){ instructionContexts.remove(i); executionChains.remove(i); }
+} \ No newline at end of file
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/LocalVariables.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/LocalVariables.java
new file mode 100644
index 000000000..cd6e07ad7
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/LocalVariables.java
@@ -0,0 +1,268 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.aspectj.apache.bcel.generic.Type;
+import org.aspectj.apache.bcel.generic.ReferenceType;
+import org.aspectj.apache.bcel.verifier.exc.*;
+
+/**
+ * This class implements an array of local variables used for symbolic JVM simulation.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class LocalVariables {
+
+ // The Type[] containing the local variable slots
+ private Type[] locals;
+
+ // Creates a new LocalVariables object
+ public LocalVariables(int maxLocals){
+ locals = new Type[maxLocals];
+ for (int i=0; i<maxLocals; i++) locals[i] = Type.TOP;
+ }
+
+ /** Returns the type of the local variable slot i */
+ public Type get(int i) {
+ return locals[i];
+ }
+
+ /**
+ * Returns a (correctly typed) clone of this object.
+ * This is equivalent to ((LocalVariables) this.clone()).
+ */
+ public LocalVariables getClone(){
+ return (LocalVariables) this.clone();
+ }
+
+ /**
+ * Returns the number of local variable slots this
+ * LocalVariables instance has.
+ */
+ public int maxLocals(){
+ return locals.length;
+ }
+
+ /**
+ * Sets a new Type for the given local variable slot.
+ */
+ public void set(int i, Type type){
+ if (type == Type.BYTE || type == Type.SHORT || type == Type.BOOLEAN || type == Type.CHAR){
+ throw new AssertionViolatedException("LocalVariables do not know about '"+type+"'. Use Type.INT instead.");
+ }
+ locals[i] = type;
+// if (type!=Type.UNKNOWN) numberThatHaveBeenSet=i;
+ }
+
+ /*
+ * Fulfills the general contract of Object.equals().
+ */
+ public boolean equals(Object o){
+ if (!(o instanceof LocalVariables)) return false;
+ LocalVariables lv = (LocalVariables) o;
+ if (this.locals.length != lv.locals.length) return false;
+ for (int i=0; i<this.locals.length; i++){
+ if (!this.locals[i].equals(lv.locals[i])){
+ //System.out.println(this.locals[i]+" is not "+lv.locals[i]);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Merges two local variables sets as described in the Java Virtual Machine Specification,
+ * Second Edition, section 4.9.2, page 146.
+ */
+ public void merge(LocalVariables lv){
+
+ if (this.locals.length != lv.locals.length){
+ throw new AssertionViolatedException("Merging LocalVariables of different size?!? From different methods or what?!?");
+ }
+
+ for (int i=0; i<locals.length; i++){
+ merge(lv, i);
+ }
+ }
+
+ /**
+ * Merges a single local variable.
+ *
+ * @see #merge(LocalVariables)
+ */
+ private void merge(LocalVariables lv, int i){
+
+ // We won't accept an unitialized object if we know it was initialized;
+ // compare vmspec2, 4.9.4, last paragraph.
+ if ( (!(locals[i] instanceof UninitializedObjectType)) && (lv.locals[i] instanceof UninitializedObjectType) ){
+ throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object in the local variables detected.");
+ }
+ // Even harder, what about _different_ uninitialized object types?!
+ if ( (!(locals[i].equals(lv.locals[i]))) && (locals[i] instanceof UninitializedObjectType) && (lv.locals[i] instanceof UninitializedObjectType) ){
+ throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object in the local variables detected.");
+ }
+ // If we just didn't know that it was initialized, we have now learned.
+ if (locals[i] instanceof UninitializedObjectType){
+ if (! (lv.locals[i] instanceof UninitializedObjectType)){
+ locals[i] = ((UninitializedObjectType) locals[i]).getInitialized();
+ }
+ }
+ if ((locals[i] instanceof ReferenceType) && (lv.locals[i] instanceof ReferenceType)){
+ if (! locals[i].equals(lv.locals[i])){ // needed in case of two UninitializedObjectType instances
+ Type sup = ((ReferenceType) locals[i]).getFirstCommonSuperclass((ReferenceType) (lv.locals[i]));
+
+ if (sup != null){
+ locals[i] = sup;
+ }
+ else{
+ // We should have checked this in Pass2!
+ throw new AssertionViolatedException("Could not load all the super classes of '"+locals[i]+"' and '"+lv.locals[i]+"'.");
+ }
+ }
+ }
+ else{
+ if (! (locals[i].equals(lv.locals[i])) ){
+/*TODO
+ if ((locals[i] instanceof org.aspectj.apache.bcel.generic.ReturnaddressType) && (lv.locals[i] instanceof org.aspectj.apache.bcel.generic.ReturnaddressType)){
+ //System.err.println("merging "+locals[i]+" and "+lv.locals[i]);
+ throw new AssertionViolatedException("Merging different ReturnAddresses: '"+locals[i]+"' and '"+lv.locals[i]+"'.");
+ }
+*/
+ locals[i] = Type.TOP;
+ }
+ }
+ }
+
+ /**
+ * Returns a String representation of this object.
+ */
+ public String toString(){
+ String s = new String();
+ for (int i=0; i<locals.length; i++){
+ s += Integer.toString(i)+": "+locals[i]+"\n";
+ }
+ return s;
+ }
+
+ /**
+ * Return a more compact string than toString()
+ */
+ public String toCompactString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("[").append(maxLocals()).append(":");
+ for (int i=0;i<locals.length;i++) sb.append(i).append("=").append(compactName(locals[i])).append(" ");
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public String compactName(Type type) {
+ if (type==Type.UNKNOWN) return "<Unknown>";
+ String s = type.toString();
+ int pos = s.lastIndexOf(".");
+ if (pos==-1) return s;
+ return s.substring(pos+1);
+ }
+
+ /**
+ * Replaces all occurences of u in this local variables set
+ * with an "initialized" ObjectType.
+ */
+ public void initializeObject(UninitializedObjectType u){
+ for (int i=0; i<locals.length; i++){
+ if (locals[i] == u){
+ locals[i] = u.getInitialized();
+ }
+ }
+ }
+
+ /**
+ * Returns a deep copy of this object; i.e. the clone
+ * operates on a new local variable array.
+ * However, the Type objects in the array are shared.
+ */
+ protected Object clone(){
+ LocalVariables lvs = new LocalVariables(locals.length);
+ for (int i=0; i<locals.length; i++){
+ lvs.locals[i] = this.locals[i];
+ }
+ return lvs;
+ }
+
+ public void flush() {
+ // reset them all back to unknown!
+ for (int i=0; i<locals.length; i++) locals[i] = Type.TOP;
+ }
+
+ public int getNextUnset() {
+ return numberThatHaveBeenSet;
+ }
+
+ public void haveSet(int i) {
+ // Called so we can remember where the end is
+ numberThatHaveBeenSet=i;
+ }
+
+ private int numberThatHaveBeenSet;
+
+// public int getFirstUnknown() {
+// for (int i = 0; i < locals.length; i++) {
+// if (locals[i].equals(Type.UNKNOWN)) return i;
+// }
+// return -1;
+// }
+
+
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/OperandStack.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/OperandStack.java
new file mode 100644
index 000000000..8cf9e8772
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/OperandStack.java
@@ -0,0 +1,300 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.aspectj.apache.bcel.generic.*;
+import org.aspectj.apache.bcel.verifier.exc.*;
+import java.util.*;
+
+/**
+ * This class implements a stack used for symbolic JVM stack simulation.
+ * [It's used an an operand stack substitute.]
+ * Elements of this stack are org.aspectj.apache.bcel.generic.Type objects.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class OperandStack{
+
+ /** We hold the stack information here. */
+ private ArrayList stack = new ArrayList();
+
+ /** The maximum number of stack slots this OperandStack instance may hold. */
+ private int maxStack;
+
+ /**
+ * Creates an empty stack with a maximum of maxStack slots.
+ */
+ public OperandStack(int maxStack){
+ this.maxStack = maxStack;
+ }
+
+ /**
+ * Creates an otherwise empty stack with a maximum of maxStack slots and
+ * the ObjectType 'obj' at the top.
+ */
+ public OperandStack(int maxStack, ObjectType obj){
+ this.maxStack = maxStack;
+ this.push(obj);
+ }
+ /**
+ * Returns a deep copy of this object; that means, the clone operates
+ * on a new stack. However, the Type objects on the stack are
+ * shared.
+ */
+ protected Object clone(){
+ OperandStack newstack = new OperandStack(this.maxStack);
+ newstack.stack = (ArrayList) this.stack.clone();
+ return newstack;
+ }
+
+ /**
+ * There will be TOP entries for double slot values!
+ */
+ public Type get(int i) { return (Type)stack.get(i);}
+
+ /**
+ * Clears the stack.
+ */
+ public void clear(){
+ stack = new ArrayList();
+ }
+
+ /**
+ * Returns true if and only if this OperandStack
+ * equals another, meaning equal lengths and equal
+ * objects on the stacks.
+ */
+ public boolean equals(Object o){
+ if (!(o instanceof OperandStack)) return false;
+ OperandStack s = (OperandStack) o;
+ return this.stack.equals(s.stack);
+ }
+
+ /**
+ * Returns a (typed!) clone of this.
+ *
+ * @see #clone()
+ */
+ public OperandStack getClone(){
+ return (OperandStack) this.clone();
+ }
+
+ /**
+ * Returns true IFF this OperandStack is empty.
+ */
+ public boolean isEmpty(){
+ return stack.isEmpty();
+ }
+
+ /**
+ * Returns the number of stack slots this stack can hold.
+ */
+ public int maxStack(){
+ return this.maxStack;
+ }
+
+ /**
+ * Returns the element on top of the stack. The element is not popped off the stack!
+ */
+ public Type peek(){
+ return peek(0);
+ }
+
+ /**
+ * Returns the element that's i elements below the top element; that means,
+ * iff i==0 the top element is returned. The element is not popped off the stack!
+ */
+ public Type peek(int i){
+ Type t = (Type) stack.get(size()-i-1);
+ if (t==Type.TOP) {
+ t = (Type) stack.get(size()-i-2);
+ }
+ return t;
+ }
+
+ /**
+ * Returns the element on top of the stack. The element is popped off the stack.
+ */
+ public Type pop(){
+ Type e = (Type) stack.remove(size()-1);
+ if (e==Type.TOP) {
+ e = (Type) stack.remove(size()-1);
+ }
+ return e;
+ }
+
+ /**
+ * Pops i elements off the stack. ALWAYS RETURNS "null"!!!
+ */
+ public Type pop(int i){
+ for (int j=0; j<i; j++){
+ pop();
+ }
+ return null;
+ }
+
+ /**
+ * Pushes a Type object onto the stack.
+ */
+ public void push(Type type){
+ if (type == null) throw new AssertionViolatedException("Cannot push NULL onto OperandStack.");
+ if (type == Type.BOOLEAN || type == Type.CHAR || type == Type.BYTE || type == Type.SHORT){
+ throw new AssertionViolatedException("The OperandStack does not know about '"+type+"'; use Type.INT instead.");
+ }
+ if (slotsUsed() >= maxStack){
+ throw new AssertionViolatedException("OperandStack too small, should have thrown proper Exception elsewhere. Stack: "+this);
+ }
+ stack.add(type);
+ if (type.getSize()==2) stack.add(Type.TOP);
+ }
+
+ /**
+ * Returns the size of this OperandStack; that means, how many Type objects there are.
+ */
+ public int size(){
+ return stack.size();
+ }
+
+ /**
+ * Returns the number of stack slots used.
+ * @see #maxStack()
+ */
+ public int slotsUsed(){
+ return stack.size();
+ /* XXX change this to a better implementation using a variable
+ that keeps track of the actual slotsUsed()-value monitoring
+ all push()es and pop()s.
+ */
+// int slots = 0;
+// for (int i=0; i<stack.size(); i++){
+// slots += peek(i).getSize();
+// }
+// return slots;
+ }
+
+ /**
+ * Returns a String representation of this OperandStack instance.
+ */
+ public String toString(){
+ String s = "Slots used: "+slotsUsed()+" MaxStack: "+maxStack+".\n";
+ for (int i=0; i<size(); i++){
+ s+=peek(i)+" (Size: "+peek(i).getSize()+")\n";
+ }
+ return s;
+ }
+
+ /**
+ * Return a more compact string than toString()
+ */
+ public String toCompactString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("[").append(size()).append(":");
+ for (int i=0;i<size();i++) sb.append(i).append("=").append(peek(i)).append("(").append(peek(i).getSize()).append(") ");
+ sb.append("]");
+ return sb.toString();
+ }
+
+ /**
+ * Merges another stack state into this instance's stack state.
+ * See the Java Virtual Machine Specification, Second Edition, page 146: 4.9.2
+ * for details.
+ */
+ public void merge(OperandStack s){
+ if ( (slotsUsed() != s.slotsUsed()) || (size() != s.size()) )
+ throw new StructuralCodeConstraintException("Cannot merge stacks of different size:\nOperandStack A:\n"+this+"\nOperandStack B:\n"+s);
+
+ for (int i=0; i<size(); i++){
+ // If the object _was_ initialized and we're supposed to merge
+ // in some uninitialized object, we reject the code (see vmspec2, 4.9.4, last paragraph).
+ if ( (! (stack.get(i) instanceof UninitializedObjectType)) && (s.stack.get(i) instanceof UninitializedObjectType) ){
+ throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object on the stack detected.");
+ }
+ // Even harder, we're not initialized but are supposed to broaden
+ // the known object type
+ if ( (!(stack.get(i).equals(s.stack.get(i)))) && (stack.get(i) instanceof UninitializedObjectType) && (!(s.stack.get(i) instanceof UninitializedObjectType))){
+ throw new StructuralCodeConstraintException("Backwards branch with an uninitialized object on the stack detected.");
+ }
+ // on the other hand...
+ if (stack.get(i) instanceof UninitializedObjectType){ //if we have an uninitialized object here
+ if (! (s.stack.get(i) instanceof UninitializedObjectType)){ //that has been initialized by now
+ stack.set(i, ((UninitializedObjectType) (stack.get(i))).getInitialized() ); //note that.
+ }
+ }
+ if (! stack.get(i).equals(s.stack.get(i))){
+ if ( (stack.get(i) instanceof ReferenceType) &&
+ (s.stack.get(i) instanceof ReferenceType) ){
+ stack.set(i, ((ReferenceType) stack.get(i)).getFirstCommonSuperclass((ReferenceType) (s.stack.get(i))));
+ }
+ else{
+ throw new StructuralCodeConstraintException("Cannot merge stacks of different types:\nStack A:\n"+this+"\nStack B:\n"+s);
+ }
+ }
+ }
+ }
+
+ /**
+ * Replaces all occurences of u in this OperandStack instance
+ * with an "initialized" ObjectType.
+ */
+ public void initializeObject(UninitializedObjectType u){
+ for (int i=0; i<stack.size(); i++){
+ if (stack.get(i) == u){
+ stack.set(i, u.getInitialized());
+ }
+ }
+ }
+
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/StackMapHelper.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/StackMapHelper.java
new file mode 100644
index 000000000..a9275fe1b
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/StackMapHelper.java
@@ -0,0 +1,225 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.apache.bcel.Constants;
+import org.aspectj.apache.bcel.classfile.StackMapFrame;
+import org.aspectj.apache.bcel.classfile.StackMapTable;
+import org.aspectj.apache.bcel.generic.BranchInstruction;
+import org.aspectj.apache.bcel.generic.CodeExceptionGen;
+import org.aspectj.apache.bcel.generic.ConstantPoolGen;
+import org.aspectj.apache.bcel.generic.InstructionHandle;
+import org.aspectj.apache.bcel.generic.InstructionTargeter;
+import org.aspectj.apache.bcel.generic.MethodGen;
+import org.aspectj.apache.bcel.generic.ObjectType;
+import org.aspectj.apache.bcel.generic.RET;
+import org.aspectj.apache.bcel.generic.ReturnaddressType;
+import org.aspectj.apache.bcel.generic.Type;
+
+
+public class StackMapHelper {
+
+ public static int count = 0;
+ private Map framesAtBranchDestinations /*<InstructionHandle,Frame>*/= new HashMap();
+ private boolean debugPumping=false;
+
+ public StackMapHelper() {}
+
+ /** Merge the new frame with anything we already know */
+ private void storeFrameAtBranchDestination(InstructionHandle iHandle,Object newFrame) {
+ if (!iHandle.isJumpDestination()) return;
+ Frame existingFrame = (Frame)framesAtBranchDestinations.get(iHandle);
+ if (debugPumping) System.out.println(((Frame)newFrame).toString("Storing at "+iHandle.getPosition()+":"));
+ if (existingFrame==null) {
+ framesAtBranchDestinations.put(iHandle,newFrame);
+ } else { // merge
+ Frame f = (Frame)newFrame;
+ existingFrame.getLocals().merge(f.getLocals());
+ existingFrame.getStack().merge(f.getStack());
+ }
+ count++; // number of frames stored
+ }
+
+ /**
+ * For everything targeted as a jump destination, create the frame. needs to return offsets to
+ */
+ private Frame[] getFramesAtBranchDestinations(InstructionHandle iHandle) {
+ Frame[] outputFrames = new Frame[framesAtBranchDestinations.size()];
+ int i=0;
+ while (iHandle!=null) {
+ if (iHandle.isJumpDestination()) {
+ Frame f = (Frame)framesAtBranchDestinations.get(iHandle);
+ f.position = iHandle.getPosition(); // fix it for StackMapFrame creation
+ outputFrames[i++]=f;
+ }
+ iHandle = iHandle.getNext();
+ }
+ return outputFrames;
+ }
+
+ /**
+ * Drive the lightweight verifier process to produce the Frames that will be used
+ * to construct the StackMapTable attribute.
+ */
+ public StackMapTable produceStackMapTableAttribute(MethodGen mg) {
+ // Don't bother if there is no code
+ if (mg.isAbstract() || mg.isNative() ) return null;
+
+ ConstantPoolGen cpg = mg.getConstantPool();
+ mg.getInstructionList().setPositions(); // fixes up the stupid bloody optimizations of LDC
+ ExecutionVisitor executionVisitor = new ExecutionVisitor(cpg);
+ ControlFlowGraph cflowGraph = new ControlFlowGraph(mg);
+ Frame initialFrame = createInitialFrame(mg);
+ CodeExceptionGen[] handlers = mg.getExceptionHandlers();
+
+ // now the initial frame is setup and we can start 'running the code'
+ if (debugPumping) System.err.println("Initial frame at start of method: "+initialFrame.toString());
+
+ InstructionContext contextOfFirstInstruction = cflowGraph.contextOf(mg.getInstructionList().getStart());
+ processInstructions(cflowGraph,contextOfFirstInstruction,initialFrame,executionVisitor,handlers);
+ Frame[] frames = getFramesAtBranchDestinations(mg.getInstructionList().getStart());
+ StackMapTable table = StackMapTable.forFrames(frames,cpg);
+ return table;
+ }
+
+ private boolean isRETInstruction(InstructionContext ic) {
+ return (ic.getInstruction().getInstruction() instanceof RET);
+ }
+
+ /**
+ * Whenever the outgoing frame situation of an InstructionContext changes,
+ * all its successors are put [back] into the queue [as if they were unvisited].
+ * The proof of termination is about the existence of a fix point of frame merging.
+ */
+
+ private void processInstructions( ControlFlowGraph flowGraph, InstructionContext start, Frame initialFrame, ExecutionVisitor executionVis, CodeExceptionGen[] handlers) {
+
+ InstructionContextQueue queue = new InstructionContextQueue();
+
+ // Passing in an empty array list here indicates no instruction was executed previously,
+ // which is interpreted as this being a 'top level' routine - no previous Jsr
+ start.execute(initialFrame, new ArrayList(), executionVis);
+ storeFrameAtBranchDestination(start.getInstruction(),initialFrame.clone());
+ queue.add(start, new ArrayList());
+
+ while (!queue.isEmpty()){
+
+ // Retrieve the next instruction context to look at and the execution chain we followed to get to it
+ InstructionContext instructionToProcess = queue.getIC(0);
+ ArrayList executionChain = queue.getEC(0);
+ queue.remove(0);
+
+
+ Frame incomingFrame = instructionToProcess.getOutFrame(executionChain);
+ executionChain.add(instructionToProcess);
+// Frame outgoingFrame = null;
+
+ if (isRETInstruction(instructionToProcess)) {
+ // We can only follow *one* successor, the one after the JSR that was recently executed.
+ RET ret = (RET) (instructionToProcess.getInstruction().getInstruction());
+ ReturnaddressType t = (ReturnaddressType) incomingFrame.getLocals().get(ret.getIndex());
+ InstructionContext theSuccessor = flowGraph.contextOf(t.getTarget());
+ if (theSuccessor.execute((Frame)incomingFrame.clone(), executionChain, executionVis)) {
+ queue.add(theSuccessor, executionChain);
+ }
+ } else { // not a RET instruction
+ // Normal successors - add them to the queue of successors
+ InstructionContext[] successors = instructionToProcess.getSuccessors();
+ for (int s=0; s<successors.length; s++) {
+ InstructionContext nextSuccessor = successors[s];
+ Frame outgoingFrame = (Frame)incomingFrame.clone();
+// System.out.println("Processed: "+instructionToProcess);
+ storeFrameAtBranchDestination(nextSuccessor.getInstruction(),outgoingFrame.clone());
+ if (nextSuccessor.execute(outgoingFrame, executionChain, executionVis)){
+ queue.add(nextSuccessor, executionChain);
+ }
+ }
+ }
+
+ // Exception Handlers. Add them to the queue of successors.
+ // [subroutines are never protected; mandated by JustIce]
+ ExceptionHandler[] exc_hds = instructionToProcess.getExceptionHandlers();
+ for (int s=0; s<exc_hds.length; s++){
+ // TODO: the "oldchain" and "newchain" is used to determine the subroutine
+ // we're in (by searching for the last JSR) by the InstructionContext
+ // implementation. Therefore, we should not use this chain mechanism
+ // when dealing with exception handlers.
+ // Example: a JSR with an exception handler as its successor does not
+ // mean we're in a subroutine if we go to the exception handler.
+ // We should address this problem later; by now we simply "cut" the chain
+ // by using an empty chain for the exception handlers.
+ InstructionContext theExceptionHandlerBlock = flowGraph.contextOf(exc_hds[s].getHandlerStart());
+ Frame f = new Frame(incomingFrame.getLocals(), new OperandStack (incomingFrame.getStack().maxStack(), (exc_hds[s].getExceptionType()==null? Type.THROWABLE : exc_hds[s].getExceptionType())) );
+// System.out.println("Processed: "+instructionToProcess);
+ storeFrameAtBranchDestination(theExceptionHandlerBlock.getInstruction(), f.clone());
+ if (theExceptionHandlerBlock.execute(f, new ArrayList(), executionVis)){
+ queue.add(theExceptionHandlerBlock, new ArrayList());
+ }
+ }
+ }
+ }
+
+ // ---
+ public static Frame createInitialFrame(MethodGen mg) {
+ Frame initialFrame = new Frame(mg.getMaxLocals(),mg.getMaxStack());
+ int pos=0;
+ if ( !mg.isStatic() ) {
+ if (mg.getName().equals(Constants.CONSTRUCTOR_NAME)){
+ Frame._this = new UninitializedObjectType(new ObjectType(mg.getClassName()),true,-1); // was clazz.getClassName
+ initialFrame.getLocals().set(pos++, Frame._this);
+ } else {
+ Frame._this = null;
+ initialFrame.getLocals().set(pos++, new ObjectType(mg.getClassName()));
+ }
+ }
+ Type[] argtypes = mg.getArgumentTypes();
+ int twoslotoffset = 0;
+ for (int j=0; j<argtypes.length; j++){
+ if (argtypes[j] == Type.SHORT || argtypes[j] == Type.BYTE || argtypes[j] == Type.CHAR || argtypes[j] == Type.BOOLEAN){
+ argtypes[j] = Type.INT;
+ }
+ initialFrame.getLocals().set(twoslotoffset + j + (mg.isStatic()?0:1), argtypes[j]);
+ if (argtypes[j].getSize() == 2) {
+ twoslotoffset++;
+ initialFrame.getLocals().set(twoslotoffset + j + (mg.isStatic()?0:1), Type.TOP); // should that be 'top' too (as in filler...)
+ }
+ pos = twoslotoffset + j + (mg.isStatic()?0:1);
+ }
+ initialFrame.getLocals().haveSet(pos+1);
+ return initialFrame;
+ }
+
+
+
+ /**
+ * Constructs the initial frame for a method then applies each of the table entries in turn, the return value is
+ * an array of complete 'unpacked' frames.
+ */
+ public static Frame[] reconstructFrames(MethodGen method,StackMapTable table) {
+ boolean debug=true;
+ StringBuffer offsets = new StringBuffer();
+ Frame theFrame = StackMapHelper.createInitialFrame(method);
+
+ if (debug) System.out.println("Initial frame is "+theFrame);
+ StackMapFrame[] frames = table.getStackMap();
+ int offset=0;
+ Frame[] fullFrames = new Frame[frames.length+1];
+ fullFrames[0] = (Frame)theFrame.clone();
+ for (int f = 0; f < frames.length; f++) {
+ StackMapFrame frame = frames[f];
+ if (f==0) offset=frame.getByteCodeOffset();
+ else offset+=1+frame.getByteCodeOffset();
+ theFrame.apply(frame);
+ fullFrames[f+1]=(Frame)theFrame.clone();
+ offsets.append(offset+" ");
+ if (debug) System.out.println("Current frame (offset="+offset+") now "+theFrame);
+ }
+ System.err.println("Frame offsets: "+offsets.toString());
+ return fullFrames;
+ }
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Subroutine.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Subroutine.java
new file mode 100644
index 000000000..211b06b3c
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Subroutine.java
@@ -0,0 +1,127 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.aspectj.apache.bcel.generic.*;
+
+/**
+ * This interface defines properties of JVM bytecode subroutines.
+ * Note that it is 'abused' to maintain the top-level code in a
+ * consistent fashion, too.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public interface Subroutine{
+
+ /**
+ * Returns all the JsrInstructions that have the
+ * first instruction of this subroutine as their target.
+ * <B>Must not be invoked on the 'top-level subroutine'.</B>
+ */
+ public InstructionHandle[] getEnteringJsrInstructions();
+
+ /**
+ * Returns the one and only RET that leaves the subroutine.
+ * Note that JustIce has a pretty rigid notion of a subroutine.
+ * <B>Must not be invoked on the 'top-level subroutine'.</B>
+ *
+ * @see org.aspectj.apache.bcel.verifier.structurals.Subroutines
+ */
+ public InstructionHandle getLeavingRET();
+
+ /**
+ * Returns all instructions that together form this subroutine.
+ * Note that an instruction is part of exactly one subroutine
+ * (the top-level code is considered to be a special subroutine) -
+ * else it is not reachable at all (dead code).
+ */
+ public InstructionHandle[] getInstructions();
+
+ /**
+ * Returns if the given InstructionHandle refers to an instruction
+ * that is part of this subroutine. This is a convenience method
+ * that saves iteration over the InstructionHandle objects returned
+ * by getInstructions().
+ *
+ * @see #getInstructions()
+ */
+ public boolean contains(InstructionHandle inst);
+
+ /**
+ * Returns an int[] containing the indices of the local variable slots
+ * accessed by this Subroutine (read-accessed, write-accessed or both);
+ * local variables referenced by subroutines of this subroutine are
+ * not included.
+ *
+ * @see #getRecursivelyAccessedLocalsIndices()
+ */
+ public int[] getAccessedLocalsIndices();
+
+ /**
+ * Returns an int[] containing the indices of the local variable slots
+ * accessed by this Subroutine (read-accessed, write-accessed or both);
+ * local variables referenced by subroutines of this subroutine are
+ * included.
+ *
+ * @see #getAccessedLocalsIndices()
+ */
+ public int[] getRecursivelyAccessedLocalsIndices();
+
+ /**
+ * Returns the subroutines that are directly called from this subroutine.
+ */
+ public Subroutine[] subSubs();
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/SubroutineImpl.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/SubroutineImpl.java
new file mode 100644
index 000000000..8412ddd50
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/SubroutineImpl.java
@@ -0,0 +1,293 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.aspectj.apache.bcel.generic.ASTORE;
+import org.aspectj.apache.bcel.generic.IndexedInstruction;
+import org.aspectj.apache.bcel.generic.Instruction;
+import org.aspectj.apache.bcel.generic.InstructionHandle;
+import org.aspectj.apache.bcel.generic.JsrInstruction;
+import org.aspectj.apache.bcel.generic.LocalVariableInstruction;
+import org.aspectj.apache.bcel.generic.RET;
+import org.aspectj.apache.bcel.verifier.exc.AssertionViolatedException;
+import org.aspectj.apache.bcel.verifier.exc.StructuralCodeConstraintException;
+
+class SubroutineImpl implements Subroutine {
+
+ private final Subroutines subroutines;
+
+ /**
+ * UNSET, a symbol for an uninitialized localVariable
+ * field. This is used for the "top-level" Subroutine;
+ * i.e. no subroutine.
+ */
+ private static final int UNSET = -1;
+
+ /** The instructions that belong to this subroutine. */
+ private HashSet instructions = new HashSet(); // Elements: InstructionHandle
+
+ /**
+ * The Local Variable slot where the first
+ * instruction of this subroutine (an ASTORE) stores
+ * the JsrInstruction's ReturnAddress in and
+ * the RET of this subroutine operates on.
+ */
+ int localVariable = UNSET;
+
+ /**
+ * The JSR or JSR_W instructions that define this
+ * subroutine by targeting it.
+ */
+ HashSet theJSRs = new HashSet();
+
+ /**
+ * The RET instruction that leaves this subroutine.
+ */
+ InstructionHandle theRET;
+
+ /**
+ * The default constructor.
+ * @param subroutines TODO
+ */
+ public SubroutineImpl(Subroutines subroutines){
+ this.subroutines = subroutines;
+ }
+
+
+ /**
+ * Adds a new JSR or JSR_W that has this subroutine as its target.
+ */
+ public void addEnteringJsrInstruction(InstructionHandle jsrInst){
+ if ( (jsrInst == null) || (! (jsrInst.getInstruction() instanceof JsrInstruction))){
+ throw new AssertionViolatedException("Expecting JsrInstruction InstructionHandle.");
+ }
+ if (localVariable == UNSET){
+ throw new AssertionViolatedException("Set the localVariable first!");
+ }
+ else{
+ // Something is wrong when an ASTORE is targeted that does not operate on the same local variable than the rest of the
+ // JsrInstruction-targets and the RET.
+ // (We don't know out leader here so we cannot check if we're really targeted!)
+ if (localVariable != ((ASTORE) (((JsrInstruction) jsrInst.getInstruction()).getTarget().getInstruction())).getIndex()){
+ throw new AssertionViolatedException("Setting a wrong JsrInstruction.");
+ }
+ }
+ theJSRs.add(jsrInst);
+ }
+
+ // ---
+ /*
+ * Refer to the Subroutine interface for documentation.
+ */
+ public boolean contains(InstructionHandle inst){
+ return instructions.contains(inst);
+ }
+
+ /*
+ * Satisfies Subroutine.getAccessedLocalIndices().
+ */
+ public int[] getAccessedLocalsIndices(){
+ //TODO: Implement caching.
+ HashSet acc = new HashSet();
+ if (theRET == null && this != this.subroutines.TOPLEVEL){
+ throw new AssertionViolatedException("This subroutine object must be built up completely before calculating accessed locals.");
+ }
+ Iterator i = instructions.iterator();
+ while (i.hasNext()){
+ InstructionHandle ih = (InstructionHandle) i.next();
+ // RET is not a LocalVariableInstruction in the current version of BCEL.
+ if (ih.getInstruction() instanceof LocalVariableInstruction || ih.getInstruction() instanceof RET){
+ int idx = ((IndexedInstruction) (ih.getInstruction())).getIndex();
+ acc.add(new Integer(idx));
+ // LONG? DOUBLE?.
+ try{
+ // LocalVariableInstruction instances are typed without the need to look into
+ // the constant pool.
+ if (ih.getInstruction() instanceof LocalVariableInstruction){
+ int s = ((LocalVariableInstruction) ih.getInstruction()).getType(null).getSize();
+ if (s==2) acc.add(new Integer(idx+1));
+ }
+ }
+ catch(RuntimeException re){
+ throw new AssertionViolatedException("Oops. BCEL did not like NULL as a ConstantPoolGen object.");
+ }
+ }
+ }
+
+ int[] ret = new int[acc.size()];
+ i = acc.iterator();
+ int j=-1;
+ while (i.hasNext()){
+ j++;
+ ret[j] = ((Integer) i.next()).intValue();
+ }
+ return ret;
+ }
+
+ /*
+ * Refer to the Subroutine interface for documentation.
+ */
+ public InstructionHandle[] getEnteringJsrInstructions(){
+ if (this == this.subroutines.TOPLEVEL) {
+ throw new AssertionViolatedException("getLeavingRET() called on top level pseudo-subroutine.");
+ }
+ InstructionHandle[] jsrs = new InstructionHandle[theJSRs.size()];
+ return (InstructionHandle[]) (theJSRs.toArray(jsrs));
+ }
+
+ /*
+ * Refer to the Subroutine interface for documentation.
+ */
+ public InstructionHandle[] getInstructions(){
+ InstructionHandle[] ret = new InstructionHandle[instructions.size()];
+ return (InstructionHandle[]) instructions.toArray(ret);
+ }
+
+ /*
+ * Refer to the Subroutine interface for documentation.
+ */
+ public InstructionHandle getLeavingRET(){
+ if (this == this.subroutines.TOPLEVEL) {
+ throw new AssertionViolatedException("getLeavingRET() called on top level pseudo-subroutine.");
+ }
+ return theRET;
+ }
+
+ /* Satisfies Subroutine.getRecursivelyAccessedLocalsIndices(). */
+ public int[] getRecursivelyAccessedLocalsIndices(){
+ HashSet s = new HashSet();
+ int[] lvs = getAccessedLocalsIndices();
+ for (int j=0; j<lvs.length; j++){
+ s.add(new Integer(lvs[j]));
+ }
+ _getRecursivelyAccessedLocalsIndicesHelper(s, this.subSubs());
+ int[] ret = new int[s.size()];
+ Iterator i = s.iterator();
+ int j=-1;
+ while (i.hasNext()){
+ j++;
+ ret[j] = ((Integer) i.next()).intValue();
+ }
+ return ret;
+ }
+
+ /*
+ * Satisfies Subroutine.subSubs().
+ */
+ public Subroutine[] subSubs(){
+ HashSet h = new HashSet();
+
+ Iterator i = instructions.iterator();
+ while (i.hasNext()){
+ Instruction inst = ((InstructionHandle) i.next()).getInstruction();
+ if (inst instanceof JsrInstruction){
+ InstructionHandle targ = ((JsrInstruction) inst).getTarget();
+ h.add(this.subroutines.getSubroutine(targ));
+ }
+ }
+ Subroutine[] ret = new Subroutine[h.size()];
+ return (Subroutine[]) h.toArray(ret);
+ }
+
+ /**
+ * Returns a String representation of this object, merely
+ * for debugging purposes.
+ * (Internal) Warning: Verbosity on a problematic subroutine may cause
+ * stack overflow errors due to recursive subSubs() calls.
+ * Don't use this, then.
+ */
+ public String toString(){
+ String ret = "Subroutine (size:"+instructions.size()+"instructions): Local variable is '"+localVariable+"', JSRs are '"+theJSRs+"', RET is '"+theRET+"', Instructions: '"+instructions.toString()+"'.";
+
+ ret += " Accessed local variable slots: '";
+ int[] alv = getAccessedLocalsIndices();
+ for (int i=0; i<alv.length; i++){
+ ret += alv[i]+" ";
+ }
+ ret+="'.";
+
+ ret += " Recursively (via subsub...routines) accessed local variable slots: '";
+ alv = getRecursivelyAccessedLocalsIndices();
+ for (int i=0; i<alv.length; i++){
+ ret += alv[i]+" ";
+ }
+ ret+="'.";
+
+ return ret;
+ }
+
+ /**
+ * A recursive helper method for getRecursivelyAccessedLocalsIndices().
+ * @see #getRecursivelyAccessedLocalsIndices()
+ */
+ private void _getRecursivelyAccessedLocalsIndicesHelper(HashSet s, Subroutine[] subs){
+ for (int i=0; i<subs.length; i++){
+ int[] lvs = subs[i].getAccessedLocalsIndices();
+ for (int j=0; j<lvs.length; j++){
+ s.add(new Integer(lvs[j]));
+ }
+ if(subs[i].subSubs().length != 0){
+ _getRecursivelyAccessedLocalsIndicesHelper(s, subs[i].subSubs());
+ }
+ }
+ }
+
+ /*
+ * Adds an instruction to this subroutine.
+ * All instructions must have been added before invoking setLeavingRET().
+ * @see #setLeavingRET
+ */
+ void addInstruction(InstructionHandle ih){
+ if (theRET != null){
+ throw new AssertionViolatedException("All instructions must have been added before invoking setLeavingRET().");
+ }
+ instructions.add(ih);
+ }
+
+ /**
+ * Sets the leaving RET instruction. Must be invoked after all instructions are added.
+ * Must not be invoked for top-level 'subroutine'.
+ */
+ void setLeavingRET(){
+ if (localVariable == UNSET){
+ throw new AssertionViolatedException("setLeavingRET() called for top-level 'subroutine' or forgot to set local variable first.");
+ }
+ Iterator iter = instructions.iterator();
+ InstructionHandle ret = null;
+ while(iter.hasNext()){
+ InstructionHandle actual = (InstructionHandle) iter.next();
+ if (actual.getInstruction() instanceof RET){
+ if (ret != null){
+ throw new StructuralCodeConstraintException("Subroutine with more then one RET detected: '"+ret+"' and '"+actual+"'.");
+ }
+ else{
+ ret = actual;
+ }
+ }
+ }
+ if (ret == null){
+ throw new StructuralCodeConstraintException("Subroutine without a RET detected.");
+ }
+ if (((RET) ret.getInstruction()).getIndex() != localVariable){
+ throw new StructuralCodeConstraintException("Subroutine uses '"+ret+"' which does not match the correct local variable '"+localVariable+"'.");
+ }
+ theRET = ret;
+ }
+
+ /*
+ * Sets the local variable slot the ASTORE that is targeted
+ * by the JsrInstructions of this subroutine operates on.
+ * This subroutine's RET operates on that same local variable
+ * slot, of course.
+ */
+ void setLocalVariable(int i){
+ if (localVariable != UNSET){
+ throw new AssertionViolatedException("localVariable set twice.");
+ }
+ else{
+ localVariable = i;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Subroutines.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Subroutines.java
new file mode 100644
index 000000000..d40a1387c
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Subroutines.java
@@ -0,0 +1,395 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.aspectj.apache.bcel.generic.*;
+import org.aspectj.apache.bcel.verifier.exc.*;
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+ /**
+ * Instances of this class contain information about the subroutines
+ * found in a code array of a method.
+ * This implementation considers the top-level (the instructions
+ * reachable without a JSR or JSR_W starting off from the first
+ * instruction in a code array of a method) being a special subroutine;
+ * see getTopLevel() for that.
+ * Please note that the definition of subroutines in the Java Virtual
+ * Machine Specification, Second Edition is somewhat incomplete.
+ * Therefore, JustIce uses an own, more rigid notion.
+ * Basically, a subroutine is a piece of code that starts at the target
+ * of a JSR of JSR_W instruction and ends at a corresponding RET
+ * instruction. Note also that the control flow of a subroutine
+ * may be complex and non-linear; and that subroutines may be nested.
+ * JustIce also mandates subroutines not to be protected by exception
+ * handling code (for the sake of control flow predictability).
+ * To understand JustIce's notion of subroutines, please read
+ *
+ * TODO: refer to the paper.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ * @see #getTopLevel()
+ */
+public class Subroutines{
+
+ /**
+ * The Hashtable containing the subroutines found.
+ * Key: InstructionHandle of the leader of the subroutine.
+ * Elements: SubroutineImpl objects.
+ */
+ private Hashtable subroutines = new Hashtable();
+
+ /**
+ * This is referring to a special subroutine, namely the
+ * top level. This is not really a subroutine but we use
+ * it to distinguish between top level instructions and
+ * unreachable instructions.
+ */
+ public final Subroutine TOPLEVEL;
+
+
+ public Subroutines(MethodGen mg){
+
+ InstructionHandle[] all = mg.getInstructionList().getInstructionHandles();
+ CodeExceptionGen[] handlers = mg.getExceptionHandlers();
+
+ // Define our "Toplevel" fake subroutine.
+ TOPLEVEL = new SubroutineImpl(this);
+
+ // Calculate "real" subroutines.
+ HashSet sub_leaders = new HashSet(); // Elements: InstructionHandle
+ InstructionHandle ih = all[0];
+ for (int i=0; i<all.length; i++){
+ Instruction inst = all[i].getInstruction();
+ if (inst instanceof JsrInstruction){
+ sub_leaders.add(((JsrInstruction) inst).getTarget());
+ }
+ }
+
+ // Build up the database.
+ Iterator iter = sub_leaders.iterator();
+ while (iter.hasNext()){
+ SubroutineImpl sr = new SubroutineImpl(this);
+ InstructionHandle astore = (InstructionHandle) (iter.next());
+ sr.setLocalVariable( ((ASTORE) (astore.getInstruction())).getIndex() );
+ subroutines.put(astore, sr);
+ }
+
+ // Fake it a bit. We want a virtual "TopLevel" subroutine.
+ subroutines.put(all[0], TOPLEVEL);
+ sub_leaders.add(all[0]);
+
+ // Tell the subroutines about their JsrInstructions.
+ // Note that there cannot be a JSR targeting the top-level
+ // since "Jsr 0" is disallowed in Pass 3a.
+ // Instructions shared by a subroutine and the toplevel are
+ // disallowed and checked below, after the BFS.
+ for (int i=0; i<all.length; i++){
+ Instruction inst = all[i].getInstruction();
+ if (inst instanceof JsrInstruction){
+ InstructionHandle leader = ((JsrInstruction) inst).getTarget();
+ ((SubroutineImpl) getSubroutine(leader)).addEnteringJsrInstruction(all[i]);
+ }
+ }
+
+ // Now do a BFS from every subroutine leader to find all the
+ // instructions that belong to a subroutine.
+ HashSet instructions_assigned = new HashSet(); // we don't want to assign an instruction to two or more Subroutine objects.
+
+ Hashtable colors = new Hashtable(); //Graph colouring. Key: InstructionHandle, Value: java.awt.Color .
+
+ iter = sub_leaders.iterator();
+ while (iter.hasNext()){
+ // Do some BFS with "actual" as the root of the graph.
+ InstructionHandle actual = (InstructionHandle) (iter.next());
+ // Init colors
+ for (int i=0; i<all.length; i++){
+ colors.put(all[i], Color.white);
+ }
+ colors.put(actual, Color.gray);
+ // Init Queue
+ ArrayList Q = new ArrayList();
+ Q.add(actual); // add(Obj) adds to the end, remove(0) removes from the start.
+
+ /* BFS ALGORITHM MODIFICATION: Start out with multiple "root" nodes, as exception handlers are starting points of top-level code, too. [why top-level? TODO: Refer to the special JustIce notion of subroutines.]*/
+ if (actual == all[0]){
+ for (int j=0; j<handlers.length; j++){
+ colors.put(handlers[j].getHandlerPC(), Color.gray);
+ Q.add(handlers[j].getHandlerPC());
+ }
+ }
+ /* CONTINUE NORMAL BFS ALGORITHM */
+
+ // Loop until Queue is empty
+ while (Q.size() != 0){
+ InstructionHandle u = (InstructionHandle) Q.remove(0);
+ InstructionHandle[] successors = getSuccessors(u);
+ for (int i=0; i<successors.length; i++){
+ if (((Color) colors.get(successors[i])) == Color.white){
+ colors.put(successors[i], Color.gray);
+ Q.add(successors[i]);
+ }
+ }
+ colors.put(u, Color.black);
+ }
+ // BFS ended above.
+ for (int i=0; i<all.length; i++){
+ if (colors.get(all[i]) == Color.black){
+ ((SubroutineImpl) (actual==all[0]?getTopLevel():getSubroutine(actual))).addInstruction(all[i]);
+ if (instructions_assigned.contains(all[i])){
+ throw new StructuralCodeConstraintException("Instruction '"+all[i]+"' is part of more than one subroutine (or of the top level and a subroutine).");
+ }
+ else{
+ instructions_assigned.add(all[i]);
+ }
+ }
+ }
+ if (actual != all[0]){// If we don't deal with the top-level 'subroutine'
+ ((SubroutineImpl) getSubroutine(actual)).setLeavingRET();
+ }
+ }
+
+ // Now make sure no instruction of a Subroutine is protected by exception handling code
+ // as is mandated by JustIces notion of subroutines.
+ for (int i=0; i<handlers.length; i++){
+ InstructionHandle _protected = handlers[i].getStartPC();
+ while (_protected != handlers[i].getEndPC().getNext()){// Note the inclusive/inclusive notation of "generic API" exception handlers!
+ Enumeration subs = subroutines.elements();
+ while (subs.hasMoreElements()){
+ Subroutine sub = (Subroutine) subs.nextElement();
+ if (sub != subroutines.get(all[0])){ // We don't want to forbid top-level exception handlers.
+ if (sub.contains(_protected)){
+ throw new StructuralCodeConstraintException("Subroutine instruction '"+_protected+"' is protected by an exception handler, '"+handlers[i]+"'. This is forbidden by the JustIce verifier due to its clear definition of subroutines.");
+ }
+ }
+ }
+ _protected = _protected.getNext();
+ }
+ }
+
+ // Now make sure no subroutine is calling a subroutine
+ // that uses the same local variable for the RET as themselves
+ // (recursively).
+ // This includes that subroutines may not call themselves
+ // recursively, even not through intermediate calls to other
+ // subroutines.
+ noRecursiveCalls(getTopLevel(), new HashSet());
+
+ }
+
+ /**
+ * This (recursive) utility method makes sure that
+ * no subroutine is calling a subroutine
+ * that uses the same local variable for the RET as themselves
+ * (recursively).
+ * This includes that subroutines may not call themselves
+ * recursively, even not through intermediate calls to other
+ * subroutines.
+ *
+ * @throws StructuralCodeConstraintException if the above constraint is not satisfied.
+ */
+ private void noRecursiveCalls(Subroutine sub, HashSet set){
+ Subroutine[] subs = sub.subSubs();
+
+ for (int i=0; i<subs.length; i++){
+ int index = ((RET) (subs[i].getLeavingRET().getInstruction())).getIndex();
+
+ if (!set.add(new Integer(index))){
+ // Don't use toString() here because of possibly infinite recursive subSubs() calls then.
+ SubroutineImpl si = (SubroutineImpl) subs[i];
+ throw new StructuralCodeConstraintException("Subroutine with local variable '"+si.localVariable+"', JSRs '"+si.theJSRs+"', RET '"+si.theRET+"' is called by a subroutine which uses the same local variable index as itself; maybe even a recursive call? JustIce's clean definition of a subroutine forbids both.");
+ }
+
+ noRecursiveCalls(subs[i], set);
+
+ set.remove(new Integer(index));
+ }
+ }
+
+ /**
+ * Returns the Subroutine object associated with the given
+ * leader (that is, the first instruction of the subroutine).
+ * You must not use this to get the top-level instructions
+ * modeled as a Subroutine object.
+ *
+ * @see #getTopLevel()
+ */
+ public Subroutine getSubroutine(InstructionHandle leader){
+ Subroutine ret = (Subroutine) subroutines.get(leader);
+
+ if (ret == null){
+ throw new AssertionViolatedException("Subroutine requested for an InstructionHandle that is not a leader of a subroutine.");
+ }
+
+ if (ret == TOPLEVEL){
+ throw new AssertionViolatedException("TOPLEVEL special subroutine requested; use getTopLevel().");
+ }
+
+ return ret;
+ }
+
+ /**
+ * Returns the subroutine object associated with the
+ * given instruction. This is a costly operation, you
+ * should consider using getSubroutine(InstructionHandle).
+ * Returns 'null' if the given InstructionHandle lies
+ * in so-called 'dead code', i.e. code that can never
+ * be executed.
+ *
+ * @see #getSubroutine(InstructionHandle)
+ * @see #getTopLevel()
+ */
+ public Subroutine subroutineOf(InstructionHandle any){
+ Iterator i = subroutines.values().iterator();
+ while (i.hasNext()){
+ Subroutine s = (Subroutine) i.next();
+ if (s.contains(any)) return s;
+ }
+System.err.println("DEBUG: Please verify '"+any+"' lies in dead code.");
+ return null;
+ //throw new AssertionViolatedException("No subroutine for InstructionHandle found (DEAD CODE?).");
+ }
+
+ /**
+ * For easy handling, the piece of code that is <B>not</B> a
+ * subroutine, the top-level, is also modeled as a Subroutine
+ * object.
+ * It is a special Subroutine object where <B>you must not invoke
+ * getEnteringJsrInstructions() or getLeavingRET()</B>.
+ *
+ * @see Subroutine#getEnteringJsrInstructions()
+ * @see Subroutine#getLeavingRET()
+ */
+ public Subroutine getTopLevel(){
+ return TOPLEVEL;
+ }
+ /**
+ * A utility method that calculates the successors of a given InstructionHandle
+ * <B>in the same subroutine</B>. That means, a RET does not have any successors
+ * as defined here. A JsrInstruction has its physical successor as its successor
+ * (opposed to its target) as defined here.
+ */
+ private static InstructionHandle[] getSuccessors(InstructionHandle instruction){
+ final InstructionHandle[] empty = new InstructionHandle[0];
+ final InstructionHandle[] single = new InstructionHandle[1];
+ final InstructionHandle[] pair = new InstructionHandle[2];
+
+ Instruction inst = instruction.getInstruction();
+
+ if (inst instanceof RET){
+ return empty;
+ }
+
+ // Terminates method normally.
+ if (inst instanceof ReturnInstruction){
+ return empty;
+ }
+
+ // Terminates method abnormally, because JustIce mandates
+ // subroutines not to be protected by exception handlers.
+ if (inst instanceof ATHROW){
+ return empty;
+ }
+
+ // See method comment.
+ if (inst instanceof JsrInstruction){
+ single[0] = instruction.getNext();
+ return single;
+ }
+
+ if (inst instanceof GotoInstruction){
+ single[0] = ((GotoInstruction) inst).getTarget();
+ return single;
+ }
+
+ if (inst instanceof BranchInstruction){
+ if (inst instanceof Select){
+ // BCEL's getTargets() returns only the non-default targets,
+ // thanks to Eli Tilevich for reporting.
+ InstructionHandle[] matchTargets = ((Select) inst).getTargets();
+ InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1];
+ ret[0] = ((Select) inst).getTarget();
+ System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length);
+ return ret;
+ }
+ else{
+ pair[0] = instruction.getNext();
+ pair[1] = ((BranchInstruction) inst).getTarget();
+ return pair;
+ }
+ }
+
+ // default case: Fall through.
+ single[0] = instruction.getNext();
+ return single;
+ }
+
+ /**
+ * Returns a String representation of this object; merely for debugging puposes.
+ */
+ public String toString(){
+ return "---\n"+subroutines.toString()+"\n---\n";
+ }
+
+ public Collection getIndividualSubroutines() {
+ return subroutines.values();
+ }
+}
diff --git a/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/UninitializedObjectType.java b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/UninitializedObjectType.java
new file mode 100644
index 000000000..3b8814555
--- /dev/null
+++ b/bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/UninitializedObjectType.java
@@ -0,0 +1,104 @@
+package org.aspectj.apache.bcel.verifier.utility;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache BCEL" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache BCEL", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
+ * ITS 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.aspectj.apache.bcel.*;
+import org.aspectj.apache.bcel.generic.*;
+
+/**
+ * This class represents an uninitialized object type; see The Java
+ * Virtual Machine Specification, Second Edition, page 147: 4.9.4 for
+ * more details.
+ *
+ * @version $Id$
+ * @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
+ */
+public class UninitializedObjectType extends ReferenceType implements Constants{
+
+ /** The "initialized" version. */
+ private ObjectType initialized;
+ private int loc;
+
+ /** Creates a new instance. */
+ public UninitializedObjectType(ObjectType t,boolean isThis,int loc){
+ super(T_UNKNOWN, "<UNINITIALIZED OBJECT OF TYPE '"+t.getClassName()+"'>");
+ initialized = t;
+ this.loc = loc;
+ this.isthis = isThis;
+ }
+
+ private boolean isthis;
+ /**
+ * Returns the ObjectType of the same class as the one of the uninitialized object
+ * represented by this UninitializedObjectType instance.
+ */
+ public ObjectType getInitialized(){
+ return initialized;
+ }
+
+ public boolean isThis() { return isthis; }
+ public int getLoc() { return loc; }
+
+ /**
+ * Returns true on equality of this and o.
+ * Equality means the ObjectType instances of "initialized"
+ * equal one another in this and the o instance.
+ *
+ */
+ public boolean equals(Object o){
+ if (! (o instanceof UninitializedObjectType)) return false;
+ return initialized.equals(((UninitializedObjectType)o).initialized);
+ }
+}
diff --git a/bcel-builder/testdata/stackmap/Code.class b/bcel-builder/testdata/stackmap/Code.class
new file mode 100644
index 000000000..81f7e8cc1
--- /dev/null
+++ b/bcel-builder/testdata/stackmap/Code.class
Binary files differ
diff --git a/bcel-builder/testdata/stackmap/Code.java b/bcel-builder/testdata/stackmap/Code.java
new file mode 100644
index 000000000..53a9202bb
--- /dev/null
+++ b/bcel-builder/testdata/stackmap/Code.java
@@ -0,0 +1,23 @@
+public class Code {
+ public void method1() {
+ int i = 1;
+ if (true) {
+ System.out.println("x");
+ }
+ i=2;
+ try {
+ int j = 5;
+ i=3;
+ System.out.println("y");
+ System.out.println("z");
+ } catch (Throwable t) {
+ System.out.println("e");
+ int k=3;
+ }
+ if (true) {
+ i = 4;
+ System.out.println("a");
+ }
+
+ }
+}
diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/preverifier/PreverifierBaseTestCase.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/preverifier/PreverifierBaseTestCase.java
new file mode 100644
index 000000000..746383342
--- /dev/null
+++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/preverifier/PreverifierBaseTestCase.java
@@ -0,0 +1,189 @@
+/* *******************************************************************
+ * Copyright (c) 2004 IBM
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Andy Clement - initial implementation {date}
+ * ******************************************************************/
+
+package org.aspectj.apache.bcel.classfile.tests.preverifier;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.aspectj.apache.bcel.Repository;
+import org.aspectj.apache.bcel.classfile.Attribute;
+import org.aspectj.apache.bcel.classfile.JavaClass;
+import org.aspectj.apache.bcel.classfile.Method;
+import org.aspectj.apache.bcel.classfile.annotation.Annotation;
+import org.aspectj.apache.bcel.generic.ClassGen;
+import org.aspectj.apache.bcel.generic.ConstantPoolGen;
+import org.aspectj.apache.bcel.generic.ObjectType;
+import org.aspectj.apache.bcel.generic.annotation.AnnotationGen;
+import org.aspectj.apache.bcel.generic.annotation.ElementNameValuePairGen;
+import org.aspectj.apache.bcel.generic.annotation.ElementValueGen;
+import org.aspectj.apache.bcel.generic.annotation.SimpleElementValueGen;
+import org.aspectj.apache.bcel.util.ClassPath;
+import org.aspectj.apache.bcel.util.SyntheticRepository;
+
+import junit.framework.TestCase;
+
+/**
+ * Super class for the Java5 tests, includes various helper methods.
+ */
+
+public class PreverifierBaseTestCase extends TestCase {
+
+ private boolean verbose = false;
+
+ protected File createTestdataFile(String name) {
+ return new File("testdata"+File.separator+name);
+ }
+
+ protected JavaClass getClassFromJar(String clazzname) throws ClassNotFoundException {
+ SyntheticRepository repos = createRepos("Java6BuiltCode.jar");
+ Repository.setRepository(repos);
+ return repos.loadClass(clazzname);
+ }
+
+ protected JavaClass getClassFromDir(String dir,String clazzname) throws ClassNotFoundException {
+ SyntheticRepository repos = createReposForDirectory(dir);
+ Repository.setRepository(repos);
+ return repos.loadClass(clazzname);
+ }
+
+ protected Method getMethod(JavaClass cl,String methodname) {
+ Method[] methods = cl.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method m = methods[i];
+ if (m.getName().equals(methodname)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ protected Method getMethod(JavaClass cl,String methodname,int count) {
+ Method[] methods = cl.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method m = methods[i];
+ if (m.getName().equals(methodname)) {
+ if (count==0) return m;
+ count--;
+ }
+ }
+ return null;
+ }
+
+ protected Method getMethod(ClassGen cg,String methodname,int count) {
+ Method[] methods = cg.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method m = methods[i];
+ if (m.getName().equals(methodname)) {
+ if (count==0) return m;
+ count--;
+ }
+ }
+ return null;
+ }
+
+ protected boolean wipe(String name) {
+ return new File("testdata"+File.separator+name).delete();
+ }
+
+ protected boolean wipe(String dir, String name) {
+ boolean b = wipe(dir+File.separator+name);
+ String[] files = new File(dir).list();
+ if (files==null || files.length==0) {
+ new File(dir).delete(); // Why does this not succeed? stupid thing
+ }
+ return b;
+ }
+
+
+ public SyntheticRepository createRepos(String cpentry) {
+ ClassPath cp = new ClassPath(
+ "testdata"+File.separator+cpentry+File.pathSeparator+"testdata"+File.separator+"stackmap"+File.pathSeparator+
+ System.getProperty("sun.boot.class.path"));
+ return SyntheticRepository.getInstance(cp);
+ }
+
+ public SyntheticRepository createReposForDirectory(String dir) {
+ ClassPath cp = new ClassPath(dir+File.pathSeparator+
+ System.getProperty("sun.boot.class.path"));
+ return SyntheticRepository.getInstance(cp);
+ }
+
+ protected Attribute[] findAttribute(String name, JavaClass clazz) {
+ Attribute[] all = clazz.getAttributes();
+ List chosenAttrsList = new ArrayList();
+ for (int i = 0; i < all.length; i++) {
+ if (verbose) System.err.println("Attribute: "+all[i].getName());
+ if (all[i].getName().equals(name)) chosenAttrsList.add(all[i]);
+ }
+ return (Attribute[])chosenAttrsList.toArray(new Attribute[]{});
+ }
+
+ protected Attribute findAttribute(String name, Attribute[] all) {
+ List chosenAttrsList = new ArrayList();
+ for (int i = 0; i < all.length; i++) {
+ if (verbose) System.err.println("Attribute: "+all[i].getName());
+ if (all[i].getName().equals(name)) chosenAttrsList.add(all[i]);
+ }
+ assertTrue("Should be one match: "+chosenAttrsList.size(),chosenAttrsList.size()==1);
+ return (Attribute)chosenAttrsList.get(0);
+ }
+
+ protected String dumpAnnotations(Annotation[] as) {
+ StringBuffer result = new StringBuffer();
+ result.append("[");
+ for (int i = 0; i < as.length; i++) {
+ Annotation annotation = as[i];
+ result.append(annotation.toShortString());
+ if (i+1<as.length) result.append(",");
+ }
+ result.append("]");
+ return result.toString();
+ }
+
+ protected String dumpAnnotations(AnnotationGen[] as) {
+ StringBuffer result = new StringBuffer();
+ result.append("[");
+ for (int i = 0; i < as.length; i++) {
+ AnnotationGen annotation = as[i];
+ result.append(annotation.toShortString());
+ if (i+1<as.length) result.append(",");
+ }
+ result.append("]");
+ return result.toString();
+ }
+
+ protected String dumpAttributes(Attribute[] as) {
+ StringBuffer result = new StringBuffer();
+ result.append("AttributeArray:[");
+ for (int i = 0; i < as.length; i++) {
+ Attribute attr = as[i];
+ result.append(attr.toString());
+ if (i+1<as.length) result.append(",");
+ }
+ result.append("]");
+ return result.toString();
+ }
+
+ public AnnotationGen createFruitAnnotation(ConstantPoolGen cp, String aFruit, boolean visibility) {
+ SimpleElementValueGen evg = new SimpleElementValueGen(ElementValueGen.STRING,cp,aFruit);
+ ElementNameValuePairGen nvGen = new ElementNameValuePairGen("fruit",evg,cp);
+ ObjectType t = new ObjectType("SimpleStringAnnotation");
+ List elements = new ArrayList();
+ elements.add(nvGen);
+ return new AnnotationGen(t,elements,visibility,cp);
+ }
+
+
+
+}
diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/preverifier/PreverifierTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/preverifier/PreverifierTest.java
new file mode 100644
index 000000000..730d3a8a9
--- /dev/null
+++ b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/preverifier/PreverifierTest.java
@@ -0,0 +1,771 @@
+/* *******************************************************************
+ * Copyright (c) 2006 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Andy Clement - IBM - 3rd April 2006 - initial implementation
+ * ******************************************************************/
+
+package org.aspectj.apache.bcel.classfile.tests.preverifier;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.aspectj.apache.bcel.Repository;
+import org.aspectj.apache.bcel.classfile.Attribute;
+import org.aspectj.apache.bcel.classfile.ClassFormatException;
+import org.aspectj.apache.bcel.classfile.ClassParser;
+import org.aspectj.apache.bcel.classfile.JavaClass;
+import org.aspectj.apache.bcel.classfile.Method;
+import org.aspectj.apache.bcel.classfile.StackMapFrame;
+import org.aspectj.apache.bcel.classfile.StackMapTable;
+import org.aspectj.apache.bcel.generic.ClassGen;
+import org.aspectj.apache.bcel.generic.ConstantPoolGen;
+import org.aspectj.apache.bcel.generic.MethodGen;
+import org.aspectj.apache.bcel.generic.Type;
+import org.aspectj.apache.bcel.util.ClassPath;
+import org.aspectj.apache.bcel.util.SyntheticRepository;
+import org.aspectj.apache.bcel.verifier.utility.Frame;
+import org.aspectj.apache.bcel.verifier.utility.LocalVariables;
+import org.aspectj.apache.bcel.verifier.utility.OperandStack;
+import org.aspectj.apache.bcel.verifier.utility.StackMapHelper;
+
+
+/**
+ * gotchas
+ * - stack at an exception entry point - is it the stack from the try{} with the exception on?
+ * - what is Top?
+ * - sometimes if we haven't merged 'routes' at the start of a chain, we may commence the chain without quite
+ * the right set of types?!? do we re-stack (the start of it) and pick another and come back later?
+ * - is the frame for a 'try' the frame before or after the instruction? (i.e. the one we hack for the exception handler) - ANSWER: its the 'before' but we may need to include lvar types 'learned' during the block in the catch block frame
+ */
+
+public class PreverifierTest extends PreverifierBaseTestCase {
+
+ private boolean debug = true;
+// /** Check StackMapTable can be retrieved and is the right length */
+// public void testLookingAtTheStackMap() throws ClassNotFoundException {
+// StackMapTable stackmap = fetchStackMapTable("org.aspectj.apache.bcel.classfile.Utility","codeToString");
+// assertTrue("Should be 8 entries in the stack map but found: "+stackmap.getMapLength(),stackmap.getMapLength()==8);
+// }
+//
+//
+//
+// /** Are the frames correct */
+// public void testTheFrames() throws ClassNotFoundException {
+// StackMapTable stackmap = fetchStackMapTable("org.aspectj.apache.bcel.classfile.Utility","codeToString");
+// StackMapFrame[] frames = stackmap.getStackMap();
+// String[] expectedKinds = new String[]{
+// "AppendFrame","SameFrame","SameFrame","SameFrame","SameFrameExtended",
+// "SameFrame","FullFrame","SameFrame"
+// };
+// for (int i = 0; i < frames.length; i++) {
+// StackMapFrame frame = frames[i];
+// //System.out.println("f"+i+" is "+frame);
+// assertTrue("Frame at position "+i+" should be "+expectedKinds[i]+" but is "+frame.getKindString(),frame.getKindString().equals(expectedKinds[i]));
+// }
+// }
+//
+//
+//
+// /** Reconstructing complete frames - applying the frames to the initial */
+// public void testFrameReconstruction() throws ClassNotFoundException {
+// MethodGen method = fetchMethod("org.aspectj.apache.bcel.classfile.Utility","codeToString");
+// StackMapTable table = fetchStackMapTable(method);
+// StackMapFrame[] frames = table.getStackMap();
+// Frame[] fullFrames = StackMapper.reconstructFrames(method,table);
+// int offset = 0;
+// for (int f = 0; f < fullFrames.length; f++) {
+// StackMapFrame frame = frames[f];
+// if (f==0) offset=frame.getByteCodeOffset();
+// else offset+=1+frame.getByteCodeOffset();
+// System.out.println("Current frame (offset="+offset+") now "+fullFrames[f]);
+// }
+// }
+//
+//
+//
+// /** Creates a set of frames and also retrieves them from a method - compares them */
+// public void testFrameComparison() throws ClassNotFoundException {
+// JavaClass clazz = getClassFromJar("org.aspectj.apache.bcel.classfile.Utility");
+// Method m = getMethod(clazz,"codeToString");
+// MethodGen method = new MethodGen(m,clazz.getClassName(),new ConstantPoolGen(clazz.getConstantPool()));
+//
+// // We are comparing the full frames here, *not* the StackMapFrames
+//
+// // First retrieve them from the method attribute
+// StackMapTable table = fetchStackMapTable(method);
+// StackMapFrame[] frames = table.getStackMap();
+// Frame[] fullFramesRead = StackMapper.reconstructFrames(method,table);
+//
+// // Now calculate them
+// long stime = System.currentTimeMillis();
+// Frame[] fullFramesCalculated = new StackMapper(clazz).createStackMapTableAttribute(method);
+//
+// // tada !!! compare the bloody things
+// assertTrue("Expected same number of frames in each case? read="+fullFramesRead.length+" calc="+fullFramesCalculated.length,
+// fullFramesRead.length==fullFramesCalculated.length);
+//
+// int pos = 0;
+// for (int i = 0; i < fullFramesCalculated.length; i++) {
+// if (i==0) pos=frames[i].getByteCodeOffset();
+// else pos+=frames[i].getByteCodeOffset()+1;
+// assertTrue("Offset "+pos+" frames should be equal? ["+i+"] "+differences(fullFramesRead[i],fullFramesCalculated[i])+
+// "\n READ="+fullFramesRead[i]+"\n CALC="+fullFramesCalculated[i],
+// equivalent(fullFramesRead[i],fullFramesCalculated[i]));
+// }
+// }
+//
+// private boolean debug = true;
+// /**
+// * Creates a set of frames and also retrieves them from a method - compares them.
+// * From the 'test a load of stuff' tests, individual problematic methods are promoted to having their own testcase
+// *
+// * Fun facts:
+// * ChopFrame occurs in this one!
+// */
+// public void testFrameComparison2() throws ClassNotFoundException {
+// JavaClass clazz = getClassFromJar("org.aspectj.apache.bcel.classfile.Utility");
+// Method m = getMethod(clazz,"methodTypeToSignature");
+// MethodGen method = new MethodGen(m,clazz.getClassName(),new ConstantPoolGen(clazz.getConstantPool()));
+//
+// // We are comparing the full frames here, *not* the StackMapFrames
+//
+// // First retrieve them from the method attribute
+// StackMapTable table = fetchStackMapTable(method);
+// StackMapFrame[] frames = table.getStackMap();
+// Frame[] fullFramesRead = StackMapper.reconstructFrames(method,table);
+// if (debug) {
+// System.err.println("READ FRAMES - START");
+// for (int i = 0; i < fullFramesRead.length; i++) {
+// Frame frame = fullFramesRead[i];
+// System.err.println(fullFramesRead[i]);
+// }
+// System.err.println("READ FRAMES - END");
+// }
+// // Now calculate them
+// long stime = System.currentTimeMillis();
+// Frame[] fullFramesCalculated = new StackMapper(clazz).createStackMapTableAttribute(method);
+// if (debug) {
+// System.err.println("CALC FRAMES - START");
+// for (int i = 0; i < fullFramesCalculated.length; i++) {
+// Frame frame = fullFramesCalculated[i];
+// System.err.println(fullFramesCalculated[i]);
+// }
+// System.err.println("CALC FRAMES - END");
+// }
+//
+// // tada !!! compare the bloody things
+// assertTrue("Expected same number of frames in each case? read="+fullFramesRead.length+" calc="+fullFramesCalculated.length,
+// fullFramesRead.length==fullFramesCalculated.length);
+//
+// int pos = 0;
+// for (int i = 0; i < fullFramesCalculated.length; i++) {
+// if (i==0) pos=frames[i].getByteCodeOffset();
+// else pos+=frames[i].getByteCodeOffset()+1;
+// assertTrue("Offset "+pos+" frames should be equal? ["+i+"] "+differences(fullFramesRead[i],fullFramesCalculated[i])+
+// "\n READ="+fullFramesRead[i]+"\n CALC="+fullFramesCalculated[i],
+// equivalent(fullFramesRead[i],fullFramesCalculated[i]));
+// }
+// }
+
+ private int[] toOffsets(StackMapFrame[] smfs) {
+ int[] offsets = new int[smfs.length+1];
+ int idx=0;
+ offsets[idx++]=0;
+ for (int i = 0; i < smfs.length; i++) {
+ offsets[idx]=offsets[idx-1]+smfs[i].getByteCodeOffset()+(i>0?1:0);
+ idx++;
+ }
+ return offsets;
+ }
+
+
+ public void testSimpleFrameComparison() throws ClassNotFoundException, ClassFormatException, IOException {
+ String cname = "Code";
+ String mname = "method1";
+
+ JavaClass clazz = getClassFromJar(cname);
+ Method interestingMethod = getMethod(clazz,mname,0);
+ System.out.println(interestingMethod);
+
+ MethodGen method = new MethodGen(interestingMethod,clazz.getClassName(),new ConstantPoolGen(clazz.getConstantPool()));
+
+ // We are comparing the full frames here, *not* the StackMapFrames
+
+ // First retrieve them from the method attribute - this is what the COMPILER generated
+ StackMapTable table = fetchStackMapTable(method);
+ StackMapFrame[] frames = table.getStackMap();
+ int[] offsets = toOffsets(frames);
+ Frame[] compilerFrames = StackMapHelper.reconstructFrames(method,table);
+ if (debug) printFrames("Javac",compilerFrames,offsets);
+ if (true) return;
+
+ // Now calculate them
+ long stime = System.currentTimeMillis();
+ // Frame[] fullFramesCalculated = new StackMapper(clazz).createStackMapTableAttribute(method);
+// Frame[] calculatedFrames = new StackMapper(clazz).produceStackMapTableAttribute(clazz, method);
+// if (debug) printFrames("Calculated",calculatedFrames,offsets);
+
+// compareFrames("Compiler and Bcel frames",compilerFrames,calculatedFrames,frames);
+ }
+ public void testComplexFrameComparison() throws ClassNotFoundException, ClassFormatException, IOException {
+ String cname = "org.aspectj.apache.bcel.classfile.Utility";
+ String mname = "methodSignatureToString";
+ int count = 2;
+
+ JavaClass clazz = getClassFromJar(cname);
+ ClassGen cg = new ClassGen(clazz);
+ Method interestingMethod = getMethod(cg,mname,2);
+ System.out.println(interestingMethod);
+
+ MethodGen method = new MethodGen(interestingMethod,clazz.getClassName(),new ConstantPoolGen(clazz.getConstantPool()));
+ method.calculateStackMapTable();
+ cg.replaceMethod(interestingMethod, method.getMethod());
+
+ // method.calculateStackMapTable();
+ String path = "c:/temp/"+clazz.getPackageName().replaceAll("\\.","/");
+ String name = clazz.getClassName();
+ if (name.indexOf(".")!=-1) {
+ name = name.substring(name.lastIndexOf(".")+1);
+ }
+ String file = path+"/"+name+".class";
+ System.err.println(file);
+ new File(path).mkdirs();
+ cg.getJavaClass().dump(new FileOutputStream(file));
+ URLClassLoader cl = new URLClassLoader(new URL[]{new File("c:/temp").toURL(),new File("c:/testcode.jar").toURL()},null);//this.getClass().getClassLoader());
+ System.err.println(cl.getURLs()[0]);
+ System.err.println("loading "+clazz.getClassName());
+ Class c = Class.forName(clazz.getClassName(),true,cl);
+//
+// // First retrieve them from the method attribute - this is what the COMPILER generated
+// StackMapTable table = fetchStackMapTable(method);
+// StackMapFrame[] frames = table.getStackMap();
+// int[] offsets = toOffsets(frames);
+// Frame[] compilerFrames = StackMapper.reconstructFrames(method,table);
+// if (debug) printFrames("Javac",compilerFrames,offsets);
+//
+// // Now calculate them
+// long stime = System.currentTimeMillis();
+// Frame[] fullFramesCalculated = new StackMapper(clazz).createStackMapTableAttribute(method);
+// Frame[] calculatedFrames = new StackMapper(clazz).produceStackMapTableAttribute(clazz, method);
+//// if (debug) printFrames("Calculated",calculatedFrames,offsets);
+////
+//// compareFrames("Compiler and Bcel frames",compilerFrames,calculatedFrames,frames);
+////
+//// // let's try serializing the new version of the method with this on...
+//// method.addStackMap(calculatedFrames);
+
+ }
+
+
+ public void testProblemClassOne() throws ClassNotFoundException, ClassFormatException, IOException {
+ // Uncovered two problems surfaced:
+ // - Bcel not understanding LDC changes to support Class Constants in the ExecutionVisitor
+ // - Bcel 'optimizing' wide instructions that don't use double byte indices - the stackmap is left unchanged and so incorrect
+ checkOneClass("org.aspectj.apache.bcel.generic.InstructionHandle",true,3);
+ }
+
+ public void testProblemClassTwo() throws ClassNotFoundException, ClassFormatException, IOException {
+ // simple problem revealed in test system with not avoiding abstract methods
+ checkOneClass("org.aspectj.apache.bcel.classfile.annotation.ElementValue",true,3);
+ }
+
+ public void testProblemClassThree() throws ClassNotFoundException, ClassFormatException, IOException {
+ // problem in deserializing a stackmaptable - incorrectly used the localcount when creating the stack array !
+ // problem with uninitialized - where the index should be the index of the related 'new' instruction
+ // - enhanced execution visitor to remember where it is
+ // problem with methods that have no stackmap (readVersion in this class)
+ // lots of problems where 'unknown' was being used when it should have been 'top'
+ checkOneClass("org.aspectj.apache.bcel.classfile.ClassParser",true,3);
+ }
+
+ public void testEveryMethodInAClass() throws ClassNotFoundException, ClassFormatException, IOException {
+ checkOneClass("org.aspectj.apache.bcel.classfile.Utility",false);
+ }
+
+ public void testProblemClassFour() throws ClassNotFoundException, ClassFormatException, IOException {
+ // Problem with incorrect handling of Type.NULL - it is a special ObjectType constant
+ checkOneClass("org.aspectj.apache.bcel.classfile.GenericSignatureParser",true);
+ }
+
+ public void testProblemClassFive() throws ClassNotFoundException, ClassFormatException, IOException {
+ // outofmemory on the clinit... it is 8870 bytes long
+ // ended up fixing the exceptionhandler creation logic - so it doesnt build a list for every instruction
+ // of the exceptions that might occur, just for those instructions that actually throw exceptions!
+ long timer = System.currentTimeMillis();
+ checkOneClass("org.aspectj.apache.bcel.Constants",true);
+ System.out.println("took "+(System.currentTimeMillis()-timer)+"ms");
+ // 3926/2684ms! 7/12/06
+ }
+
+ public void testProblemClassSix() throws ClassNotFoundException, ClassFormatException, IOException {
+ // Problem here was that after optimizing the exception code so that it didn't persue so many execution
+ // chains, i forgot that astores alter the local variable table for the catch block - and in this
+ // case, if I forgot that the catch block thought LV1 was <null> when in fact it was Object
+ // fix is to be a little less aggressive - and recognize ASTOREs need to be followed through the
+ // catch block
+ checkOneClass("org.aspectj.apache.bcel.classfile.Attribute",true,14); // clone method
+ }
+
+ public void testProblemClassSeven() throws ClassNotFoundException, ClassFormatException, IOException {
+ // Now we had a problem with double slot values (long/double) - they are internally represented but when
+ // the frame is dumped the duplicate TOPs are removed.
+ // Changes were to StackMapHelper.createInitialFrame() and StackMapFrame.dump() and Frame.getLocalsAsStackMapTypes()
+ checkOneClass("org.aspectj.apache.bcel.generic.ConstantPoolGen",true,17);
+ }
+
+ public void testProblemClassEight() throws ClassNotFoundException, ClassFormatException, IOException {
+ // java.lang.VerifyError: Instruction type does not match stack map in method org.aspectj.apache.bcel.verifier.utility.StackMapper.chaseChains()V at offset 0
+ // interesting! The method code ends with a 'goto 0' causing us to jump back to the start - because I didn't store the initialframe for the
+ // method, we didn't do a merge after the jump back to 0, we just used what the contents were. A merge would have told us we knew much
+ // less than we thought. The fix was to store the initial frame as we start
+ checkOneClass("org.aspectj.apache.bcel.verifier.utility.StackMapper",true,11);
+ }
+
+ // rt.jar classes
+ public void testProblemClass9() throws ClassNotFoundException, ClassFormatException, IOException {
+ // Revealed that the OperandStack wasn't correctly working for double slot entries like LONG
+ checkOneClass("com.sun.corba.se.impl.corba.AnyImpl",true,34);
+ }
+
+ public void testProblemClass10() throws ClassNotFoundException, ClassFormatException, IOException {
+ // method 2 - internalGetServant has jsrs, yey!
+ checkOneClass("com.sun.corba.se.impl.oa.poa.POAPolicyMediatorImpl_R_USM",true,2);
+ }
+
+ public void testProblemClass11() throws ClassNotFoundException, ClassFormatException, IOException {
+ checkOneClass("com.sun.corba.se.impl.corba.AnyImplHelper",false);
+ }
+
+
+ public void testJar() throws ClassNotFoundException, ClassFormatException, IOException {
+ StackMapHelper.count=0;
+ verifyJar("testdata/Java6BuiltCode.jar");
+ System.out.println("Stored: "+StackMapHelper.count+" frames");
+ }
+
+ public void testJar2() throws ClassNotFoundException, ClassFormatException, IOException {
+ verifyJar("C:/Program Files/Java/jdk1.6.0/jre/lib/rt.jar");
+ }
+
+ public void verifyJar(String where) throws ClassNotFoundException, ClassFormatException, IOException {
+ long timer = System.currentTimeMillis();
+ ZipFile zf = new ZipFile(where);
+ Enumeration e = zf.entries();
+ int count=0,verified=0;
+ while (e.hasMoreElements()) {
+ ZipEntry zfe = (ZipEntry)e.nextElement();
+ if (zfe.getName().endsWith(".class")) {
+ String n = zfe.getName();
+ if (debug) System.out.println("Processing class #"+count+": "+n);
+ n = n.substring(0,n.indexOf(".class"));
+ if (n.indexOf("OperatingSystem")==-1 && n.indexOf("JdbcOdbc")==-1) {
+ boolean b = checkOneClass(n.replaceAll("/","."),false);
+ count++;
+ if (b) verified++;
+ }
+ }
+ }
+ System.out.println("Tested entire jar, took "+(System.currentTimeMillis()-timer)+"ms for "+count+" classes (verified: "+verified+")");
+ }
+
+
+ public File getTempDir() {
+ String s = "c:/temp";//System.getProperty("java.io.tmpdir");
+ File f = new File(s+File.separator+"verifier");
+ f.mkdir();
+ return f;
+ }
+
+ public boolean checkOneClass(String cname,boolean verifyAsYouGoAlong) throws ClassNotFoundException, ClassFormatException, IOException {
+ return checkOneClass(cname,verifyAsYouGoAlong,0);
+ }
+
+// public static void main(String []argv) throws ClassNotFoundException, FileNotFoundException, IOException {
+// // remove one
+// ClassPath cp = new ClassPath(
+// "c:/igor/fails/"+File.pathSeparator+
+// System.getProperty("sun.boot.class.path"));
+// SyntheticRepository repos = SyntheticRepository.getInstance(cp);
+// Repository.setRepository(repos);
+// JavaClass clazz = repos.loadClass("com.ibm.tivoli.itcam.toolkit.ai.aspectj.captureJDBC.CaptureDataSource");
+// ClassGen cg = new ClassGen(clazz);
+// Attributes[] as = cg.getAttributes();
+// for (int i = 0; i < as.length; i++) {
+//
+// }
+// File f = new File("c:/igor/CaptureDataSource.class");
+// cg.getJavaClass().dump(new FileOutputStream(f));
+//
+// }
+
+ public boolean checkOneClass(String cname,boolean verifyAsYouGoAlong,int startMethod) throws ClassNotFoundException, ClassFormatException, IOException {
+ if (debug) System.out.println("? PreverifierTest.testClass(): testing class '"+cname+"'");
+ long timer = System.currentTimeMillis();
+ JavaClass clazz = getClassFromJar(cname);
+ ClassGen cg = new ClassGen(clazz);
+ cg.setMajor(50); // upgrade it so it gets verified!
+// if (cg.getMajor()<50) {
+// System.out.println("? skipping this class, it is major version "+cg.getMajor());
+// return false;
+// }
+
+ File tempDir = getTempDir();
+ String destination = clazz.getPackageName().replaceAll("\\.","/");
+ String name = clazz.getClassName();
+ if (name.indexOf(".")!=-1) name = name.substring(name.lastIndexOf(".")+1);
+ File outputDir = new File(tempDir,destination);
+ outputDir.mkdirs();
+ File file = new File (outputDir,name+".class");
+ if (debug) System.out.println("? New file will be dumped to "+file);
+ Method[] methods = cg.getMethods();
+ for (int i = startMethod; i <methods.length; i++) {
+ Method originalMethod = methods[i];
+ if (originalMethod.isAbstract()) {
+ if (debug) System.out.println("? skipping abstract method "+i+"/"+methods.length);
+ } else {
+ if (debug) System.out.println("? processing method "+i+"/"+methods.length+": "+originalMethod.getName());
+ ConstantPoolGen cpg = cg.getConstantPool();
+ MethodGen newMethod = new MethodGen(originalMethod,clazz.getClassName(),cpg);
+ newMethod.calculateStackMapTable();
+ cg.replaceMethod(originalMethod, newMethod.getMethod());
+
+ if (verifyAsYouGoAlong) {
+ cg.getJavaClass().dump(new FileOutputStream(file));
+ URLClassLoader cl = new URLClassLoader(new URL[]{tempDir.toURL(),new File("c:/testcode.jar").toURL()},null);//this.getClass().getClassLoader());
+ Class c = Class.forName(clazz.getClassName(),true,cl);
+ }
+ }
+
+ }
+ if (!verifyAsYouGoAlong) { // Just do this once at the end
+ cg.getJavaClass().dump(new FileOutputStream(file));
+ URLClassLoader cl = new URLClassLoader(new URL[]{tempDir.toURL(),new File("c:/testcode.jar").toURL()},null);//this.getClass().getClassLoader());
+ Class c = Class.forName(clazz.getClassName(),true,cl);
+ }
+ if (debug) System.out.println("Time taken testing "+cname+": "+(System.currentTimeMillis()-timer)+"ms");
+ return true;
+ }
+
+
+
+ private void printFrames(String id,Frame[] fs,int[] offsets) {
+ System.err.println(id+": start ("+fs.length+" frames)");
+ for (int i = 0; i < fs.length; i++) System.err.println(fs[i].toString(i+"(o"+offsets[i]+")"));
+ System.err.println(id+": end");
+ }
+
+ /** Compare two sets of frames - the final parameter is just used for offset reporting*/
+ public void compareFrames(String description, Frame[] compilerFrames,Frame[] calculatedFrames,StackMapFrame[] frames) {
+ System.out.println(description);
+ assertTrue("Expected same number of frames in each case? read="+compilerFrames.length+" calc="+calculatedFrames.length,
+ compilerFrames.length==calculatedFrames.length);
+
+ int pos = 0;
+ for (int i = 0; i < calculatedFrames.length; i++) {
+ System.out.println("Comparing frames at offset "+pos);
+ assertTrue("Offset "+pos+" frames should be equal? ["+i+"] "+differences(compilerFrames[i],calculatedFrames[i])+
+ "\n READ="+compilerFrames[i]+"\n CALC="+calculatedFrames[i],equivalent(compilerFrames[i],calculatedFrames[i]));
+ if (i<calculatedFrames.length-1) pos+=frames[i].getByteCodeOffset()+(i>0?1:0);
+ }
+ System.out.println("comparison successful");
+ }
+
+
+
+ /**
+ * Creates a set of frames and also retrieves them from a method - compares them.
+ *
+ * Victim: org.aspectj.apache.bcel.classfile.Utility.methodSignatureToString() (the 2nd one)
+ */
+// public void testFrameComparison() throws ClassNotFoundException, ClassFormatException, IOException {
+// JavaClass clazz = getClassFromJar("org.aspectj.apache.bcel.classfile.Utility");
+// Method interestingMethod = getMethod(clazz,"methodSignatureToString",2);
+// System.out.println(interestingMethod);
+//
+// MethodGen method = new MethodGen(interestingMethod,clazz.getClassName(),new ConstantPoolGen(clazz.getConstantPool()));
+//
+// // We are comparing the full frames here, *not* the StackMapFrames
+//
+//
+// // First retrieve them from the method attribute - this is what the COMPILER generated
+// StackMapTable table = fetchStackMapTable(method);
+// StackMapFrame[] frames = table.getStackMap();
+// Frame[] fullFrames = StackMapper.reconstructFrames(method,table);
+// if (debug) {
+// System.out.println("Javac: start ("+fullFrames.length+" frames)");
+// for (int i = 0; i < fullFrames.length; i++) System.out.println(fullFrames[i].toString(i+") "));
+// System.out.println("Javac: end");
+// }
+//
+//
+//
+//
+//
+// // Now calculate them
+// long stime = System.currentTimeMillis();
+// // Frame[] fullFramesCalculated = new StackMapper(clazz).createStackMapTableAttribute(method);
+// Frame[] fullFramesCalculated = new StackMapper(clazz).produceStackMapTableAttribute(clazz, method);//(method);
+// if (debug) {
+// System.out.println("Calculated: start ("+fullFramesCalculated.length+" frames)");
+// for (int i = 0; i < fullFramesCalculated.length; i++)
+// System.out.println(fullFramesCalculated[i]);
+// System.out.println("Calculated: end");
+// }
+//
+// // tada !!! compare the bloody things
+//// assertTrue("Expected same number of frames in each case? read="+fullFramesRead.length+" calc="+fullFramesCalculated.length,
+//// fullFramesRead.length==fullFramesCalculated.length);
+//
+// int pos = 0;
+// for (int i = 0; i < fullFramesCalculated.length; i++) {
+// if (i==0) pos=frames[i].getByteCodeOffset();
+// else pos+=frames[i].getByteCodeOffset()+1;
+// assertTrue("Offset "+pos+" frames should be equal? ["+i+"] "+differences(fullFrames[i],fullFramesCalculated[i])+
+// "\n READ="+fullFrames[i]+"\n CALC="+fullFramesCalculated[i],
+// equivalent(fullFrames[i],fullFramesCalculated[i]));
+// }
+// }
+
+
+// public void testTheChuffinLot() throws ClassNotFoundException {
+// // Load a whole class and test all its frames for every method.
+// int compared=0;
+// JavaClass clazz = getClassFromJar("org.aspectj.apache.bcel.classfile.Utility");
+// ClassGen cg = new ClassGen(clazz);
+// Method[] ms = cg.getMethods();
+// System.err.println("Class "+clazz.getClassName()+" has "+ms.length+" methods to compare");
+// for (int i = 0; i < ms.length; i++) {
+// Method m = ms[i];
+// MethodGen method = new MethodGen(m,clazz.getClassName(),cg.getConstantPool());
+// if (!hasStackMapTableAttribute(method)) {System.err.println("No StackMapAttribute for "+method.getName());continue;}
+// System.err.println("====================================================");
+// System.err.println("Method "+i+" is '"+m+"': commencing frame comparison");
+// // First retrieve them from the method attribute
+// StackMapTable table = fetchStackMapTable(method);
+// StackMapFrame[] frames = table.getStackMap();
+// Frame[] fullFramesRead = StackMapper.reconstructFrames(method,table);
+//
+// // Now calculate them
+// long stime = System.currentTimeMillis();
+// Frame[] fullFramesCalculated = new StackMapper(clazz).createStackMapTableAttribute(method);
+//
+// // tada !!! compare the bloody things
+// assertTrue("Expected same number of frames in each case? read="+fullFramesRead.length+" calc="+fullFramesCalculated.length,
+// fullFramesRead.length==fullFramesCalculated.length);
+//
+// int pos = 0;
+// for (int ii = 0; ii < fullFramesCalculated.length; ii++) {
+// if (ii==0) pos=frames[ii].getByteCodeOffset();
+// else pos+=frames[ii].getByteCodeOffset()+1;
+// assertTrue("Offset "+pos+" frames should be equal? ["+ii+"] "+differences(fullFramesRead[ii],fullFramesCalculated[ii])+
+// "\n READ="+fullFramesRead[ii]+"\n CALC="+fullFramesCalculated[ii],
+// equivalent(fullFramesRead[ii],fullFramesCalculated[ii]));
+// }
+// compared++;
+// }
+// System.err.println("Successfully compared attributes for "+compared+" methods");
+// }
+
+// ZipFile zf = new ZipFile(f);
+// int i = 0;
+// long stime = System.currentTimeMillis();
+// Enumeration entries = zf.entries();
+// while (entries.hasMoreElements()) {
+// ZipEntry zfe = (ZipEntry) entries.nextElement();
+// String classfileName = zfe.getName();
+// if (classfileName.endsWith(".class")) {
+// String clazzname = classfileName.substring(0,
+// classfileName.length() - 6).replace('/', '.');
+// ReferenceType b = (ReferenceType) slowWorld
+// .resolve(clazzname);
+// i++;
+// }
+// }
+
+
+// public void testDumbVerifier() throws ClassNotFoundException {
+// MethodGen method = fetchMethod("org.aspectj.apache.bcel.classfile.Utility","codeToString");
+//
+// JavaClass clazz = getClassFromJar("org.aspectj.apache.bcel.classfile.Utility");
+// Method m = getMethod(clazz,"codeToString");
+// Attribute a = findAttribute("Code", m.getAttributes());
+// assertTrue("Should be of type 'Code' but is "+a.getClass(),a instanceof Code);
+// Code c = (Code)a;
+// Attribute[] codeAttributes = c.getAttributes();
+// StackMapTable stackmap = (StackMapTable)findAttribute("StackMapTable", c.getAttributes());
+// assertTrue("Should be 8 entries in the stack map but found: "+stackmap.getMapLength(),stackmap.getMapLength()==8);
+// try {
+// MethodGen mg = new MethodGen(m,clazz.getClassName(),new ConstantPoolGen(clazz.getConstantPool()));
+// long stime = System.currentTimeMillis();
+// new StackMapper().createStackMapTableAttribute(mg);
+// System.err.println("Took "+(System.currentTimeMillis()-stime)+"ms");
+// } catch (Exception e) {e.printStackTrace();}
+// }
+
+ /**
+ * Retrieves a stack map then asks for verification of the method in the class which spits out
+ * stackmapframes we can compare against...
+ * this checks:
+ * - the verifier works
+ * - the stackmap loading is correct
+ * - the process for having our own cut down verifier
+ */
+
+//
+//
+//
+// public void testVerifyTheMap() throws ClassNotFoundException {
+//// JavaClass clazz = getClassFromJar("org.aspectj.apache.bcel.classfile.Utility");
+//// Method m = getMethod(clazz,"codeToString");
+// JavaClass clazz = getClassFromJar("org.aspectj.apache.bcel.classfile.Utility");
+// Method m = getMethod(clazz,"methodSignatureToString",2);
+// Attribute a = findAttribute("Code", m.getAttributes());
+// assertTrue("Should be of type 'Code' but is "+a.getClass(),a instanceof Code);
+// Code c = (Code)a;
+// Attribute[] codeAttributes = c.getAttributes();
+// StackMapTable stackmap = (StackMapTable)findAttribute("StackMapTable", c.getAttributes());
+//// assertTrue("Should be 8 entries in the stack map but found: "+stackmap.getMapLength(),stackmap.getMapLength()==8);
+// try {
+// MethodGen mg = new MethodGen(m,clazz.getClassName(),new ConstantPoolGen(clazz.getConstantPool()));
+// long stime = System.currentTimeMillis();
+// Frame[] o = new StackMapper(clazz).produceStackMapTableAttribute(clazz,mg);
+// System.err.println("Took "+(System.currentTimeMillis()-stime)+"ms");
+// } catch (Exception e) {e.printStackTrace();}
+// }
+//
+//
+//
+// /** Let's test the creation of subroutines for a method */
+// public void testSubroutines() throws ClassNotFoundException {
+// JavaClass clazz = getClassFromJar("org.aspectj.apache.bcel.classfile.Utility");
+// Method m = getMethod(clazz,"methodSignatureToString",2);
+// MethodGen mg = new MethodGen(m,clazz.getClassName(),new ConstantPoolGen(clazz.getConstantPool()));
+// long stime = System.currentTimeMillis();
+// Subroutines subs = new Subroutines(mg);
+// System.err.println("Took "+(System.currentTimeMillis()-stime)+"ms");
+// Collection c = subs.getIndividualSubroutines();
+// System.err.println("End of analysis: "+c.size()+" subroutines");
+// for (Iterator iter = c.iterator(); iter.hasNext();) {
+// Subroutine element = (Subroutine) iter.next();
+// System.err.println(element);
+// }
+// }
+//
+//
+
+ // ---
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ // ---
+// private StackMapTable fetchStackMapTable(String classname,String methodname) throws ClassNotFoundException {
+// JavaClass clazz = getClassFromJar(classname);
+// Method m = getMethod(clazz,methodname);
+// Attribute a = findAttribute("Code", m.getAttributes());
+// Code c = (Code)a;
+// Attribute[] codeAttributes = c.getAttributes();
+// CodeException[] ces = c.getExceptionTable();
+// StackMapTable stackmap = (StackMapTable)findAttribute("StackMapTable", c.getAttributes());
+// return stackmap;
+// }
+//
+// private boolean hasStackMapTableAttribute(MethodGen method) {
+// Attribute[] all = method.getCodeAttributes();
+// for (int i = 0; i < all.length; i++) {
+// if (all[i].getName().equals("StackMapTable")) return true;
+// }
+// return false;
+// }
+
+ private StackMapTable fetchStackMapTable(MethodGen method) throws ClassNotFoundException {
+ Attribute[] codeAttributes = method.getCodeAttributes();
+ StackMapTable stackmap = (StackMapTable)findAttribute("StackMapTable", codeAttributes);
+ return stackmap;
+ }
+
+ private MethodGen fetchMethod(String classname,String methodname) throws ClassNotFoundException {
+ JavaClass clazz = getClassFromJar(classname);
+ Method m = getMethod(clazz,methodname);
+ MethodGen mg = new MethodGen(m,clazz.getClassName(),new ConstantPoolGen(clazz.getConstantPool()));
+ return mg;
+ }
+
+
+ /** For frames that aren't the same (equivalent()) this method will return why */
+ private String differences(Frame f1,Frame f2) {
+ LocalVariables f1Locals = f1.getLocals();
+ LocalVariables f2Locals = f2.getLocals();
+ OperandStack f1Stack = f1.getStack();
+ OperandStack f2Stack = f2.getStack();
+
+ if (f1Locals.maxLocals()!=f2Locals.maxLocals()) return "Different number of locals";
+ if (f1Stack.maxStack()!=f2Stack.maxStack()) return "Different max stack sizes";
+ if (f1Stack.size()!=f2Stack.size()) return "Difference 'current' stack depths";
+
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < f1Locals.maxLocals(); i++) {
+ Type f1Type = f1Locals.get(i);
+ Type f2Type = f2Locals.get(i);
+ if (!f1Type.equals(f2Type)) return "Different types at local variable position "+i+" "+f1Type+"!="+f2Type;
+ }
+ for (int i = 0; i < f1Stack.size(); i++) {
+ Type f1Type = f1Stack.peek(i);
+ Type f2Type = f2Stack.peek(i);
+ if (!f1Type.equals(f2Type)) return "Different types at stack depth "+i+" "+f1Type+"!="+f2Type;
+ }
+ return "";
+ }
+
+ /** Are two frames the same? */
+ private boolean equivalent(Frame f1,Frame f2) {
+ LocalVariables f1Locals = f1.getLocals();
+ LocalVariables f2Locals = f2.getLocals();
+ OperandStack f1Stack = f1.getStack();
+ OperandStack f2Stack = f2.getStack();
+
+ if (f1Locals.maxLocals()!=f2Locals.maxLocals()) return false;
+ if (f1Stack.maxStack()!=f2Stack.maxStack()) return false;
+ if (f1Stack.size()!=f2Stack.size()) return false;
+
+ for (int i = 0; i < f1Locals.maxLocals(); i++) {
+ Type f1Type = f1Locals.get(i);
+ Type f2Type = f2Locals.get(i);
+ if (!f1Type.equals(f2Type)) return false;
+ }
+ for (int i = 0; i < f1Stack.size(); i++) {
+ Type f1Type = f1Stack.peek(i);
+ Type f2Type = f2Stack.peek(i);
+ if (!f1Type.equals(f2Type)) return false;
+ }
+ return true;
+ }
+
+ private void dump(Attribute[] mAttributes) {
+ for (int i = 0; i < mAttributes.length; i++) {
+ Attribute attribute = mAttributes[i];
+ System.err.println(attribute);
+ }
+ }
+
+}