Documentation updates.

build.xml updates.
javac-1.1 finally/synchronized blocks work again.
some other changes, see ChangeLog for details.


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1346 379699f6-c40d-0410-875b-85095c16579e
master
hoenicke 23 years ago
parent 6acf9d8d7a
commit 7714d5d503
  1. 57
      jode/ChangeLog
  2. 25
      jode/build.xml
  3. 5
      jode/config.props
  4. 2
      jode/doc/feedback.php
  5. 2
      jode/doc/footer.inc
  6. 7
      jode/src/net/sf/jode/bytecode/BasicBlockReader.java
  7. 3
      jode/src/net/sf/jode/bytecode/BasicBlockWriter.java
  8. 2
      jode/src/net/sf/jode/bytecode/BasicBlocks.java
  9. 3
      jode/src/net/sf/jode/bytecode/Reference.java
  10. 2
      jode/src/net/sf/jode/bytecode/ReferenceInstruction.java
  11. 145
      jode/src/net/sf/jode/bytecode/TypeSignature.java
  12. 31
      jode/src/net/sf/jode/bytecode/package.html
  13. 3
      jode/src/net/sf/jode/expr/InvokeOperator.java
  14. 19
      jode/src/net/sf/jode/flow/FlowBlock.java
  15. 15
      jode/src/net/sf/jode/flow/StructuredBlock.java
  16. 632
      jode/src/net/sf/jode/flow/TransformExceptionHandlers.java
  17. 8
      jode/src/net/sf/jode/flow/TryBlock.java
  18. 12
      jode/src/net/sf/jode/jvm/CodeVerifier.java
  19. 28
      jode/src/net/sf/jode/jvm/SyntheticAnalyzer.java

@ -1,3 +1,56 @@
2001-08-14 Jochen Hoenicke <jochen@gnu.org>
* build.xml: test is default.
(release-javadoc): New target.
(release-src): Get from dir test only source files.
(doc-javadoc): More parameters for nicer docu.
2001-08-12 Jochen Hoenicke <jochen@gnu.org>
* net/sf/jode/bytecode/TypeSignature.java:
(getArgumentSize): Renamed to ...
(getParameterSize): ... this. Changed all callers.
(skipType): Made private.
* net/sf/jode/jvm/CodeVerifier.java:
(initInfo): Use TypeSignature.getParameterTypes instead of skipType.
* net/sf/jode/jvm/SyntheticAnalyzer.java:
(checkGetClass): Be more lenient with the types, they are already
checked by the CodeVerifier. This is to support jdk-1.4.
* net/sf/jode/expr/InvokeOperator.java
(dumpExpression): Fixed the check for null outerExpr.
* net/sf/jode/flow/FlowBlock.java:
(checkConsistent): Allow lastModified in a finally block.
* net/sf/jode/flow/TransformExceptionHandlers.java: Reworked exception
handlers again. This time checked with javac 1.3, javac 1.1 and
jikes.
(checkTryCatchOrder): New method that was previously part of
analyze.
(analyze): Use checkTryCatchOrder. Don't merge try and catch flow
blocks anymore, leave it to the analyzeXXX methods.
(mergeTryCatch): New method.
(analyzeCatchBlock): Get catchFlow as parameter. Call
mergeTryCatch.
(transformSubroutine): Handle POP-only subroutines.
(removeJSR): Don't do special case for catchBlock any more. This
is because catchFlow isn't yet merged when this method is called.
(checkAndRemoveJSR): Likewise.
(checkAndRemoveMonitorExit): Likewise. Merge subroutine only if
we are the only predecessor.
(analyzeSynchronized): Get catchFlow as parameter. Call
mergeTryCatch.
(mergeFinallyBlocks): New method, calls mergeTryCatch and does the
common part of mergeFinally and mergeSpecialFinally.
(analyzeFinally): Simplified, after checking and removing JSR, it
does immediately analyze and transform subroutine to get the
finallyBlock. Then it throws away the catchFlow and calls
mergeFinallyBlocks.
(analyzeSpecialFinally): Simplified, after checking it only handles
the jumps in the try part and then call mergeFinallyBlocks.
2001-08-08 Jochen Hoenicke <jochen@gnu.org>
More Documentation updates.
* build.xml: Release rules.
@ -304,7 +357,7 @@
type can't be intersected, return tObject as common super type.
2001-07-15 Jochen Hoenicke <jochen@gnu.org>
Applied patch from Java 1.1 tree:
Applied patch from Jode 1.1 tree:
* jode/expr/Expression.java (updateParentTypes): Call setType,
instead of merging the types. Other childs want to know about the
@ -317,7 +370,7 @@
innermost.
2001-07-14 Jochen Hoenicke <jochen@gnu.org>
Applied patches from the Java 1.1 tree:
Applied patches from the Jode 1.1 tree:
* jode/decompiler/TabbedPrintWriter.java: Better gnu style handling:
(openBraceClass) (closeBraceClass)

@ -19,7 +19,7 @@
-->
<!DOCTYPE project PUBLIC "-//ANT//DTD project//EN" "project.dtd">
<project name="jode" default="all" basedir=".">
<project name="jode" default="test" basedir=".">
<!-- set global properties for this build -->
<property name="version" value="1.90-CVS"/>
@ -32,7 +32,7 @@
<property name="distdir" value="${release}/jode-${version}"/>
<property name="scripts" value="${basedir}/scripts"/>
<property name="api.doc" value="doc/api"/>
<property name="api.doc" value="${doc}/api"/>
<property name="test" value="${basedir}/test"/>
<property name="test.src" value="${test}/src"/>
@ -164,7 +164,7 @@
<!-- ********* Create Release files ******* -->
<target name="release" depends="release-bin,release-bin11,release-src"/>
<target name="release" depends="release-bin,release-bin11,release-src,release-javadoc"/>
<target name="release-bindist" depends="build">
<jar jarfile="${distdir}/jode.jar">
@ -221,7 +221,9 @@
<include name="doc/**"/>
<include name="scripts/**"/>
<include name="src/**"/>
<include name="test/**"/>
<include name="test/*.java"/>
<include name="test/*.j"/>
<include name="test/src/**"/>
<include name="props/**"/>
<include name="lib/**"/>
</fileset>
@ -231,6 +233,14 @@
<delete dir="${distdir}"/>
</target>
<target name="release-javadoc">
<antcall target="doc-javadoc"/>
<mkdir dir="${release}"/>
<jar jarfile="${release}/jode-${version}-API.jar"
basedir="${doc}" includes="api/**"/>
<antcall target="clean-doc"/>
</target>
<target name="clean-release">
<delete dir="${release}"/>
</target>
@ -254,8 +264,15 @@
</execon>
</target>
<target name="doc-javadoc">
<tstamp>
<format property="date" pattern="MMM d, yyyy"/>
</tstamp>
<mkdir dir="${api.doc}"/>
<javadoc packagenames="net.sf.jode.*"
windowtitle="Jode ${version} API Specification"
header='&lt;b&gt;&lt;a href="http://jode.sourceforge.net/"&gt;Jode&lt;/a&gt; ${version}&lt;/b&gt;&lt;br&gt;&lt;font size="-2"&gt;Build ${date}&lt;/font&gt;'
overview="${src}/net/sf/jode/overview.html"
bottom='Copyright &amp;copy; 1998-2001 by Jochen Hoenicke.'
sourcepath="${src}"
destdir="${api.doc}"
use="yes">

