Browse Source

verification prototype code

verification
aclement 17 years ago
parent
commit
291bb7dbcf
56 changed files with 8726 additions and 150 deletions
  1. 1
    1
      bcel-builder/.classpath
  2. 105
    0
      bcel-builder/.fbprefs
  3. 9
    8
      bcel-builder/.settings/org.eclipse.jdt.core.prefs
  4. BIN
      bcel-builder/foo.jar
  5. 15
    12
      bcel-builder/src/org/aspectj/apache/bcel/Constants.java
  6. 7
    8
      bcel-builder/src/org/aspectj/apache/bcel/classfile/Attribute.java
  7. 2
    2
      bcel-builder/src/org/aspectj/apache/bcel/classfile/ConstantNameAndType.java
  8. 5
    5
      bcel-builder/src/org/aspectj/apache/bcel/classfile/DescendingVisitor.java
  9. 3
    3
      bcel-builder/src/org/aspectj/apache/bcel/classfile/EmptyVisitor.java
  10. 3
    5
      bcel-builder/src/org/aspectj/apache/bcel/classfile/GenericSignatureParser.java
  11. 2
    3
      bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java
  12. 4
    5
      bcel-builder/src/org/aspectj/apache/bcel/classfile/Method.java
  13. 1
    2
      bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java
  14. 6
    5
      bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMap.java
  15. 2
    2
      bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapEntry.java
  16. 333
    0
      bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapFrame.java
  17. 282
    0
      bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapTable.java
  18. 9
    12
      bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapType.java
  19. 5
    6
      bcel-builder/src/org/aspectj/apache/bcel/classfile/Utility.java
  20. 3
    3
      bcel-builder/src/org/aspectj/apache/bcel/classfile/Visitor.java
  21. 2
    2
      bcel-builder/src/org/aspectj/apache/bcel/generic/ArrayType.java
  22. 4
    3
      bcel-builder/src/org/aspectj/apache/bcel/generic/ConstantPoolGen.java
  23. 2
    2
      bcel-builder/src/org/aspectj/apache/bcel/generic/EmptyVisitor.java
  24. 34
    1
      bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionHandle.java
  25. 2
    1
      bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionList.java
  26. 40
    1
      bcel-builder/src/org/aspectj/apache/bcel/generic/MethodGen.java
  27. 3
    1
      bcel-builder/src/org/aspectj/apache/bcel/generic/Type.java
  28. 22
    1
      bcel-builder/src/org/aspectj/apache/bcel/verifier/Verifier.java
  29. 2
    2
      bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/DOUBLE_Upper.java
  30. 2
    2
      bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/LONG_Upper.java
  31. 7
    5
      bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/StringRepresentation.java
  32. 3
    2
      bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ControlFlowGraph.java
  33. 3
    3
      bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ExecutionVisitor.java
  34. 8
    8
      bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/InstConstraintVisitor.java
  35. 5
    2
      bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/LocalVariables.java
  36. 23
    32
      bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/Pass3bVerifier.java
  37. 140
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ControlFlowGraph.java
  38. 93
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExceptionHandler.java
  39. 112
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExceptionHandlers.java
  40. 1143
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExecutionVisitor.java
  41. 375
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Frame.java
  42. 2667
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstConstraintVisitor.java
  43. 113
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContext.java
  44. 395
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContextImpl.java
  45. 34
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContextQueue.java
  46. 268
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/LocalVariables.java
  47. 300
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/OperandStack.java
  48. 225
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/StackMapHelper.java
  49. 127
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Subroutine.java
  50. 293
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/SubroutineImpl.java
  51. 395
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Subroutines.java
  52. 104
    0
      bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/UninitializedObjectType.java
  53. BIN
      bcel-builder/testdata/stackmap/Code.class
  54. 23
    0
      bcel-builder/testdata/stackmap/Code.java
  55. 189
    0
      bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/preverifier/PreverifierBaseTestCase.java
  56. 771
    0
      bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/preverifier/PreverifierTest.java

+ 1
- 1
bcel-builder/.classpath View File

@@ -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>

+ 105
- 0
bcel-builder/.fbprefs View File

@@ -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=|

+ 9
- 8
bcel-builder/.settings/org.eclipse.jdt.core.prefs View File

@@ -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

BIN
bcel-builder/foo.jar View File


+ 15
- 12
bcel-builder/src/org/aspectj/apache/bcel/Constants.java View File

@@ -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"
};
}

+ 7
- 8
bcel-builder/src/org/aspectj/apache/bcel/classfile/Attribute.java View File

@@ -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:

+ 2
- 2
bcel-builder/src/org/aspectj/apache/bcel/classfile/ConstantNameAndType.java View File

@@ -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());
}

