diff --git a/jode/jode/expr/CheckNullOperator.java b/jode/jode/expr/CheckNullOperator.java new file mode 100644 index 0000000..be2f35b --- /dev/null +++ b/jode/jode/expr/CheckNullOperator.java @@ -0,0 +1,65 @@ +/* + * CheckNullOperator (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ + +package jode.decompiler; +import jode.Type; + +/** + * This is a pseudo operator, which represents the check against null + * that jikes and javac generates for inner classes: + * + *
+ *   outer.new Inner()
+ * 
+ * is translated by javac to + *
+ *   new Outer$Inner(outer ((void) DUP.getClass()));
+ * 
+ * and by jikes to + *
+ *   new Outer$Inner(outer (DUP == null ? throw null));
+ * 
+ */ + +public class CheckNullOperator extends SimpleOperator { + + public CheckNullOperator(Type type) { + super(type, 0, 1); + operandTypes[0] = type; + } + + public int getPriority() { + return 200; + } + + public int getOperandPriority(int i) { + return 0; + } + + public String toString(String[] operands) { + /* There is no way to produce exactly the same code. + * This is a good approximation. + * op.getClass will throw a null pointer exception if operands[0] + * is null, otherwise return something not equal to null. + * The bad thing is that this isn't atomar. + */ + return "/*CHECK NULL*/ " + + operands[0] + ".getClass() != null ? " + operands[0] + " : null"; + } +} diff --git a/jode/jode/flow/CreateCheckNull.java b/jode/jode/flow/CreateCheckNull.java new file mode 100644 index 0000000..7d04bd1 --- /dev/null +++ b/jode/jode/flow/CreateCheckNull.java @@ -0,0 +1,105 @@ +/* + * CreateCheckNull (c) 1998 Jochen Hoenicke + * + * You may distribute under the terms of the GNU General Public License. + * + * IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE + * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" + * BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * $Id$ + */ + +package jode.flow; +import jode.decompiler.*; +import jode.Type; + +public class CreateCheckNull { + + /* Situation: + * + * javac: + * DUP + * stack_0.getClass(); + * + * jikes: + * DUP + * if (!stack_0 != null) + * throw null; + */ + + public static boolean transformJavac(InstructionContainer ic, + StructuredBlock last) { + if (!(last.outer instanceof SequentialBlock) + || !(ic.getInstruction() instanceof ComplexExpression) + || !(last.outer.getSubBlocks()[0] instanceof SpecialBlock)) + return false; + + SpecialBlock dup = (SpecialBlock) last.outer.getSubBlocks()[0]; + if (dup.type != SpecialBlock.DUP + || dup.count != 1 || dup.depth != 0) + return false; + + ComplexExpression ce = (ComplexExpression) ic.getInstruction(); + + if (!(ce.getOperator() instanceof PopOperator) + || !(ce.getSubExpressions()[0] instanceof InvokeOperator)) + return false; + + InvokeOperator getClassCall + = (InvokeOperator) ce.getSubExpressions()[0]; + if (!getClassCall.getMethodName().equals("getClass") + || !(getClassCall.getMethodType().toString() + .equals("()Ljava/lang/Class;"))) + return false; + + ic.setInstruction(new CheckNullOperator(Type.tUObject)); + last.replace(last.outer); + return true; + } + + public static boolean transformJikes(IfThenElseBlock ifBlock, + StructuredBlock last) { + if (!(last.outer instanceof SequentialBlock) + || !(last.outer.getSubBlocks()[0] instanceof SpecialBlock) + || ifBlock.elseBlock != null + || !(ifBlock.thenBlock instanceof ThrowBlock)) + return false; + System.err.println("last.outer: "+last.outer); + + SpecialBlock dup = (SpecialBlock) last.outer.getSubBlocks()[0]; + if (dup.type != SpecialBlock.DUP + || dup.count != 1 || dup.depth != 0) + return false; + + System.err.println("tick1"); + /* negate the instruction back to its original state */ + Expression expr = ifBlock.cond.negate(); + System.err.println(expr); + if (!(expr instanceof CompareUnaryOperator) + || expr.getOperator().getOperatorIndex() != Operator.NOTEQUALS_OP + || !(expr.getOperator().getOperandType(0).isOfType(Type.tUObject))) + return false; + + System.err.println("tick2"); + InstructionContainer ic = + new InstructionBlock(new CheckNullOperator(Type.tUObject)); + ifBlock.flowBlock.removeSuccessor(ifBlock.thenBlock.jump); + ic.moveJump(ifBlock.jump); + if (last == ifBlock) { + ic.replace(last.outer); + last = ic; + } else { + ic.replace(ifBlock); + last.replace(last.outer); + } + return true; + } +} diff --git a/jode/test/ClassOpTest.java b/jode/test/ClassOpTest.java new file mode 100644 index 0000000..cb85f2e --- /dev/null +++ b/jode/test/ClassOpTest.java @@ -0,0 +1,14 @@ +package jode.test; + +public class ClassOpTest { + static void test1() { + Class c1 = ClassOpTest.class; + Class c2 = Object.class; + Class c3 = ClassOpTest.class; + } + + void test2() { + Class c2 = Object.class; + Class c3 = ClassOpTest.class; + } +}