@ -1,10 +1,11 @@
# Do you have online access for generating javadoc?
# If not, where are your local files.
javadoc.offline=false
#javadoc.href=http://java.sun.com/products/jdk/1.2/docs/api/
javadoc.packagelistLoc=
javadoc.href=http://java.sun.com/products/jdk/1.2/docs/api/
#javadoc.href=file:/usr/doc/inet/java/jdk1.2/docs/api
#javadoc.offline=true
javadoc.href=file:/usr/doc/inet/java/jdk1.2/docs/api
#javadoc.packagelistLoc=/usr/doc/inet/java/jdk1.2/docs/api
# Is Perl installed on your system?

@ -7,7 +7,7 @@ Please send me a short notice if you add a bug.</p>
<p>You can contact me per email via <a
href="http://sourceforge.net/sendmessage.php?touser=18252">hoenicke at
users.sourceforge.net</a>. Please mention <i>jode</i> in the
users.sourceforge.net</a>. Please mention <i>Jode</i> in the
subject.</p>
<p>There is a mailing list. Check <a href="http://lists.sourceforge.net/mailman/listinfo/jode-users">this page</a> for subscription informations.</p>

@ -3,7 +3,7 @@
<TD align="center"><SPAN class=footer>
All trademarks and copyrights on this page are properties of their respective owners. <br>
Last updated on 3-Jul-2000,
Copyright &copy; 1998-2000 by Jochen Hoenicke.<br>
Copyright &copy; 1998-2001 by Jochen Hoenicke.<br>
Canonic URL is <a class=boldlink href="http://jode.sourceforge.net/">http://jode.sourceforge.net/</a></SPAN>
</TD>
</TR>