/**

+ 5
- 5
bcel-builder/src/org/aspectj/apache/bcel/classfile/DescendingVisitor.java View File

@@ -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();

+ 3
- 3
bcel-builder/src/org/aspectj/apache/bcel/classfile/EmptyVisitor.java View File

@@ -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) {}

+ 3
- 5
bcel-builder/src/org/aspectj/apache/bcel/classfile/GenericSignatureParser.java View File

@@ -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() {

+ 2
- 3
bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java View File

@@ -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;
}

}

+ 4
- 5
bcel-builder/src/org/aspectj/apache/bcel/classfile/Method.java View File

@@ -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];

+ 1
- 2
bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java View File

@@ -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);
}

+ 6
- 5
bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMap.java View File

@@ -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; }

+ 2
- 2
bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapEntry.java View File

@@ -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);
}

/**

+ 333
- 0
bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapFrame.java View File

@@ -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;
}
}

+ 282
- 0
bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapTable.java View File

@@ -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();
}
}
}

+ 9
- 12
bcel-builder/src/org/aspectj/apache/bcel/classfile/StackMapType.java View File

@@ -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 "";

+ 5
- 6
bcel-builder/src/org/aspectj/apache/bcel/classfile/Utility.java View File

@@ -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;
}


+ 3
- 3
bcel-builder/src/org/aspectj/apache/bcel/classfile/Visitor.java View File

@@ -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);

+ 2
- 2
bcel-builder/src/org/aspectj/apache/bcel/generic/ArrayType.java View File

@@ -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);
}


+ 4
- 3
bcel-builder/src/org/aspectj/apache/bcel/generic/ConstantPoolGen.java View File

@@ -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));
}
}
}

+ 2
- 2
bcel-builder/src/org/aspectj/apache/bcel/generic/EmptyVisitor.java View File

@@ -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) { }

+ 34
- 1
bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionHandle.java View File

@@ -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

+ 2
- 1
bcel-builder/src/org/aspectj/apache/bcel/generic/InstructionList.java View File

@@ -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();
}

+ 40
- 1
bcel-builder/src/org/aspectj/apache/bcel/generic/MethodGen.java View File

@@ -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);
}
}

+ 3
- 1
bcel-builder/src/org/aspectj/apache/bcel/generic/Type.java View File

@@ -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;

+ 22
- 1
bcel-builder/src/org/aspectj/apache/bcel/verifier/Verifier.java View File

@@ -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);
}


/**

+ 2
- 2
bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/DOUBLE_Upper.java View File

@@ -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. */

+ 2
- 2
bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/LONG_Upper.java View File

@@ -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. */

+ 7
- 5
bcel-builder/src/org/aspectj/apache/bcel/verifier/statics/StringRepresentation.java View File

@@ -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);
}

+ 3
- 2
bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ControlFlowGraph.java View File

@@ -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");

+ 3
- 3
bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/ExecutionVisitor.java View File

@@ -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){

+ 8
- 8
bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/InstConstraintVisitor.java View File

@@ -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+"'.");
}
}


+ 5
- 2
bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/LocalVariables.java View File

@@ -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;
}


+ 23
- 32
bcel-builder/src/org/aspectj/apache/bcel/verifier/structurals/Pass3bVerifier.java View File

@@ -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(){

+ 140
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ControlFlowGraph.java View File

@@ -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);
}
}

+ 93
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExceptionHandler.java View File

@@ -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;
}
}

+ 112
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExceptionHandlers.java View File

@@ -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));
}
}

}

+ 1143
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/ExecutionVisitor.java
File diff suppressed because it is too large
View File


+ 375
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Frame.java View File

@@ -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;
}

}

+ 2667
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstConstraintVisitor.java
File diff suppressed because it is too large
View File


+ 113
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContext.java View File

@@ -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();
}

+ 395
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContextImpl.java View File

@@ -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;
}

}

+ 34
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/InstructionContextQueue.java View File

@@ -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); }
}

+ 268
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/LocalVariables.java View File

@@ -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;
// }


}

+ 300
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/OperandStack.java View File

@@ -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());
}
}
}

}

+ 225
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/StackMapHelper.java View File

@@ -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;
}
}

+ 127
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Subroutine.java View File

@@ -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();
}

+ 293
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/SubroutineImpl.java View File

@@ -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;
}
}

}

+ 395
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/Subroutines.java View File

@@ -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();
}
}

+ 104
- 0
bcel-builder/src/org/aspectj/apache/bcel/verifier/utility/UninitializedObjectType.java View File

@@ -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);
}
}

BIN
bcel-builder/testdata/stackmap/Code.class View File


+ 23
- 0
bcel-builder/testdata/stackmap/Code.java View File

@@ -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");
}
}
}

+ 189
- 0
bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/preverifier/PreverifierBaseTestCase.java View File

@@ -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);
}

}

+ 771
- 0
bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/preverifier/PreverifierTest.java View File

@@ -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);
}
}
}

Loading…
Cancel
Save