@ -693,7 +693,7 @@ class BasicBlockReader implements Opcodes {
throw new ClassFormatException
("Illegal call of special method "+ref);
int nargs = input.readUnsignedByte();
if (TypeSignature.getArgumentSize(ref.getType())
if (TypeSignature.getParameterSize(ref.getType())
!= nargs - 1)
throw new ClassFormatException
("Interface nargs mismatch: "+ref+" vs. "+nargs);
@ -890,7 +890,7 @@ class BasicBlockReader implements Opcodes {
GlobalOptions.err.println("Illegal LVT length, ignoring it");
return;
}
Vector[] lvt = new Vector[bb.maxLocals];
Vector[] lvt = new Vector[maxLocals];
for (int i=0; i < count; i++) {
LVTEntry lve = new LVTEntry();
lve.start = input.readUnsignedShort();
@ -899,7 +899,8 @@ class BasicBlockReader implements Opcodes {
int typeIndex = input.readUnsignedShort();
int slot = input.readUnsignedShort();
if (nameIndex == 0 || cp.getTag(nameIndex) != cp.UTF8
|| typeIndex == 0 || cp.getTag(typeIndex) != cp.UTF8) {
|| typeIndex == 0 || cp.getTag(typeIndex) != cp.UTF8
|| slot >= maxLocals) {
// This is probably an evil lvt as created by HashJava
// simply ignore it.

@ -894,7 +894,8 @@ class BasicBlockWriter implements Opcodes {
output.writeShort
(gcp.putRef(gcp.INTERFACEMETHODREF, ref));
output.writeByte
(TypeSignature.getArgumentSize(ref.getType()) + 1);
(TypeSignature
.getParameterSize(ref.getType()) + 1);
output.writeByte(0);
} else
output.writeShort(gcp.putRef(gcp.METHODREF, ref));

@ -132,7 +132,7 @@ public class BasicBlocks extends BinaryInfo implements Opcodes {
public BasicBlocks(MethodInfo mi) {
methodInfo = mi;
int paramSize = (mi.isStatic() ? 0 : 1)
+ TypeSignature.getArgumentSize(mi.getType());
+ TypeSignature.getParameterSize(mi.getType());
paramInfos = new LocalVariableInfo[paramSize];
for (int i=0; i< paramSize; i++)
paramInfos[i] = LocalVariableInfo.getInfo(i);

@ -24,7 +24,8 @@ import java.util.Iterator;
///#enddef
/**
* This class represents a field or method reference.
* This class represents a field or method reference. It consists of
* the class name the method/field name and the type signature.
*/
public class Reference {
/**

@ -61,7 +61,7 @@ class ReferenceInstruction extends Instruction {
case opc_invokestatic:
case opc_invokeinterface:
poppush[0] = opcode != opc_invokestatic ? 1 : 0;
poppush[0] += TypeSignature.getArgumentSize(typeSig);
poppush[0] += TypeSignature.getParameterSize(typeSig);
poppush[1] = TypeSignature.getReturnSize(typeSig);
break;

@ -21,7 +21,37 @@ package net.sf.jode.bytecode;
import net.sf.jode.util.UnifyHash;
/**
* This class contains some static methods to handle type signatures.
* This class contains some static methods to handle type signatures. <br>
*
* A type signature is a compact textual representation of a java
* types. It is described in the Java Virtual Machine Specification.
* Primitive types have a one letter type signature. Type signature
* of classes contains the class name. Type signatures for arrays and
* methods are recursively build from the type signatures of their
* elements. <br>
*
* Here are a few examples:
* <table><tr><th>type signature</th><th>Java type</th></tr>
* <tr><td><code>Z</code></td><td><code>boolean</code></td></tr>
* <tr><td><code>B</code></td><td><code>byte</code></td></tr>
* <tr><td><code>S</code></td><td><code>short</code></td></tr>
* <tr><td><code>C</code></td><td><code>char</code></td></tr>
* <tr><td><code>I</code></td><td><code>int</code></td></tr>
* <tr><td><code>F</code></td><td><code>float</code></td></tr>
* <tr><td><code>J</code></td><td><code>long</code></td></tr>
* <tr><td><code>D</code></td><td><code>double</code></td></tr>
* <tr><td><code>Ljava/lang/Object;</code></td>
* <td><code>java.lang.Object</code></td></tr>
* <tr><td><code>[[I</code></td><td><code>int[][]</code></td></tr>
* <tr><td><code>(Ljava/lang/Object;I)V</code></td>
* <td>method with argument types <code>Object</code> and
* <code>int</code> and <code>void</code> return type.</td></tr>
* <tr><td><code>()I</code></td>
* <td> method without arguments
* and <code>int</code> return type.</td></tr>
* </table>
*
* @author Jochen Hoenicke
*/
public class TypeSignature {
/**
@ -61,22 +91,20 @@ public class TypeSignature {
}
/**
* Generate the signature for the given Class.
* Generates the type signature of the given Class.
* @param clazz a java.lang.Class, this may also be a primitive or
* array type.
* @return the type signature (see section 4.3.2 Field Descriptors
* of the JVM specification)
* @return the type signature.
*/
public static String getSignature(Class clazz) {
return appendSignature(new StringBuffer(), clazz).toString();
}
/**
* Generate a method signature.
* Generates a method signature.
* @param paramT the java.lang.Class of the parameter types of the method.
* @param returnT the java.lang.Class of the return type of the method.
* @return the method signature (see section 4.3.3 Method Descriptors
* of the JVM specification)
* @return the method type signature
*/
public static String getSignature(Class paramT[], Class returnT) {
StringBuffer sig = new StringBuffer("(");
@ -86,8 +114,8 @@ public class TypeSignature {
}
/**
* Generate a Class for a type signature. This is the pendant to
* getSignature.
* Generates a Class object for a type signature. This is the
* inverse function of getSignature.
* @param typeSig a single type signature
* @return the Class object representing that type.
*/
@ -124,25 +152,43 @@ public class TypeSignature {
}
/**
* Check if the given type is a two slot type. */
* Check if the given type is a two slot type. The only two slot
* types are long and double.
*/
private static boolean usingTwoSlots(char type) {
return "JD".indexOf(type) >= 0;
}
/**
* Returns the number of words, an object of the given simple type
* signature takes.
* signature takes. For long and double this is two, for all other
* types it is one.
*/
public static int getTypeSize(String typeSig) {
return usingTwoSlots(typeSig.charAt(0)) ? 2 : 1;
}
/**
* Gets the element type of an array.
* @param typeSig type signature of the array.
* @return type signature for the element type.
* @exception IllegalArgumentException if typeSig is not an array
* type signature.
*/
public static String getElementType(String typeSig) {
if (typeSig.charAt(0) != '[')
throw new IllegalArgumentException();
return typeSig.substring(1);
}
/**
* Gets the ClassInfo for a class type.
* @param classpath the classpath in which the ClassInfo is searched.
* @param typeSig type signature of the class.
* @return the ClassInfo object for the class.
* @exception IllegalArgumentException if typeSig is not an class
* type signature.
*/
public static ClassInfo getClassInfo(ClassPath classpath, String typeSig) {
if (typeSig.charAt(0) != 'L')
throw new IllegalArgumentException();
@ -150,7 +196,13 @@ public class TypeSignature {
(typeSig.substring(1, typeSig.length()-1).replace('/', '.'));
}
public static int skipType(String methodTypeSig, int position) {
/**
* Skips the next entry of a method type signature
* @param methodTypeSig type signature of the method.
* @param position the index to the last entry.
* @return the index to the next entry.
*/
static int skipType(String methodTypeSig, int position) {
char c = methodTypeSig.charAt(position++);
while (c == '[')
c = methodTypeSig.charAt(position++);
@ -160,10 +212,13 @@ public class TypeSignature {
}
/**
* Returns the number of words, the arguments for the given method
* type signature takes.
* Gets the number of words the parameters for the given method
* type signature takes. This is the sum of getTypeSize() for
* each parameter type.
* @param methodTypeSig the method type signature.
* @return the number of words the parameters take.
*/
public static int getArgumentSize(String methodTypeSig) {
public static int getParameterSize(String methodTypeSig) {
int nargs = 0;
int i = 1;
for (;;) {
@ -179,8 +234,11 @@ public class TypeSignature {
}
/**
* Returns the number of words, an object of the given simple type
* signature takes.
* Gets the size of the return type of the given method in words.
* This is zero for void return type, two for double or long return
* type and one otherwise.
* @param methodTypeSig the method type signature.
* @return the size of the return type in words.
*/
public static int getReturnSize(String methodTypeSig) {
int length = methodTypeSig.length();
@ -195,8 +253,9 @@ public class TypeSignature {
}
/**
* Returns the number of words, an object of the given simple type
* signature takes.
* Gets the parameter type signatures of the given method signature.
* @param methodTypeSig the method type signature.
* @return an array containing all parameter types in correct order.
*/
public static String[] getParameterTypes(String methodTypeSig) {
int pos = 1;
@ -215,6 +274,26 @@ public class TypeSignature {
return params;
}
/**
* Gets the return type for a method signature
* @param methodTypeSig the method signature.
* @return the return type for a method signature, `V' for void methods.
*/
public static String getReturnType(String methodTypeSig) {
return methodTypeSig.substring(methodTypeSig.lastIndexOf(')')+1);
}
/**
* Gets the default value an object of the given type has. It is
* null for objects and arrays, Integer(0) for boolean and short
* integer types or Long(0L), Double(0.0), Float(0.0F) for long,
* double and float. This seems strange, but this way the type
* returned is the same as for FieldInfo.getConstant().
*
* @param typeSig the type signature.
* @return the default value.
* @exception IllegalArgumentException if this is a method type signature.
*/
public static Object getDefaultValue(String typeSig) {
switch(typeSig.charAt(0)) {
case 'Z':
@ -238,15 +317,7 @@ public class TypeSignature {
}
/**
* Returns the number of words, an object of the given simple type
* signature takes.
*/
public static String getReturnType(String methodTypeSig) {
return methodTypeSig.substring(methodTypeSig.lastIndexOf(')')+1);
}
/**
* Check if there is a valid class name starting at index
* Checks if there is a valid class name starting at index
* in string typesig and ending with a semicolon.
* @return the index at which the class name ends.
* @exception IllegalArgumentException if there was an illegal character.
@ -266,7 +337,7 @@ public class TypeSignature {
}
/**
* Check if there is a valid simple type signature starting at index
* Checks if there is a valid simple type signature starting at index
* in string typesig.
* @return the index at which the type signature ends.
* @exception IllegalArgumentException if there was an illegal character.
@ -285,6 +356,14 @@ public class TypeSignature {
return index;
}
/**
* Checks whether a given type signature is a valid (not method)
* type signature. Throws an exception otherwise.
* @param typeSig the type signature.
* @exception NullPointerException if typeSig is null.
* @exception IllegalArgumentException if typeSig is not a valid
* type signature or if it's a method type signature.
*/
public static void checkTypeSig(String typesig)
throws IllegalArgumentException
{
@ -298,6 +377,14 @@ public class TypeSignature {
}
}
/**
* Checks whether a given type signature is a valid method
* type signature. Throws an exception otherwise.
* @param typeSig the type signature.
* @exception NullPointerException if typeSig is null.
* @exception IllegalArgumentException if typeSig is not a valid
* method type signature.
*/
public static void checkMethodTypeSig(String typesig)
throws IllegalArgumentException
{

@ -18,7 +18,7 @@
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-->
<title>JODE Bytecode Package</title>
<title>Jode Bytecode Package</title>
</head>
<body>
@ -71,11 +71,36 @@ You can also use this package to create and write new classes:
...
</pre>
<h3><a name="advantages">Advantages of this bytecode package</a></h3>
<ul>
<li>You don't need to think of the constant pool, except when you want
to write your custom attributes.</li>
<li>The set of opcodes is drastically reduced: For example you don't
have to handle 20 different opcodes that all push a constant value on
the stack. When reading it will automatically convert them to
<code>ldc</code> or <code>ldc2</code> and on writing it will convert
them back.</li>
<li>Wide instructions are automatically generated when needed, large
methods are supported.</li>
<li>The code is organized in {@link net.sf.jode.bytecode.BasicBlocks}
which makes flow analysis much easier.</li>
<li>The memory consumption is quite moderate.</li>
</ul>
<h3>Disadvantages</h3>
<ul>
<li>You can't change every byte. For example Jode decides itself if
a lookup switch or table switch is generated.</li>
<li>Jode does a lot of checks when reading the bytecode and it is
impossible to recover from errors. This makes it sometime hard to
find out why the bytecode of a particular class files is invalid.</li>
</ul>
<hr>
<address><a href="mailto:jochen@gnu.org">Jochen Hoenicke</a></address>
<!-- Created: Thu Jun 22 16:56:39 MET DST 2000 -->
<!-- Created: Thu Jun 22 2000 -->
<!-- hhmts start -->
Last modified: Sun Aug 5 17:53:03 MEST 2001
Last modified: Sat Aug 11 18:44:19 MEST 2001
<!-- hhmts end -->
</body>
</html>

@ -1033,7 +1033,8 @@ public final class InvokeOperator extends Operator
}
} else {
qualifiedNew = true;
if (outerExpr.getType() instanceof NullType) {
if (outerExpr.getType().getCanonic()
instanceof NullType) {
writer.print("(");
writer.startOp(writer.EXPL_PAREN, 1);
writer.print("(");

@ -1,4 +1,4 @@
/* FlowBlock Copyright (C) 1998-1999 Jochen Hoenicke.
/* FlowBlock Copyright (C) 1998-2001 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -211,6 +211,9 @@ public class FlowBlock {
* @return The remaining jumps, that couldn't be resolved.
*/
public Jump resolveSomeJumps(Jump jumps, FlowBlock succ) {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("before Resolve: "+this);
/* We will put all jumps that we can not resolve into this
* linked list.
*/
@ -721,7 +724,7 @@ public class FlowBlock {
* begin of successor.
* @param kills The slots that are always overwritten on the way to
* successor.
* @return The variables that must be defined * in this block.
* @return The variables that must be defined in this block.
*/
void updateInOut(FlowBlock successor, VariableSet gens, SlotSet kills) {
successor.updateGenKill(gens, kills);
@ -805,7 +808,9 @@ public class FlowBlock {
try {
if (block.outer != null || block.flowBlock != this) {
throw new InternalError("Inconsistency: outer:"+block.outer+" block.flow"+block.flowBlock +" this: "+this);
throw new InternalError("Inconsistency: outer:" + block.outer
+ " block.flow"+block.flowBlock
+ " this: "+this);
}
block.checkConsistent();
@ -820,7 +825,8 @@ public class FlowBlock {
StructuredBlock last = lastModified;
while (last.outer instanceof SequentialBlock
|| last.outer instanceof TryBlock)
|| last.outer instanceof TryBlock
|| last.outer instanceof FinallyBlock)
last = last.outer;
if (last.outer != null)
throw new InternalError("Inconsistency");
@ -999,8 +1005,6 @@ public class FlowBlock {
/* Update the in/out-Vectors now */
updateInOut(succ, succInfo.gen, succInfo.kill);
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("before Resolve: "+this);
/* Try to eliminate as many jumps as possible.
*/
@ -1055,9 +1059,6 @@ public class FlowBlock {
jumps = jump;
}
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_FLOW) != 0)
GlobalOptions.err.println("before resolve: "+this);
/* Try to eliminate as many jumps as possible.
*/
jumps = resolveSomeJumps(jumps, END_OF_METHOD);

@ -60,14 +60,13 @@ import java.util.Set;
public abstract class StructuredBlock {
/* Invariants:
* in.intersection(out) = empty
* outer != null => flowBlock = outer.flowBlock
* outer == null => flowBlock.block = this
* jump == null => outer != null
* either getNextBlock() != null
* or getNextFlowBlock() != null or outer == null
* either outer.getNextBlock(this) != null
* or outer.getNextFlowBlock(this) != null
* outer != null ==> flowBlock = outer.flowBlock;
* outer == null ==> flowBlock.block = this;
* jump == null ==> outer != null;
* getNextBlock() != null ^ getNextFlowBlock() != null;
* outer != null ==>
* outer.getNextBlock(this) != null
* ^ outer.getNextFlowBlock(this) != null;
*/
/**

@ -103,35 +103,62 @@ public class TransformExceptionHandlers {
handlers.add(new Handler(tryBlock, endBlock, catchBlock, type));
}
/**
* Merge the try flow block with the catch flow block. This is a kind
* of special T2 transformation, as all jumps to the catch block are
* implicit (exception can be thrown everywhere). <br>
*
* This method doesn't actually merge the contents of the blocks. The
* caller should do it right afterwards. <br>
*
* The flow block catchFlow mustn't have any predecessors.
* @param tryFlow the flow block containing the try.
* @param catchFlow the flow block containing the catch handler.
*/
static void mergeTryCatch(FlowBlock tryFlow, FlowBlock catchFlow) {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("mergeTryCatch(" + tryFlow.getBlockNr()
+ ", " + catchFlow.getBlockNr() + ")");
tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeSuccessors(catchFlow);
tryFlow.mergeBlockNr(catchFlow);
}
/* simple try catch block:
/**
* Analyzes a simple try/catch block. The try and catch part are both
* analyzed, the try block is already created, but the catch block
* isn't. <br>
* The catchFlow block mustn't have any predecessors.
*
* try-header
* |- first instruction
* | ...
* | last instruction
* |- optional jump (last+1)
* | ...
* `- catch block
* @param type The type of the exception which is caught.
* @param tryFlow The flow block containing the try. The contained
* block must be a try block.
* @param catchFlow the flow block containing the catch handler.
*/
static void analyzeCatchBlock(Type type, FlowBlock tryFlow,
StructuredBlock catchBlock) {
FlowBlock catchFlow) {
/* Merge try and catch flow blocks */
mergeTryCatch(tryFlow, catchFlow);
/* Insert catch block into tryFlow */
CatchBlock newBlock = new CatchBlock(type);
((TryBlock)tryFlow.block).addCatchBlock(newBlock);
newBlock.setCatchBlock(catchBlock);
newBlock.setCatchBlock(catchFlow.block);
tryFlow.lastModified = tryFlow.block;
}
/* And now the complicated parts. */
/**
* This transforms a sub routine, that is checks if the beginning
* local assignment matches the final ret and then returns.
* This transforms a sub routine, i.e. it checks if the beginning
* local assignment matches the final ret and removes both. It also
* accepts sub routines that just pop their return address.
*/
boolean transformSubRoutine(StructuredBlock subRoutine) {
if (!(subRoutine instanceof SequentialBlock))
return false;
SequentialBlock sequBlock = (SequentialBlock) subRoutine;
StructuredBlock firstBlock = sequBlock.getSubBlocks()[0];
boolean transformSubRoutine(StructuredBlock subRoutineBlock) {
StructuredBlock firstBlock = subRoutineBlock;
if (firstBlock instanceof SequentialBlock)
firstBlock = subRoutineBlock.getSubBlocks()[0];
LocalInfo local = null;
if (firstBlock instanceof SpecialBlock) {
@ -156,24 +183,25 @@ public class TransformExceptionHandlers {
} else
return false;
/* We are now committed. Remove the first Statement which
* stores/removes the return address.
/* We are now committed and can start changing code. Remove
* the first Statement which stores/removes the return
* address.
*/
firstBlock.removeBlock();
/* XXX - Replace any RET with a jump to end of this flow block.
/* We don't check if there is a RET in the middle.
*
* This is a complicated task which isn't needed for javac nor
* jikes. We just check if the last instruction is a ret and
* replace this. This will never produce code with wrong semantic,
* remove this. This will never produce code with wrong semantic,
* as long as the bytecode was verified correctly.
*/
while (sequBlock.subBlocks[1] instanceof SequentialBlock)
sequBlock = (SequentialBlock) sequBlock.subBlocks[1];
while (subRoutineBlock instanceof SequentialBlock)
subRoutineBlock = subRoutineBlock.getSubBlocks()[1];
if (sequBlock.subBlocks[1] instanceof RetBlock
&& (((RetBlock) sequBlock.subBlocks[1]).local.equals(local))) {
sequBlock.subBlocks[1].removeBlock();
if (subRoutineBlock instanceof RetBlock
&& (((RetBlock) subRoutineBlock).local.equals(local))) {
subRoutineBlock.removeBlock();
}
return true;
}
@ -203,51 +231,32 @@ public class TransformExceptionHandlers {
}
/**
* Remove the wrongly placed JSRs jumping to the specified
* subRoutine. The right JSRs are already removed, but we have to
* replace the wrong ones with a warning.
* @param tryFlow the FlowBLock of the try block.
* Remove the JSRs jumping to the specified subRoutine. The right
* JSRs are marked and we can just remove them. For the other JSR
* instructions we replace them with a warning.
* @param tryFlow the FlowBlock of the try block.
* @param subRoutine the FlowBlock of the sub routine.
*/
private void removeJSR(FlowBlock tryFlow, StructuredBlock catchBlock,
FlowBlock subRoutine) {
Jump nextJump;
for (Jump jumps = tryFlow.getJumps(subRoutine);
jumps != null; jumps = nextJump) {
private void removeJSR(FlowBlock tryFlow, FlowBlock subRoutine) {
for (Jump jumps = tryFlow.removeJumps(subRoutine);
jumps != null; jumps = jumps.next) {
StructuredBlock prev = jumps.prev;
nextJump = jumps.next;
if (prev instanceof EmptyBlock
&& prev.outer instanceof JsrBlock) {
JsrBlock jsr = (JsrBlock) prev.outer;
if (prev.outer == catchBlock) {
/* This is the mandatory jsr in the catch block */
continue;
}
prev.removeJump();
tryFlow.removeSuccessor(jumps);
prev.removeJump();
if (jsr.isGood()) {
StructuredBlock next = jsr.getNextBlock();
jsr.removeBlock();
if (next instanceof ReturnBlock)
removeReturnLocal((ReturnBlock) next);
} else {
/* We have a JSR to the subroutine, which is badly placed.
* We complain here.
*/
DescriptionBlock msg
= new DescriptionBlock("ERROR: JSR FINALLY BLOCK!");
msg.replace(prev.outer);
}
} else {
/* We have a jump to the subroutine, that is wrong.
if (prev instanceof EmptyBlock
&& prev.outer instanceof JsrBlock
&& ((JsrBlock) prev.outer).isGood()) {
StructuredBlock next = prev.outer.getNextBlock();
prev.outer.removeBlock();
if (next instanceof ReturnBlock)
removeReturnLocal((ReturnBlock) next);
} else {
/* We have a jump to the subroutine, that is badly placed.
* We complain here.
*/
DescriptionBlock msg
= new DescriptionBlock("ERROR: GOTO FINALLY BLOCK!");
tryFlow.removeSuccessor(jumps);
prev.removeJump();
DescriptionBlock msg = new DescriptionBlock
("ERROR: invalid jump to finally block!");
prev.appendBlock(msg);
}
}
@ -313,7 +322,6 @@ public class TransformExceptionHandlers {
private void checkAndRemoveJSR(FlowBlock tryFlow,
StructuredBlock catchBlock,
FlowBlock subRoutine,
int startOutExit, int endOutExit) {
Iterator iter = tryFlow.getSuccessors().iterator();
@ -330,8 +338,8 @@ public class TransformExceptionHandlers {
StructuredBlock prev = jumps.prev;
if (prev instanceof EmptyBlock
&& prev.outer instanceof JsrBlock) {
/* This jump is really a jsr, since it doesn't
* leave the block forever, we can ignore it.
/* This jump is a jsr, since it doesn't leave the
* block forever, we can ignore it.
*/
continue;
}
@ -382,7 +390,7 @@ public class TransformExceptionHandlers {
* Complain!
*/
DescriptionBlock msg
= new DescriptionBlock("ERROR: NO JSR TO FINALLY");
= new DescriptionBlock("ERROR: no jsr to finally");
if (pred != null)
pred.prependBlock(msg);
else {
@ -392,11 +400,10 @@ public class TransformExceptionHandlers {
}
}
if (tryFlow.getSuccessors().contains(subRoutine))
removeJSR(tryFlow, catchBlock, subRoutine);
removeJSR(tryFlow, subRoutine);
}
private void checkAndRemoveMonitorExit(FlowBlock tryFlow,
StructuredBlock catchBlock,
LocalInfo local,
int start, int end) {
FlowBlock subRoutine = null;
@ -494,7 +501,7 @@ public class TransformExceptionHandlers {
/* Complain!
*/
DescriptionBlock msg
= new DescriptionBlock("ERROR: NO MONITOREXIT");
= new DescriptionBlock("ERROR: no monitorexit");
prev.appendBlock(msg);
msg.moveJump(jumps);
}
@ -502,8 +509,9 @@ public class TransformExceptionHandlers {
if (subRoutine != null) {
if (tryFlow.getSuccessors().contains(subRoutine))
removeJSR(tryFlow, catchBlock, subRoutine);
tryFlow.mergeBlockNr(subRoutine);
removeJSR(tryFlow, subRoutine);
if (subRoutine.predecessors.size() == 0)
tryFlow.mergeBlockNr(subRoutine);
}
}
@ -526,20 +534,25 @@ public class TransformExceptionHandlers {
}
private boolean analyzeSynchronized(FlowBlock tryFlow,
StructuredBlock catchBlock,
FlowBlock catchFlow,
int endHandler) {
/* Check if this is a synchronized block. We mustn't change
* anything until we are sure.
*/
StructuredBlock catchBlock = catchFlow.block;
/* Check for a optional exception store and skip it */
StoreInstruction excStore = getExceptionStore(catchBlock);
if (excStore != null)
catchBlock = catchBlock.getSubBlocks()[1];
/* Check for the monitorexit instruction */
if (!(catchBlock instanceof SequentialBlock
&& catchBlock.getSubBlocks()[0]
instanceof InstructionBlock))
return false;
Expression instr =
((InstructionBlock)catchBlock.getSubBlocks()[0]).getInstruction();
if (!(instr instanceof MonitorExitOperator
&& instr.getFreeOperandCount() == 0
&& (((MonitorExitOperator)instr).getSubExpressions()[0]
@ -547,9 +560,9 @@ public class TransformExceptionHandlers {
&& catchBlock.getSubBlocks()[1] instanceof ThrowBlock))
return false;
/* Check for the throw instruction */
Expression throwInstr =
((ThrowBlock)catchBlock.getSubBlocks()[1]).getInstruction();
if (excStore != null) {
if (!(throwInstr instanceof Operator
&& excStore.lvalueMatches((Operator)throwInstr)))
@ -583,6 +596,12 @@ public class TransformExceptionHandlers {
* monitorexit local_x
* return_n
*/
/* Merge try and catch flow blocks. No need to insert the
* catchFlow.block into the try flow though, since all its
* instruction are synthetic.
*/
mergeTryCatch(tryFlow, catchFlow);
MonitorExitOperator monexit = (MonitorExitOperator)
((InstructionBlock) catchBlock.getSubBlocks()[0]).instr;
@ -597,7 +616,7 @@ public class TransformExceptionHandlers {
+ "," + tryFlow.getNextBlockNr() + "," + endHandler + ")");
checkAndRemoveMonitorExit
(tryFlow, catchBlock, local, tryFlow.getNextBlockNr(), endHandler);
(tryFlow, local, tryFlow.getNextBlockNr(), endHandler);
SynchronizedBlock syncBlock = new SynchronizedBlock(local);
TryBlock tryBlock = (TryBlock) tryFlow.block;
@ -609,8 +628,41 @@ public class TransformExceptionHandlers {
return true;
}
/**
* Merge try and finally flow blocks.
* @param tryFlow The try flow block. Its contained block must be
* a try block.
* @param catchFlow The catch flow block that contains the finally
* block.
* @param finallyBlock block that either contains the finally block.
* It is part of the catchFlow. The other parts of catchFlow are
* synthetic and can be removed.
*/
private void mergeFinallyBlock(FlowBlock tryFlow, FlowBlock catchFlow,
StructuredBlock finallyBlock) {
TryBlock tryBlock = (TryBlock) tryFlow.block;
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) {
/* A try { try { } catch {} } finally{} is equivalent
* to a try {} catch {} finally {}
* so remove the surrounding tryBlock.
*/
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0];
innerTry.gen = tryBlock.gen;
innerTry.replace(tryBlock);
tryBlock = innerTry;
tryFlow.lastModified = tryBlock;
tryFlow.block = tryBlock;
}
/* Now merge try and catch flow blocks */
mergeTryCatch(tryFlow, catchFlow);
FinallyBlock newBlock = new FinallyBlock();
newBlock.setCatchBlock(finallyBlock);
tryBlock.addCatchBlock(newBlock);
}
private boolean analyzeFinally(FlowBlock tryFlow,
StructuredBlock catchBlock, int end) {
FlowBlock catchFlow, int end) {
/* Layout of a try-finally block:
*
@ -632,6 +684,7 @@ public class TransformExceptionHandlers {
* return_n
*/
StructuredBlock catchBlock = catchFlow.block;
StoreInstruction excStore = getExceptionStore(catchBlock);
if (excStore == null)
return false;
@ -643,9 +696,10 @@ public class TransformExceptionHandlers {
StructuredBlock finallyBlock = null;
if (catchBlock.getSubBlocks()[0] instanceof LoopBlock) {
/* In case the try block has no exit (that means, it throws
* an exception), the finallyBlock was already merged with
* the catchBlock. We have to check for this case separately:
/* In case the try block has no exit (that means, it
* throws an exception or loops forever), the finallyBlock
* was already merged with the catchBlock. We have to
* check for this case separately:
*
* do {
* JSR
@ -682,7 +736,7 @@ public class TransformExceptionHandlers {
FlowBlock subRoutine;
if (finallyBlock != null) {
/* Check if the jsr breaks (see two comments above). We don't
/* Check if the jsr breaks (see comment above). We don't
* need to check if it breaks to the right block, because
* we know that there is only one Block around the jsr.
*/
@ -690,269 +744,255 @@ public class TransformExceptionHandlers {
return false;
/* Check if the try block has no exit
* XXX - Unfortunately the try block already has the
* successors of catch block.
*/
// if (tryFlow.getSuccessors().size() > 0)
// return false;
if (tryFlow.getSuccessors().size() > 0)
return false;
catchBlock = finallyBlock;
subRoutine = null;
} else {
if (!(jsrBlock.innerBlock instanceof EmptyBlock))
return false;
catchBlock = jsrBlock;
subRoutine = jsrBlock.innerBlock.jump.destination;
checkAndRemoveJSR(tryFlow, catchBlock, subRoutine,
tryFlow.getNextBlockNr(),
subRoutine.getBlockNr());
}
/* Wow that was complicated :-)
* But now we know that the catch block looks
* exactly like it should:
*
* local_n = POP
* catchBlock:
* JSR
* finally
* throw local_n
*/
finallyBlock = jsrBlock.innerBlock;
subRoutine = finallyBlock.jump.destination;
TryBlock tryBlock = (TryBlock) tryFlow.block;
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) {
/* remove the surrounding tryBlock */
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0];
innerTry.gen = tryBlock.gen;
innerTry.replace(tryBlock);
tryBlock = innerTry;
tryFlow.lastModified = tryBlock;
tryFlow.block = tryBlock;
}
FinallyBlock newBlock = new FinallyBlock();
newBlock.setCatchBlock(catchBlock);
tryBlock.addCatchBlock(newBlock);
/* We are committed now and can start changing the try
* block.
*/
checkAndRemoveJSR(tryFlow, subRoutine,
tryFlow.getNextBlockNr(), end);
if (subRoutine != null) {
while (subRoutine.analyze(tryFlow.getNextBlockNr(), end));
/* Now check if the subroutine is correct and has only the
* catchFlow as predecessor.
/* Now analyze and transform the subroutine.
*/
if (subRoutine.predecessors.size() == 1
&& transformSubRoutine(subRoutine.block)) {
tryFlow.removeSuccessor(jsrBlock.innerBlock.jump);
tryFlow.mergeBlockNr(subRoutine);
tryFlow.mergeSuccessors(subRoutine);
subRoutine.block.replace(catchBlock);
tryFlow.updateInOutCatch(subRoutine);
while (subRoutine.analyze(tryFlow.getNextBlockNr(), end));
if (subRoutine.predecessors.size() == 1) {
/* catchFlow is synthetic, so we can safely remove it
* here.
*/
subRoutine.mergeBlockNr(catchFlow);
catchFlow = subRoutine;
if (!transformSubRoutine(subRoutine.block)) {
finallyBlock = subRoutine.block;
DescriptionBlock msg = new DescriptionBlock
("ERROR: Missing return address handling");
StructuredBlock subblock = subRoutine.block;
msg.replace(finallyBlock);
msg.appendBlock(finallyBlock);
}
finallyBlock = subRoutine.block;
}
}
/* Now finish it.
*/
mergeFinallyBlock(tryFlow, catchFlow, finallyBlock);
return true;
}
private boolean analyzeSpecialFinally(FlowBlock tryFlow,
StructuredBlock catchBlock,
int end) {
FlowBlock catchFlow, int end) {
StructuredBlock finallyBlock = catchFlow.block;
StructuredBlock firstInstr =
catchBlock instanceof SequentialBlock
? catchBlock.getSubBlocks()[0]: catchBlock;
finallyBlock instanceof SequentialBlock
? finallyBlock.getSubBlocks()[0]: finallyBlock;
if (!(firstInstr instanceof SpecialBlock
&& ((SpecialBlock)firstInstr).type == SpecialBlock.POP
&& ((SpecialBlock)firstInstr).count == 1))
return false;
/* This may be a special try/finally-block, where
/* This is a special try/finally-block, where
* the finally block ends with a break, return or
* similar.
*/
FlowBlock succ = null;
/* remove the pop now */
if (catchBlock instanceof SequentialBlock)
catchBlock = catchBlock.getSubBlocks()[1];
/* Make sure that resolveJump only works on the inside of the try
*/
tryFlow.lastModified = tryFlow.block.getSubBlocks()[0];
if (finallyBlock instanceof SequentialBlock)
finallyBlock = finallyBlock.getSubBlocks()[1];
else {
catchBlock = new EmptyBlock();
catchBlock.moveJump(firstInstr.jump);
finallyBlock = new EmptyBlock();
finallyBlock.moveJump(firstInstr.jump);
succ = firstInstr.jump.destination;
/* Handle the jumps in the tryFlow to finallyFlow.
*/
FlowBlock finallyFlow = finallyBlock.jump.destination;
if (tryFlow.getSuccessors().contains(finallyFlow)) {
Jump jumps = tryFlow.removeJumps(finallyFlow);
jumps = tryFlow.resolveSomeJumps(jumps, finallyFlow);
tryFlow.resolveRemaining(jumps);
}
}
// Set trySuccs = tryFlow.getSuccessors();
// if (trySuccs.size() > 1
// || (trySuccs.size() == 1
// && trySuccs.iterator().next() != succ))
// return false;
/* Complain about all other jumps in try block */
Set trySuccs = tryFlow.getSuccessors();
for (Iterator i = trySuccs.iterator(); i.hasNext(); ) {
for (Jump jumps = tryFlow.getJumps((FlowBlock) i.next());
jumps != null; jumps = jumps.next) {
DescriptionBlock msg =
new DescriptionBlock
("ERROR: doesn't go through finally block!");
if (jumps.prev instanceof ReturnBlock) {
msg.replace(jumps.prev);
msg.appendBlock(jumps.prev);
} else {
jumps.prev.appendBlock(msg);
msg.moveJump(jumps);
}
}
}
if (succ != null) {
/* Handle the jumps in the tryFlow.
*/
Jump jumps = tryFlow.removeJumps(succ);
jumps = tryFlow.resolveSomeJumps(jumps, succ);
tryFlow.resolveRemaining(jumps);
}
TryBlock tryBlock = (TryBlock)tryFlow.block;
if (tryBlock.getSubBlocks()[0] instanceof TryBlock) {
/* remove the unnecessary tryBlock */
TryBlock innerTry = (TryBlock)tryBlock.getSubBlocks()[0];
innerTry.gen = tryBlock.gen;
innerTry.replace(tryBlock);
tryBlock = innerTry;
tryFlow.lastModified = innerTry;
}
FinallyBlock newBlock = new FinallyBlock();
tryBlock.addCatchBlock(newBlock);
newBlock.setCatchBlock(catchBlock);
mergeFinallyBlock(tryFlow, catchFlow, finallyBlock);
/* Following code will work be put inside the finallyBlock */
tryFlow.lastModified = finallyBlock;
return true;
}
/**
* Analyzes all exception handlers to try/catch/finally or
* synchronized blocks.
*/
public void analyze() {
void checkTryCatchOrder() {
/* Check if try/catch ranges are okay. The following succeeds
* for all classes generated by the sun java compiler, but hand
* optimized classes (or generated by other compilers) will fail.
*/
{
Handler last = null;
for (Iterator i = handlers.iterator(); i.hasNext(); ) {
Handler exc = (Handler) i.next();
int start = exc.start.getBlockNr();
int end = exc.end.getBlockNr();
int handler = exc.handler.getBlockNr();
if (start > end || handler <= end)
throw new InternalError
Handler last = null;
for (Iterator i = handlers.iterator(); i.hasNext(); ) {
Handler exc = (Handler) i.next();
int start = exc.start.getBlockNr();
int end = exc.end.getBlockNr();
int handler = exc.handler.getBlockNr();
if (start > end || handler <= end)
throw new InternalError
("ExceptionHandler order failed: not "
+ start + " < " + end + " <= " + handler);
if (last != null
&& (last.start.getBlockNr() != start
|| last.end.getBlockNr() != end)) {
/* The last handler does catch another range.
* Due to the order:
* start < last.start.getBlockNr()
* || end > last.end.getBlockNr()
*/
if (end >= last.start.getBlockNr()
&& end < last.end.getBlockNr())
throw new InternalError
("Exception handlers ranges are intersecting: ["
+ last.start.getBlockNr()+", "
+ last.end.getBlockNr()+"] and ["
+ start+", "+end+"].");
}
last = exc;
if (last != null
&& (last.start.getBlockNr() != start
|| last.end.getBlockNr() != end)) {
/* The last handler does catch another range.
* Due to the order:
* start < last.start.getBlockNr()
* || end > last.end.getBlockNr()
*/
if (end >= last.start.getBlockNr()
&& end < last.end.getBlockNr())
throw new InternalError
("Exception handlers ranges are intersecting: ["
+ last.start.getBlockNr()+", "
+ last.end.getBlockNr()+"] and ["
+ start+", "+end+"].");
}
last = exc;
}
}
{
Iterator i = handlers.iterator();
Handler exc = null;
Handler next = i.hasNext() ? (Handler) i.next() : null;
while(next != null) {
Handler last = exc;
exc = next;
int startNr = exc.start.getBlockNr();
int endNr = exc.end.getBlockNr();
next = i.hasNext() ? (Handler) i.next() : null;
int endHandler = Integer.MAX_VALUE;
/* If the next exception handler catches a bigger range
* it must surround the handler completely.
/**
* Analyzes all exception handlers to try/catch/finally or
* synchronized blocks.
*/
public void analyze() {
checkTryCatchOrder();
Iterator i = handlers.iterator();
Handler exc = null;
Handler next = i.hasNext() ? (Handler) i.next() : null;
while(next != null) {
Handler last = exc;
exc = next;
next = i.hasNext() ? (Handler) i.next() : null;
int startNr = exc.start.getBlockNr();
int endNr = exc.end.getBlockNr();
int endHandler = Integer.MAX_VALUE;
/* If the next exception handler catches a bigger range
* it must surround the handler completely.
*/
if (next != null
&& next.end.getBlockNr() > endNr)
endHandler = next.end.getBlockNr() + 1;
FlowBlock tryFlow = exc.start;
tryFlow.checkConsistent();
if (last == null || exc.type == null
|| last.start.getBlockNr() != startNr
|| last.end.getBlockNr() != endNr) {
/* The last handler does catch another range.
* Create a new try block.
*/
if (next != null
&& next.end.getBlockNr() > endNr)
endHandler = next.end.getBlockNr() + 1;
FlowBlock tryFlow = exc.start;
tryFlow.checkConsistent();
if (last == null || exc.type == null
|| last.start.getBlockNr() != startNr
|| last.end.getBlockNr() != endNr) {
/* The last handler does catch another range.
* Create a new try block.
*/
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeTry(" + startNr + ", " + endNr+")");
while(true) {
while (tryFlow.analyze(startNr,
endNr+1));
int nextNr = tryFlow.getNextBlockNr();
if (nextNr > endNr)
break;
tryFlow = flowBlocks[nextNr];
}
if (tryFlow.getBlockNr() != startNr)
GlobalOptions.err.println
("Warning: Can't completely analyze try.");
TryBlock tryBlock = new TryBlock(tryFlow);
} else if (!(tryFlow.block instanceof TryBlock))
throw new InternalError("no TryBlock");
FlowBlock catchFlow = exc.handler;
boolean isMultiUsed = catchFlow.predecessors.size() != 0;
if (!isMultiUsed && next != null) {
for (Iterator j = handlers.tailSet(next).iterator();
j.hasNext();) {
Handler h = (Handler) j.next();
if (h.handler == catchFlow) {
isMultiUsed = true;
break;
}
}
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeTry(" + startNr + ", " + endNr+")");
while(true) {
while (tryFlow.analyze(startNr, endNr+1));
int nextNr = tryFlow.getNextBlockNr();
if (nextNr > endNr)
break;
tryFlow = flowBlocks[nextNr];
}
if (isMultiUsed) {
/* If this exception is used in other exception handlers,
* create a new flow block, that jumps to the handler.
* This will be our new exception handler.
*/
FlowBlock newFlow = new FlowBlock
(catchFlow.method, catchFlow.getBlockNr(),
catchFlow.prevByCodeOrder);
newFlow.setSuccessors(new FlowBlock[] { catchFlow });
newFlow.nextByCodeOrder = catchFlow;
catchFlow.prevByCodeOrder = newFlow;
catchFlow = newFlow;
} else {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeCatch("
+ catchFlow.getBlockNr() + ", " + endHandler + ")");
while (catchFlow.analyze(catchFlow.getBlockNr(),
endHandler));
if (tryFlow.getBlockNr() != startNr) {
GlobalOptions.err.println
("Warning: Can't completely analyze try.");
}
/* Merge the try-block with the catch-block now */
tryFlow.updateInOutCatch(catchFlow);
tryFlow.mergeSuccessors(catchFlow);
tryFlow.mergeBlockNr(catchFlow);
if (exc.type != null)
analyzeCatchBlock(exc.type, tryFlow, catchFlow.block);
else if (!analyzeSynchronized(tryFlow, catchFlow.block,
endHandler)
&& ! analyzeFinally(tryFlow, catchFlow.block,
endHandler)
&& ! analyzeSpecialFinally(tryFlow, catchFlow.block,
endHandler))
analyzeCatchBlock(Type.tObject, tryFlow, catchFlow.block);
tryFlow.checkConsistent();
TryBlock tryBlock = new TryBlock(tryFlow);
} else if (!(tryFlow.block instanceof TryBlock))
throw new InternalError("no TryBlock");
FlowBlock catchFlow = exc.handler;
boolean isMultiUsed = catchFlow.predecessors.size() != 0;
if (!isMultiUsed && next != null) {
for (Iterator j = handlers.tailSet(next).iterator();
j.hasNext();) {
Handler h = (Handler) j.next();
if (h.handler == catchFlow) {
isMultiUsed = true;
break;
}
}
}
if (isMultiUsed) {
/* If this exception is used in other exception handlers,
* create a new flow block, that jumps to the handler.
* This will be our new exception handler.
*/
FlowBlock newFlow = new FlowBlock
(catchFlow.method, catchFlow.getBlockNr(),
catchFlow.prevByCodeOrder);
newFlow.setSuccessors(new FlowBlock[] { catchFlow });
newFlow.nextByCodeOrder = catchFlow;
catchFlow.prevByCodeOrder = newFlow;
catchFlow = newFlow;
} else {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeTryCatch(" + tryFlow.getBlockNr() + ", "
+ tryFlow.getNextBlockNr() + ") done.");
("analyzeCatch("
+ catchFlow.getBlockNr() + ", " + endHandler + ")");
while (catchFlow.analyze(catchFlow.getBlockNr(),
endHandler));
}
if (exc.type != null)
analyzeCatchBlock(exc.type, tryFlow, catchFlow);
else if (! analyzeSynchronized(tryFlow, catchFlow, endHandler)
&& ! analyzeFinally(tryFlow, catchFlow, endHandler)
&& ! analyzeSpecialFinally(tryFlow, catchFlow,
endHandler))
/* As last resort make a catch(Object) block. This doesn't
* compile, but at least it gives a hint what the code
* does.
*/
analyzeCatchBlock(Type.tObject, tryFlow, catchFlow);
tryFlow.checkConsistent();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_ANALYZE) != 0)
GlobalOptions.err.println
("analyzeTryCatch(" + tryFlow.getBlockNr() + ", "
+ tryFlow.getNextBlockNr() + ") done.");
}
}
}

@ -26,17 +26,15 @@ import net.sf.jode.expr.LocalLoadOperator;
/**
* A TryBlock is created for each exception in the
* ExceptionHandlers-Attribute. <p>
* ExceptionHandlers attribute. <br>
*
* For each catch block (there may be more than one catch block
* appending a single try block) and for each finally and each
* synchronized block such a TryBlock is created. The
* finally/synchronized-blocks have a null exception type so that they
* are easily distinguishable from the catch blocks. <p>
* are easily distinguishable from the catch blocks. <br>
*
* A TryBlock is an intermediate representation that gets
* converted later to a CatchBlock, a FinallyBlock or a
* SynchronizedBlock (after the body is parsed).
* A TryBlock may be converted later into a SynchronizedBlock.
*
* @date 1998/09/16
* @author Jochen Hoenicke

@ -596,7 +596,6 @@ public class CodeVerifier implements Opcodes {
private VerifyInfo initInfo() throws VerifyException {
VerifyInfo info = new VerifyInfo();
int pos = 1;
int slot = 0;
if (!mi.isStatic()) {
if (slot >= bb.getMaxLocals())
@ -606,14 +605,13 @@ public class CodeVerifier implements Opcodes {
else
info.locals[slot++] = tType("L", ci);
}
while (methodType.charAt(pos) != ')') {
int start = pos;
pos = TypeSignature.skipType(methodType, pos);
String paramType = methodType.substring(start, pos);
String[] paramTypes = TypeSignature.getParameterTypes(methodType);
for (int i = 0; i < paramTypes.length; i++) {
if (slot >= bb.getMaxLocals())
throw new VerifyException("Too few local slots");
info.locals[slot++] = tType(paramType);
if (TypeSignature.getTypeSize(paramType) == 2) {
info.locals[slot++] = tType(paramTypes[i]);
if (TypeSignature.getTypeSize(paramTypes[i]) == 2) {
if (slot >= bb.getMaxLocals())
throw new VerifyException("Too few local slots");
info.locals[slot++] = tSecondPart;

@ -98,16 +98,6 @@ public class SyntheticAnalyzer implements Opcodes {
opc_astore, opc_new, opc_dup, opc_aload,
opc_invokevirtual, opc_invokespecial, opc_athrow
};
private static final Reference[] getClassRefs = {
null, Reference.getReference("Ljava/lang/Class;", "forName",
"(Ljava/lang/String;)Ljava/lang/Class;"),
null, null, null, null, null,
Reference.getReference("Ljava/lang/Throwable;", "getMessage",
"()Ljava/lang/String;"),
Reference.getReference("Ljava/lang/NoClassDefFoundError;", "<init>",
"(Ljava/lang/String;)V"), null
};
boolean checkGetClass() {
if (!method.isStatic()
@ -133,9 +123,12 @@ public class SyntheticAnalyzer implements Opcodes {
Instruction instr = startBlock.getInstructions()[i];
if (instr.getOpcode() != getClassOpcodes[i])
return false;
if (getClassRefs[i] != null
&& !getClassRefs[i].equals(instr.getReference()))
return false;
if (i == 1) {
Reference ref = instr.getReference();
if (!ref.getClazz().equals("Ljava/lang/Class;")
|| !ref.getName().equals("forName"))
return false;
}
if (i == 0 && instr.getLocalSlot() != 0)
return false;
}
@ -148,9 +141,6 @@ public class SyntheticAnalyzer implements Opcodes {
Instruction instr = catchBlock.getInstructions()[i];
if (instr.getOpcode() != getClassOpcodes[3+i])
return false;
if (getClassRefs[3+i] != null
&& !getClassRefs[3+i].equals(instr.getReference()))
return false;
if (i == 0)
excSlot = instr.getLocalSlot();
if (i == 1 && !instr.getClazzType().equals
@ -158,6 +148,12 @@ public class SyntheticAnalyzer implements Opcodes {
return false;
if (i == 3 && instr.getLocalSlot() != excSlot)
return false;
if (i == 4
&& !instr.getReference().getName().equals("getMessage"))
return false;
if (i == 5
&& !instr.getReference().getName().equals("<init>"))
return false;
}
this.kind = GETCLASS;
return true;

Loading…
Cancel
Save